Overview
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Sun Oct 8 16:26:36 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.81
6
+
7
+-------------------------------------------------------------------
8
Fri Sep 22 17:21:32 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.80
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.80
6
+Version: 0.3.81
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.80.tar.gz/.gitlab-ci.yml -> pipewire-0.3.81.tar.gz/.gitlab-ci.yml
Changed
18
1
2
extends:
3
- .build_on_fedora
4
stage: analysis
5
+ variables:
6
+ MESON_OPTIONS: >-
7
+ -Dpipewire-v4l2=enabled
8
+ -Dpipewire-jack=enabled
9
script:
10
- - shellcheck $(git grep -l "#\!/.*bin/.*sh")
11
+ - echo "Configuring with meson options $MESON_OPTIONS"
12
+ - meson setup "$BUILD_DIR" --prefix="$PREFIX" $MESON_OPTIONS
13
+ - shellcheck $(git ls-files '*.sh')
14
+ - shellcheck $(grep -rl "#\!/.*bin/.*sh" "$BUILD_DIR")
15
16
spellcheck:
17
extends:
18
pipewire-0.3.80.tar.gz/NEWS -> pipewire-0.3.81.tar.gz/NEWS
Changed
100
1
2
+# PipeWire 0.3.81 (2023-10-06)
3
+
4
+This is the first 1.0 release candidate that is API and ABI compatible
5
+with previous 0.3.x releases.
6
+
7
+## Highlights
8
+ - jackdbus support is now enabled by default.
9
+ - IRQ based scheduling in ALSA was improved and enabled by default for
10
+ Pro-Audio profile. It will also link the pcms together to get lower
11
+ latency. This now matches what JACK does and gives equal latency to
12
+ PipeWire for Pro-Audio profiles.
13
+ - Support both old and new versions of webrtc-audio-processing to make
14
+ the transition easier.
15
+ - Forced quantum changes by nodes or metadata will now also force a
16
+ suspend and resume of the graph, like the rate changes to make sure all
17
+ nodes adapt to the new quantum. This is important for Pro-Audio nodes
18
+ that need to reconfigure the hardware to a new period in IRQ based
19
+ scheduling.
20
+ - Fix a regression in regex parsing.
21
+ - Many bugfixes and improvements.
22
+
23
+
24
+## PipeWire
25
+ - jackdbus is by default enabled now. The idea is that when jackdbus is
26
+ installed, the real libjack.so is in the path and we can become a
27
+ real JACK client.
28
+ - Forces quantum changes by nodes or metadata will now also force a
29
+ suspend and resume in the graph, like the rate changes to make sure all
30
+ nodes adapt to the new quantum. This is important for Pro-Audio nodes
31
+ that need to reconfigure the hardware to a new period.
32
+ - The stream now has an EARLY_PROCESS option that can be used to implement
33
+ custum buffer fill levels. (#3480)
34
+ - Fix a regression in regex parsing. (#3528)
35
+ - Fix a bug in position reporting in the driver node. (#3189) (#3544)
36
+ - Destroying a link will now recalculate the graph correctly.
37
+ - Fix the rate comparison for finding the best rate in the graph.
38
+ - Use malloc_trim() when available to release memory. (#1840)
39
+
40
+## Tools
41
+ - pw-cat now supports DFF DSD files.
42
+ - pw-cli avoid some NULL derefs in some cases.
43
+
44
+## Modules
45
+ - The RAOP sink has seen some cleanups and improvements. It will now ask
46
+ for feedback every 2 seconds to keep some devices alive.
47
+ - A bug in filter-chain was fixed where it would fail to apply the gain
48
+ when mixing just one source.
49
+ - The filter-chain can now pass the stream volume to a control in the
50
+ filter-chain graph. (#3434)
51
+ - Improve volume handling in RAOP sink.
52
+
53
+## Pulse-server
54
+ - Some cleanup in the pending_stream handling.
55
+ - Fix a regression in the event emission code where it failed to emit
56
+ a changed event when a node was linked. (#3522)
57
+ - Lower the realtime priority of pulseaudio clients.
58
+ - Set pulse.module.id on the echo-cancel streams. (#3541)
59
+
60
+## SPA
61
+ - Support both old and new versions of webrtc-audio-processing to make
62
+ the transition easier.
63
+ - The ALSA driver now does the sync of all followers directly from the
64
+ wakeup event. This results in more stable rate matching.
65
+ - IRQ based scheduling in ALSA was improved and enabled by default for
66
+ Pro-Audio profile. It will also link the pcms together to get lower
67
+ latency. This now matches what JACK does and gives equal latency to
68
+ PipeWire for Pro-Audio profiles.
69
+ - GNU/Hurd support was added.
70
+ - Some improvements to passthrough handling.
71
+
72
+## Bluetooth
73
+ - Improvements to the codec handling when PipeWire is used as Audio
74
+ Gateway.
75
+ - Adapt to new Bluez API for BAP devices.
76
+
77
+## JACK
78
+ - When the jack library is set in the default library path, avoid using
79
+ LD_LIBRARY_PATH because this can cause confusion.
80
+ - Handle clearing the latency on a port.
81
+ - jack_property now always manages to actually change the metadata because
82
+ it waits for a roundtrip before exiting.
83
+
84
+Older versions:
85
+
86
+
87
# PipeWire 0.3.80 (2023-09-14)
88
89
This is a bugfix release that is API and ABI compatible with previous
90
91
- The mixer io areas are updated and handled safely now to avoid
92
crashes. (#3506)
93
94
-Older versions:
95
-
96
-
97
# PipeWire 0.3.79 (2023-08-29)
98
99
This is a quick bugfix release that is API and ABI compatible with previous
100
pipewire-0.3.80.tar.gz/doc/input-filter-h.sh -> pipewire-0.3.81.tar.gz/doc/input-filter-h.sh
Changed
9
1
2
# Add \ingroup commands for the file, for each \addgroup in it
3
BASEFILE=$(echo "$FILENAME" | sed -e 's@.*src/pipewire/@pipewire/@; s@.*spa/include/spa/@spa/@; s@.*src/test/@test/@;')
4
5
+# shellcheck disable=SC2028 # \file is not an escape sequence
6
echo "/** \file"
7
echo "\`$BASEFILE\`"
8
sed -n -e '/.*\\addtogroup a-zA-Z0-9_.*/ { s/.*addtogroup /\\ingroup /; p; }' < "$FILENAME" | sort | uniq
9
pipewire-0.3.80.tar.gz/meson.build -> pipewire-0.3.81.tar.gz/meson.build
Changed
57
1
2
project('pipewire', 'c' ,
3
- version : '0.3.80',
4
+ version : '0.3.81',
5
license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
meson_version : '>= 0.61.1',
7
default_options : 'warning_level=3',
8
9
spaversion = '0.2'
10
apiversion = '0.3'
11
soversion = 0
12
-libversion = '@0@.@1@.0'.format(soversion, pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int())
13
+libversion_minor = pipewire_version_major.to_int() * 1000 + pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int()
14
+libversion = '@0@.@1@.0'.format(soversion, libversion_minor)
15
16
# LADI/jack
17
# 3, for PipeWire being the third JACK implementation, after JACK1 and jackdmp/JACK2)
18
jack_version_major = 3
19
-jack_version_minor = pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int()
20
+jack_version_minor = libversion_minor
21
# libjackserver version has 0 for major (for compatibility with other implementations),
22
-# 3 for minor, and "100*pipewire_version_minor + pipewire_version_micro"
23
-# as micro version (the minor libpipewire soversion number)
24
+# 3 for minor, and "1000*major + 100*minor + micro" as micro version (the minor libpipewire soversion number)
25
libjackversion = '@0@.@1@.@2@'.format(soversion, jack_version_major, jack_version_minor)
26
27
pipewire_name = 'pipewire-@0@'.format(apiversion)
28
29
30
webrtc_dep = dependency('webrtc-audio-processing-1',
31
version : '>= 1.2' ,
32
- required : get_option('echo-cancel-webrtc'))
33
-summary({'WebRTC Echo Canceling': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies')
34
-cdata.set('HAVE_WEBRTC', webrtc_dep.found())
35
+ required : false)
36
+cdata.set('HAVE_WEBRTC1', webrtc_dep.found())
37
+if webrtc_dep.found()
38
+ summary({'WebRTC Echo Canceling >= 1.2': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies')
39
+else
40
+ webrtc_dep = dependency('webrtc-audio-processing',
41
+ version : '>= 0.2', '< 1.0',
42
+ required : get_option('echo-cancel-webrtc'))
43
+ cdata.set('HAVE_WEBRTC', webrtc_dep.found())
44
+ summary({'WebRTC Echo Canceling < 1.0': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies')
45
+endif
46
47
# On FreeBSD and MidnightBSD, epoll-shim library is required for eventfd() and timerfd()
48
epoll_shim_dep = (host_machine.system() == 'freebsd' or host_machine.system() == 'midnightbsd'
49
50
'reallocarray', '#include <stdlib.h>', '-D_GNU_SOURCE', ,
51
'sigabbrev_np', '#include <string.h>', '-D_GNU_SOURCE', ,
52
'XSetIOErrorExitHandler', '#include <X11/Xlib.h>', , x11_dep,
53
+ 'malloc_trim', '#include <malloc.h>', , ,
54
55
56
foreach f : check_functions
57
pipewire-0.3.80.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.81.tar.gz/pipewire-jack/src/meson.build
Changed
21
1
2
if libjack_path == ''
3
libjack_path = modules_install_dir / 'jack'
4
libjack_path_dlopen = modules_install_dir_dlopen / 'jack'
5
+ libjack_path_enable = ''
6
+elif libjack_path == get_option('libdir') or libjack_path == pipewire_libdir
7
+ libjack_path = pipewire_libdir
8
+ libjack_path_dlopen = libjack_path
9
+ libjack_path_enable = '#'
10
else
11
libjack_path_dlopen = libjack_path
12
+ libjack_path_enable = ''
13
endif
14
15
tools_config = configuration_data()
16
tools_config.set('LIBJACK_PATH', libjack_path_dlopen)
17
+tools_config.set('LIBJACK_PATH_ENABLE', libjack_path_enable)
18
19
configure_file(input : 'pw-jack.in',
20
output : 'pw-jack',
21
pipewire-0.3.80.tar.gz/pipewire-jack/src/metadata.c -> pipewire-0.3.81.tar.gz/pipewire-jack/src/metadata.c
Changed
47
1
2
pw_log_info("set id:%u (%"PRIu64") '%s' to '%s@%s'", o->id, subject, key, value, type);
3
if (update_property(c, subject, key, type, value))
4
pw_metadata_set_property(c->metadata->proxy, o->id, key, type, value);
5
- res = 0;
6
+ res = do_sync(c);
7
done:
8
pw_thread_loop_unlock(c->context.loop);
9
10
11
pw_log_info("remove id:%u (%"PRIu64") '%s'", id, subject, key);
12
pw_metadata_set_property(c->metadata->proxy,
13
id, key, NULL, NULL);
14
- res = 0;
15
+ res = do_sync(c);
16
done:
17
pw_thread_loop_unlock(c->context.loop);
18
19
20
pw_log_info("remove id:%u (%"PRIu64")", id, subject);
21
pw_metadata_set_property(c->metadata->proxy,
22
id, NULL, NULL, NULL);
23
- res = 0;
24
+ res = do_sync(c);
25
done:
26
pw_thread_loop_unlock(c->context.loop);
27
28
29
SPA_EXPORT
30
int jack_remove_all_properties (jack_client_t* client)
31
{
32
+ int res;
33
struct client *c = (struct client *) client;
34
35
spa_return_val_if_fail(c != NULL, -EINVAL);
36
37
pw_thread_loop_lock(c->context.loop);
38
pw_metadata_clear(c->metadata->proxy);
39
+ res = do_sync(c);
40
pw_thread_loop_unlock(c->context.loop);
41
42
- return 0;
43
+ return res;
44
}
45
46
SPA_EXPORT
47
pipewire-0.3.80.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.81.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
24
1
2
int res;
3
4
if (param == NULL)
5
- return 0;
6
- if ((res = spa_latency_parse(param, &info)) < 0)
7
+ info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(p->direction));
8
+ else if ((res = spa_latency_parse(param, &info)) < 0)
9
return res;
10
+ if (info.direction == p->direction)
11
+ return 0;
12
13
current = &p->object->port.latencyinfo.direction;
14
if (spa_latency_info_compare(current, &info) == 0)
15
16
info.min_rate, info.max_rate,
17
info.min_ns, info.max_ns);
18
19
- if (info.direction == p->direction)
20
- return 0;
21
22
if (info.direction == SPA_DIRECTION_INPUT)
23
mode = JackPlaybackLatency;
24
pipewire-0.3.80.tar.gz/pipewire-jack/src/pw-jack.in -> pipewire-0.3.81.tar.gz/pipewire-jack/src/pw-jack.in
Changed
13
1
2
fi
3
export PIPEWIRE_QUANTUM
4
fi
5
-LD_LIBRARY_PATH='@LIBJACK_PATH@'"${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"}"
6
-export LD_LIBRARY_PATH
7
+
8
+# shellcheck disable=SC2016 # ${LIB} is interpreted by ld.so, not the shell
9
+@LIBJACK_PATH_ENABLE@LD_LIBRARY_PATH='@LIBJACK_PATH@'"${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"}"
10
+@LIBJACK_PATH_ENABLE@export LD_LIBRARY_PATH
11
12
exec "$@"
13
pipewire-0.3.80.tar.gz/pipewire-v4l2/src/pw-v4l2.in -> pipewire-0.3.81.tar.gz/pipewire-v4l2/src/pw-v4l2.in
Changed
9
1
2
if "$PW_UNINSTALLED" = 1 ; then
3
PW_V4L2_LD_PRELOAD="$PW_BUILDDIR"'/pipewire-v4l2/src/libpw-v4l2.so'
4
else
5
+ # shellcheck disable=SC2016 # ${LIB} is interpreted by ld.so, not the shell
6
PW_V4L2_LD_PRELOAD='@LIBV4L2_PATH@/libpw-v4l2.so'
7
fi
8
9
pipewire-0.3.80.tar.gz/spa/examples/adapter-control.c -> pipewire-0.3.81.tar.gz/spa/examples/adapter-control.c
Changed
13
1
2
printf("got error %d\n", res);
3
}
4
5
-static char *getscale(uint32_t scale)
6
+static const char *getscale(uint32_t scale)
7
{
8
- char *scale_s = NULL;
9
+ const char *scale_s = NULL;
10
11
if (scale == SPA_AUDIO_VOLUME_RAMP_LINEAR)
12
scale_s = LINEAR;
13
pipewire-0.3.80.tar.gz/spa/include/spa/debug/log.h -> pipewire-0.3.81.tar.gz/spa/include/spa/debug/log.h
Changed
12
1
2
#include <spa/utils/defs.h>
3
#include <spa/support/log.h>
4
#include <spa/debug/context.h>
5
+#include <spa/debug/dict.h>
6
+#include <spa/debug/format.h>
7
+#include <spa/debug/mem.h>
8
+#include <spa/debug/pod.h>
9
10
/**
11
* \addtogroup spa_debug
12
pipewire-0.3.80.tar.gz/spa/include/spa/utils/cleanup.h -> pipewire-0.3.81.tar.gz/spa/include/spa/utils/cleanup.h
Changed
47
1
2
3
#define spa_exchange(var, new_value) \
4
__extension__ ({ \
5
- __typeof__(var) _old_value = (var); \
6
- (var) = (new_value); \
7
+ __typeof__(var) *_ptr = &(var); \
8
+ __typeof__(var) _old_value = *_ptr; \
9
+ *_ptr = (new_value); \
10
_old_value; \
11
})
12
13
-#if __GNUC__ > 10 || defined(__clang__)
14
+#if __GNUC__ >= 10 || defined(__clang__)
15
#define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL))
16
#else
17
-#define spa_steal_ptr(ptr) ((__typeof__(ptr)) spa_exchange((ptr), NULL))
18
+#define spa_steal_ptr(ptr) spa_exchange((ptr), NULL)
19
#endif
20
21
#define spa_steal_fd(fd) spa_exchange((fd), -1)
22
23
24
#include <stdlib.h>
25
26
-
27
-#if __GNUC__ > 10 || defined(__clang__)
28
-#define spa_clear_ptr(ptr, destructor) \
29
-__extension__ ({ \
30
- __typeof__(*(ptr)) *_old_value = spa_steal_ptr(ptr); \
31
- if (_old_value) \
32
- destructor(_old_value); \
33
- (void) 0; \
34
-})
35
-#else
36
#define spa_clear_ptr(ptr, destructor) \
37
__extension__ ({ \
38
__typeof__(ptr) _old_value = spa_steal_ptr(ptr); \
39
40
destructor(_old_value); \
41
(void) 0; \
42
})
43
-#endif
44
45
static inline void _spa_autofree_cleanup_func(void *p)
46
{
47
pipewire-0.3.80.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.81.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
196
1
2
/* SPDX-FileCopyrightText: Copyright © 2021 Arun Raghavan <arun@asymptotic.io> */
3
/* SPDX-License-Identifier: MIT */
4
5
+#include "config.h"
6
+
7
#include <memory>
8
#include <utility>
9
10
11
#include <spa/utils/json.h>
12
#include <spa/support/plugin.h>
13
14
+#ifdef HAVE_WEBRTC
15
+#include <webrtc/modules/audio_processing/include/audio_processing.h>
16
+#include <webrtc/modules/interface/module_common_types.h>
17
+#include <webrtc/system_wrappers/include/trace.h>
18
+#else
19
#include <modules/audio_processing/include/audio_processing.h>
20
+#endif
21
22
struct impl_data {
23
struct spa_handle handle;
24
25
return default_value;
26
}
27
28
+#ifdef HAVE_WEBRTC
29
+/* f0 f1 f2 */
30
+static int parse_point(struct spa_json *it, float (&f)3)
31
+{
32
+ struct spa_json arr;
33
+ int i, res;
34
+
35
+ if (spa_json_enter_array(it, &arr) <= 0)
36
+ return -EINVAL;
37
+
38
+ for (i = 0; i < 3; i++) {
39
+ if ((res = spa_json_get_float(&arr, &fi)) <= 0)
40
+ return -EINVAL;
41
+ }
42
+ return 0;
43
+}
44
+
45
+/* point1 point2 ... */
46
+static int parse_mic_geometry(struct impl_data *impl, const char *mic_geometry,
47
+ std::vector<webrtc::Point>& geometry)
48
+{
49
+ int res;
50
+ size_t i;
51
+ struct spa_json it2;
52
+
53
+ spa_json_init(&it0, mic_geometry, strlen(mic_geometry));
54
+ if (spa_json_enter_array(&it0, &it1) <= 0) {
55
+ spa_log_error(impl->log, "Error: webrtc.mic-geometry expects an array");
56
+ return -EINVAL;
57
+ }
58
+
59
+ for (i = 0; i < geometry.size(); i++) {
60
+ float f3;
61
+
62
+ if ((res = parse_point(&it1, f)) < 0) {
63
+ spa_log_error(impl->log, "Error: can't parse webrtc.mic-geometry points: %d", res);
64
+ return res;
65
+ }
66
+
67
+ spa_log_info(impl->log, "mic %zd position: (%g %g %g)", i, f0, f1, f2);
68
+ geometryi.c0 = f0;
69
+ geometryi.c1 = f1;
70
+ geometryi.c2 = f2;
71
+ }
72
+ return 0;
73
+}
74
+#endif
75
+
76
static int webrtc_init2(void *object, const struct spa_dict *args,
77
struct spa_audio_info_raw *rec_info, struct spa_audio_info_raw *out_info,
78
struct spa_audio_info_raw *play_info)
79
80
81
bool high_pass_filter = webrtc_get_spa_bool(args, "webrtc.high_pass_filter", true);
82
bool noise_suppression = webrtc_get_spa_bool(args, "webrtc.noise_suppression", true);
83
- bool transient_suppression = webrtc_get_spa_bool(args, "webrtc.transient_suppression", true);
84
bool voice_detection = webrtc_get_spa_bool(args, "webrtc.voice_detection", true);
85
-
86
+#ifdef HAVE_WEBRTC
87
+ bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true);
88
+ bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true);
89
+ // Disable experimental flags by default
90
+ bool experimental_agc = webrtc_get_spa_bool(args, "webrtc.experimental_agc", false);
91
+ bool experimental_ns = webrtc_get_spa_bool(args, "webrtc.experimental_ns", false);
92
+
93
+ bool beamforming = webrtc_get_spa_bool(args, "webrtc.beamforming", false);
94
+#else
95
+ bool transient_suppression = webrtc_get_spa_bool(args, "webrtc.transient_suppression", true);
96
+#endif
97
// Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech,
98
// result in very poor performance, disable by default
99
bool gain_control = webrtc_get_spa_bool(args, "webrtc.gain_control", false);
100
101
// This filter will modify playback buffer (when calling ProcessReverseStream), but now
102
// playback buffer modifications are discarded.
103
104
+#ifdef HAVE_WEBRTC
105
+ webrtc::Config config;
106
+ config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter));
107
+ config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic));
108
+ config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc));
109
+ config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns));
110
+
111
+ if (beamforming) {
112
+ std::vector<webrtc::Point> geometry(rec_info->channels);
113
+ const char *mic_geometry, *target_direction;
114
+
115
+ /* The beamformer gives a single mono channel */
116
+ out_info->channels = 1;
117
+ out_info->position0 = SPA_AUDIO_CHANNEL_MONO;
118
+
119
+ if ((mic_geometry = spa_dict_lookup(args, "webrtc.mic-geometry")) == NULL) {
120
+ spa_log_error(impl->log, "Error: webrtc.beamforming requires webrtc.mic-geometry");
121
+ return -EINVAL;
122
+ }
123
+
124
+ if ((res = parse_mic_geometry(impl, mic_geometry, geometry)) < 0)
125
+ return res;
126
+
127
+ if ((target_direction = spa_dict_lookup(args, "webrtc.target-direction")) != NULL) {
128
+ webrtc::SphericalPointf direction(0.0f, 0.0f, 0.0f);
129
+ struct spa_json it;
130
+ float f3;
131
+
132
+ spa_json_init(&it, target_direction, strlen(target_direction));
133
+ if (parse_point(&it, f) < 0) {
134
+ spa_log_error(impl->log, "Error: can't parse target-direction %s",
135
+ target_direction);
136
+ return -EINVAL;
137
+ }
138
+
139
+ direction.s0 = f0;
140
+ direction.s1 = f1;
141
+ direction.s2 = f2;
142
+
143
+ config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry, direction));
144
+ } else {
145
+ config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
146
+ }
147
+ }
148
+#else
149
webrtc::AudioProcessing::Config config;
150
config.echo_canceller.enabled = true;
151
// FIXME: Example code enables both gain controllers, but that seems sus
152
153
// FIXME: expose pre/postamp gain
154
config.transient_suppression.enabled = transient_suppression;
155
config.voice_detection.enabled = voice_detection;
156
+#endif
157
158
webrtc::ProcessingConfig pconfig = {{
159
webrtc::StreamConfig(rec_info->rate, rec_info->channels, false), /* input stream */
160
161
webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse output stream */
162
}};
163
164
+#ifdef HAVE_WEBRTC
165
+ auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config));
166
+#else
167
auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessingBuilder().Create());
168
169
apm->ApplyConfig(config);
170
+#endif
171
172
if ((res = apm->Initialize(pconfig)) != webrtc::AudioProcessing::kNoError) {
173
spa_log_error(impl->log, "Error initialising webrtc audio processing module: %d", res);
174
return -EINVAL;
175
}
176
177
+#ifdef HAVE_WEBRTC
178
+ apm->high_pass_filter()->Enable(high_pass_filter);
179
+ // Always disable drift compensation since PipeWire will already do
180
+ // drift compensation on all sinks and sources linked to this echo-canceler
181
+ apm->echo_cancellation()->enable_drift_compensation(false);
182
+ apm->echo_cancellation()->Enable(true);
183
+ // TODO: wire up supression levels to args
184
+ apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression);
185
+ apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh);
186
+ apm->noise_suppression()->Enable(noise_suppression);
187
+ apm->voice_detection()->Enable(voice_detection);
188
+ // TODO: wire up AGC parameters to args
189
+ apm->gain_control()->set_analog_level_limits(0, 255);
190
+ apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
191
+ apm->gain_control()->Enable(gain_control);
192
+#endif
193
impl->apm = std::move(apm);
194
impl->rec_info = *rec_info;
195
impl->out_info = *out_info;
196
pipewire-0.3.80.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.81.tar.gz/spa/plugins/alsa/acp/acp.c
Changed
19
1
2
pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm);
3
pa_proplist_setf(m->output_proplist, "clock.name", "api.alsa.%u", index);
4
pa_proplist_setf(m->output_proplist, "device.profile.pro", "true");
5
+ pa_proplist_setf(m->output_proplist, "node.group", "pro-audio-%u", index);
6
+ pa_proplist_setf(m->output_proplist, "node.link-group", "pro-audio-%u", index);
7
pa_alsa_close(&m->output_pcm);
8
m->supported = true;
9
pa_channel_map_init_auto(&m->channel_map, m->sample_spec.channels, PA_CHANNEL_MAP_AUX);
10
11
pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm);
12
pa_proplist_setf(m->input_proplist, "clock.name", "api.alsa.%u", index);
13
pa_proplist_setf(m->input_proplist, "device.profile.pro", "true");
14
+ pa_proplist_setf(m->input_proplist, "node.group", "pro-audio-%u", index);
15
+ pa_proplist_setf(m->input_proplist, "node.link-group", "pro-audio-%u", index);
16
pa_alsa_close(&m->input_pcm);
17
m->supported = true;
18
pa_channel_map_init_auto(&m->channel_map, m->sample_spec.channels, PA_CHANNEL_MAP_AUX);
19
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-compress-offload-sink.c -> pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-compress-offload-sink.c
Changed
16
1
2
3
nextptr = device + 3;
4
for (value_index = 0; ; ++value_index) {
5
- char *value_label;
6
+ const char *value_label;
7
8
switch (value_index) {
9
case 0: value_label = "card"; break;
10
case 1: value_label = "device"; break;
11
- default: assert(false);
12
+ default: spa_assert_not_reached();
13
}
14
15
errno = 0;
16
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
15
1
2
3
switch (id) {
4
case SPA_IO_Clock:
5
+ if (size > 0 && size < sizeof(struct spa_io_clock))
6
+ return -EINVAL;
7
this->clock = data;
8
break;
9
case SPA_IO_Position:
10
+ if (size > 0 && size < sizeof(struct spa_io_position))
11
+ return -EINVAL;
12
this->position = data;
13
break;
14
default:
15
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
10
1
2
this->clock = data;
3
break;
4
case SPA_IO_Position:
5
+ if (size > 0 && size < sizeof(struct spa_io_position))
6
+ return -EINVAL;
7
this->position = data;
8
break;
9
default:
10
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
1469
1
2
#include "alsa-pcm.h"
3
4
static struct spa_list cards = SPA_LIST_INIT(&cards);
5
+static struct spa_list states = SPA_LIST_INIT(&states);
6
7
static struct card *find_card(uint32_t index)
8
{
9
10
int err;
11
const char *str;
12
13
+ spa_list_init(&state->followers);
14
+ spa_list_init(&state->rt.followers);
15
+
16
snd_config_update_free_global();
17
18
if ((str = spa_dict_lookup(info, "device.profile.pro")) != NULL)
19
20
21
state->multi_rate = true;
22
state->htimestamp = false;
23
+ state->disable_tsched = state->is_pro;
24
for (i = 0; info && i < info->n_items; i++) {
25
const char *k = info->itemsi.key;
26
const char *s = info->itemsi.value;
27
28
}
29
CHECK(snd_output_stdio_attach(&state->output, state->log_file, 0), "attach failed");
30
31
+ spa_list_append(&states, &state->link);
32
+
33
state->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
34
state->rate_limit.burst = 1;
35
36
37
{
38
int err;
39
40
+ spa_list_remove(&state->link);
41
release_card(state->card);
42
43
state->card = NULL;
44
45
err = snd_ctl_open(&state->ctl, device_name, SND_CTL_NONBLOCK);
46
if (err < 0) {
47
spa_log_info(state->log, "%s could not find ctl device: %s",
48
- state->props.device, snd_strerror(err));
49
+ device_name, snd_strerror(err));
50
state->ctl = NULL;
51
goto error;
52
}
53
54
err = snd_ctl_elem_read(state->ctl, state->pitch_elem);
55
if (err < 0) {
56
spa_log_debug(state->log, "%s: did not find ctl %s: %s",
57
- state->props.device, elem_name, snd_strerror(err));
58
+ device_name, elem_name, snd_strerror(err));
59
60
snd_ctl_elem_value_free(state->pitch_elem);
61
state->pitch_elem = NULL;
62
63
CHECK(snd_ctl_elem_write(state->ctl, state->pitch_elem), "snd_ctl_elem_write");
64
state->last_rate = 1.0;
65
66
- spa_log_info(state->log, "%s: found ctl %s", state->props.device, elem_name);
67
+ spa_log_info(state->log, "%s: found ctl %s", device_name, elem_name);
68
err = 0;
69
error:
70
snd_lib_error_set_handler(NULL);
71
return err;
72
}
73
74
+static int do_link(struct state *driver, struct state *state)
75
+{
76
+ int res;
77
+ snd_pcm_status_t *status;
78
+
79
+ snd_pcm_status_alloca(&status);
80
+ snd_pcm_status(driver->hndl, status);
81
+ snd_pcm_status_dump(status, state->output);
82
+ snd_pcm_status(state->hndl, status);
83
+ snd_pcm_status_dump(status, state->output);
84
+ fflush(state->log_file);
85
+
86
+ res = snd_pcm_link(driver->hndl, state->hndl);
87
+ if (res >= 0 || res == -EALREADY)
88
+ state->linked = true;
89
+
90
+ spa_log_info(state->log, "%p: linked to driver %p: %u (%s)",
91
+ state, driver, state->linked, snd_strerror(res));
92
+ return 0;
93
+}
94
+
95
int spa_alsa_open(struct state *state, const char *params)
96
{
97
int err;
98
99
spa_scnprintf(device_name, sizeof(device_name), "%s%s%s",
100
state->card->ucm_prefix ? state->card->ucm_prefix : "",
101
props->device, params ? params : "");
102
+ spa_scnprintf(state->name, sizeof(state->name), "%s%s",
103
+ props->device, state->stream == SND_PCM_STREAM_CAPTURE ? "c" : "p");
104
105
spa_log_info(state->log, "%p: ALSA device open '%s' %s", state, device_name,
106
state->stream == SND_PCM_STREAM_CAPTURE ? "capture" : "playback");
107
108
* these are initialised in spa_alsa_start() */
109
}
110
111
- if (state->clock)
112
- spa_scnprintf(state->clock->name, sizeof(state->clock->name),
113
- "%s", state->clock_name);
114
state->opened = true;
115
state->sample_count = 0;
116
state->sample_time = 0;
117
118
return 0;
119
120
error_exit_close:
121
- spa_log_info(state->log, "%p: Device '%s' closing: %s", state, state->props.device,
122
+ spa_log_info(state->log, "%p: Device '%s' closing: %s", state, state->name,
123
spa_strerror(err));
124
snd_pcm_close(state->hndl);
125
return err;
126
}
127
128
+static void try_unlink(struct state *state)
129
+{
130
+ struct state *follower;
131
+
132
+ if (state->driver != NULL && state->linked) {
133
+ snd_pcm_unlink(state->hndl);
134
+ spa_log_info(state->log, "%p: unlinked from driver %p",
135
+ state, state->driver);
136
+ state->linked = false;
137
+ }
138
+ spa_list_for_each(follower, &state->followers, driver_link) {
139
+ if (follower->opened && follower->linked) {
140
+ snd_pcm_unlink(follower->hndl);
141
+ spa_log_info(state->log, "%p: follower unlinked from driver %p",
142
+ follower, state);
143
+ follower->linked = false;
144
+ }
145
+ }
146
+}
147
+
148
int spa_alsa_close(struct state *state)
149
{
150
int err = 0;
151
152
if (!state->opened)
153
return 0;
154
155
+ try_unlink(state);
156
+
157
spa_alsa_pause(state);
158
159
- spa_log_info(state->log, "%p: Device '%s' closing", state, state->props.device);
160
+ spa_log_info(state->log, "%p: Device '%s' closing", state, state->name);
161
if ((err = snd_pcm_close(state->hndl)) < 0)
162
- spa_log_warn(state->log, "%s: close failed: %s", state->props.device,
163
+ spa_log_warn(state->log, "%s: close failed: %s", state->name,
164
snd_strerror(err));
165
166
if (!state->disable_tsched)
167
168
169
state->have_format = false;
170
state->opened = false;
171
+ state->linked = false;
172
173
if (state->pitch_elem) {
174
snd_ctl_elem_value_free(state->pitch_elem);
175
176
CHECK(snd_pcm_hw_params_set_channels_near(hndl, params, &rchannels), "set_channels");
177
if (state->default_channels != rchannels) {
178
spa_log_warn(state->log, "%s: Channels doesn't match (requested %u, got %u)",
179
- state->props.device, state->default_channels, rchannels);
180
+ state->name, state->default_channels, rchannels);
181
}
182
}
183
if (state->default_rate != 0) {
184
185
CHECK(snd_pcm_hw_params_set_rate_near(hndl, params, &rrate, 0), "set_rate_near");
186
if (state->default_rate != rrate) {
187
spa_log_warn(state->log, "%s: Rate doesn't match (requested %u, got %u)",
188
- state->props.device, state->default_rate, rrate);
189
+ state->name, state->default_rate, rrate);
190
}
191
}
192
193
194
}
195
}
196
spa_log_warn(state->log, "%s: no format found (def:%d) formats:%s",
197
- state->props.device, state->default_format, buf);
198
+ state->name, state->default_format, buf);
199
200
for (i = 0, offs = 0; i <= SND_PCM_ACCESS_LAST; i++) {
201
if (snd_pcm_access_mask_test(amask, (snd_pcm_access_t)i)) {
202
203
offs += r;
204
}
205
}
206
- spa_log_warn(state->log, "%s: access:%s", state->props.device, buf);
207
+ spa_log_warn(state->log, "%s: access:%s", state->name, buf);
208
return -ENOTSUP;
209
}
210
211
212
213
if (rformat == SND_PCM_FORMAT_UNKNOWN) {
214
spa_log_warn(state->log, "%s: unknown format",
215
- state->props.device);
216
+ state->name);
217
return -EINVAL;
218
}
219
220
221
planar ? SND_PCM_ACCESS_RW_NONINTERLEAVED
222
: SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
223
spa_log_error(state->log, "%s: RW not possible: %s",
224
- state->props.device, snd_strerror(err));
225
+ state->name, snd_strerror(err));
226
return err;
227
}
228
}
229
230
CHECK(snd_pcm_hw_params_set_channels_near(hndl, params, &val), "set_channels");
231
if (rchannels != val) {
232
spa_log_warn(state->log, "%s: Channels doesn't match (requested %u, got %u)",
233
- state->props.device, rchannels, val);
234
+ state->name, rchannels, val);
235
if (!SPA_FLAG_IS_SET(flags, SPA_NODE_PARAM_FLAG_NEAREST))
236
return -EINVAL;
237
if (fmt->media_subtype != SPA_MEDIA_SUBTYPE_raw)
238
239
CHECK(snd_pcm_hw_params_set_rate_near(hndl, params, &val, 0), "set_rate_near");
240
if (rrate != val) {
241
spa_log_warn(state->log, "%s: Rate doesn't match (requested %iHz, got %iHz)",
242
- state->props.device, rrate, val);
243
+ state->name, rrate, val);
244
if (!SPA_FLAG_IS_SET(flags, SPA_NODE_PARAM_FLAG_NEAREST))
245
return -EINVAL;
246
if (fmt->media_subtype != SPA_MEDIA_SUBTYPE_raw)
247
248
}
249
if (rchannels == 0 || rrate == 0) {
250
spa_log_error(state->log, "%s: invalid channels:%d or rate:%d",
251
- state->props.device, rchannels, rrate);
252
+ state->name, rchannels, rrate);
253
return -EIO;
254
}
255
256
257
else
258
state->frame_size *= rchannels;
259
260
+ /* make sure we update threshold in check_position_config() because they depend
261
+ * on the samplerate. */
262
+ state->driver_duration = 0;
263
+ state->driver_rate.denom = 0;
264
+
265
state->have_format = true;
266
if (state->card->format_ref++ == 0)
267
state->card->rate = rrate;
268
269
CHECK(snd_pcm_hw_params_set_period_size_near(hndl, params, &period_size, &dir), "set_period_size_near");
270
271
if (period_size == 0) {
272
- spa_log_error(state->log, "%s: invalid period_size 0 (driver error?)", state->props.device);
273
+ spa_log_error(state->log, "%s: invalid period_size 0 (driver error?)", state->name);
274
return -EIO;
275
}
276
277
278
periods = state->buffer_frames / period_size;
279
}
280
if (state->buffer_frames == 0) {
281
- spa_log_error(state->log, "%s: invalid buffer_frames 0 (driver error?)", state->props.device);
282
+ spa_log_error(state->log, "%s: invalid buffer_frames 0 (driver error?)", state->name);
283
return -EIO;
284
}
285
286
287
state->latencystate->port_direction.min_rate =
288
state->latencystate->port_direction.max_rate = latency;
289
290
- spa_log_info(state->log, "%s (%s): format:%s access:%s-%s rate:%d channels:%d "
291
+ spa_log_info(state->log, "%s: format:%s access:%s-%s rate:%d channels:%d "
292
"buffer frames %lu, period frames %lu, periods %u, frame_size %zd "
293
"headroom %u start-delay:%u batch:%u tsched:%u",
294
- state->props.device,
295
- state->stream == SND_PCM_STREAM_CAPTURE ? "capture" : "playback",
296
- snd_pcm_format_name(state->format),
297
+ state->name, snd_pcm_format_name(state->format),
298
state->use_mmap ? "mmap" : "rw",
299
planar ? "planar" : "interleaved",
300
state->rate, state->channels, state->buffer_frames, state->period_frames,
301
302
CHECK(snd_ctl_elem_write(state->ctl, state->pitch_elem), "snd_ctl_elem_write");
303
304
spa_log_trace_fp(state->log, "%s %u set rate to %g",
305
- state->props.device, state->stream, state->rate_match->rate);
306
+ state->name, state->stream, state->rate_match->rate);
307
308
state->last_rate = state->rate_match->rate;
309
310
311
static int set_timeout(struct state *state, uint64_t time)
312
{
313
struct itimerspec ts;
314
-
315
- if (state->disable_tsched)
316
- return 0;
317
-
318
ts.it_value.tv_sec = time / SPA_NSEC_PER_SEC;
319
ts.it_value.tv_nsec = time % SPA_NSEC_PER_SEC;
320
ts.it_interval.tv_sec = 0;
321
322
return 0;
323
}
324
325
-int spa_alsa_silence(struct state *state, snd_pcm_uframes_t silence)
326
+static int spa_alsa_silence(struct state *state, snd_pcm_uframes_t silence)
327
{
328
snd_pcm_t *hndl = state->hndl;
329
const snd_pcm_channel_area_t *my_areas;
330
331
332
if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) {
333
spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s",
334
- state->props.device, snd_strerror(res));
335
+ state->name, snd_strerror(res));
336
return res;
337
}
338
silence = SPA_MIN(silence, frames);
339
340
341
if (SPA_UNLIKELY((res = snd_pcm_mmap_commit(hndl, offset, silence)) < 0)) {
342
spa_log_error(state->log, "%s: snd_pcm_mmap_commit error: %s",
343
- state->props.device, snd_strerror(res));
344
+ state->name, snd_strerror(res));
345
return res;
346
}
347
} else {
348
349
return 0;
350
}
351
352
+static void reset_buffers(struct state *this)
353
+{
354
+ uint32_t i;
355
+
356
+ spa_list_init(&this->free);
357
+ spa_list_init(&this->ready);
358
+
359
+ for (i = 0; i < this->n_buffers; i++) {
360
+ struct buffer *b = &this->buffersi;
361
+ if (this->stream == SND_PCM_STREAM_PLAYBACK) {
362
+ SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
363
+ spa_node_call_reuse_buffer(&this->callbacks, 0, b->id);
364
+ } else {
365
+ spa_list_append(&this->free, &b->link);
366
+ SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
367
+ }
368
+ }
369
+}
370
+
371
+
372
+static int do_prepare(struct state *state)
373
+{
374
+ int err;
375
+
376
+ state->last_threshold = state->threshold;
377
+
378
+ spa_log_debug(state->log, "%p: start threshold:%d duration:%d rate:%d follower:%d match:%d resample:%d",
379
+ state, state->threshold, state->driver_duration, state->driver_rate.denom,
380
+ state->following, state->matching, state->resample);
381
+
382
+ CHECK(set_swparams(state), "swparams");
383
+
384
+ if ((err = snd_pcm_prepare(state->hndl)) < 0 && err != -EBUSY) {
385
+ spa_log_error(state->log, "%s: snd_pcm_prepare error: %s",
386
+ state->name, snd_strerror(err));
387
+ return err;
388
+ }
389
+ if (state->stream == SND_PCM_STREAM_PLAYBACK) {
390
+ snd_pcm_uframes_t silence = state->start_delay + state->threshold + state->headroom;
391
+ if (state->disable_tsched)
392
+ silence += state->threshold;
393
+ spa_alsa_silence(state, silence);
394
+ }
395
+
396
+ reset_buffers(state);
397
+ state->alsa_sync = true;
398
+ state->alsa_sync_warning = false;
399
+ state->alsa_recovering = false;
400
+ state->alsa_started = false;
401
+
402
+ return 0;
403
+}
404
+
405
+static inline int do_drop(struct state *state)
406
+{
407
+ int res;
408
+ spa_log_debug(state->log, "%p: snd_pcm_drop %u", state, state->linked);
409
+ if (!state->linked && (res = snd_pcm_drop(state->hndl)) < 0) {
410
+ spa_log_error(state->log, "%s: snd_pcm_drop: %s",
411
+ state->name, snd_strerror(res));
412
+ return res;
413
+ }
414
+ return 0;
415
+}
416
+
417
static inline int do_start(struct state *state)
418
{
419
int res;
420
if (SPA_UNLIKELY(!state->alsa_started)) {
421
- spa_log_trace(state->log, "%p: snd_pcm_start", state);
422
- if ((res = snd_pcm_start(state->hndl)) < 0) {
423
+ spa_log_debug(state->log, "%p: snd_pcm_start %u", state, state->linked);
424
+ if (!state->linked && (res = snd_pcm_start(state->hndl)) < 0) {
425
spa_log_error(state->log, "%s: snd_pcm_start: %s",
426
- state->props.device, snd_strerror(res));
427
+ state->name, snd_strerror(res));
428
return res;
429
}
430
state->alsa_started = true;
431
432
return 0;
433
}
434
435
+static inline int check_position_config(struct state *state);
436
+
437
static int alsa_recover(struct state *state, int err)
438
{
439
int res, st;
440
snd_pcm_status_t *status;
441
+ struct state *driver, *follower;
442
443
snd_pcm_status_alloca(&status);
444
if (SPA_UNLIKELY((res = snd_pcm_status(state->hndl, status)) < 0)) {
445
spa_log_error(state->log, "%s: snd_pcm_status error: %s",
446
- state->props.device, snd_strerror(res));
447
+ state->name, snd_strerror(res));
448
goto recover;
449
}
450
451
452
}
453
case SND_PCM_STATE_SUSPENDED:
454
spa_log_info(state->log, "%s: recover from state %s",
455
- state->props.device, snd_pcm_state_name(st));
456
+ state->name, snd_pcm_state_name(st));
457
res = snd_pcm_resume(state->hndl);
458
if (res >= 0)
459
return res;
460
461
break;
462
default:
463
spa_log_error(state->log, "%s: recover from error state %s",
464
- state->props.device, snd_pcm_state_name(st));
465
+ state->name, snd_pcm_state_name(st));
466
break;
467
}
468
469
recover:
470
if (SPA_UNLIKELY((res = snd_pcm_recover(state->hndl, err, true)) < 0)) {
471
spa_log_error(state->log, "%s: snd_pcm_recover error: %s",
472
- state->props.device, snd_strerror(res));
473
+ state->name, snd_strerror(res));
474
return res;
475
}
476
- spa_dll_init(&state->dll);
477
- state->alsa_recovering = true;
478
- state->alsa_started = false;
479
+ if (state->driver && state->linked)
480
+ driver = state->driver;
481
+ else
482
+ driver = state;
483
484
- if (state->stream == SND_PCM_STREAM_PLAYBACK)
485
- spa_alsa_silence(state, state->start_delay + state->threshold + state->headroom);
486
+ do_drop(driver);
487
+ spa_list_for_each(follower, &driver->rt.followers, rt.driver_link) {
488
+ if (follower != driver && follower->linked) {
489
+ do_drop(follower);
490
+ check_position_config(follower);
491
+ }
492
+ }
493
+ do_prepare(driver);
494
+ spa_list_for_each(follower, &driver->rt.followers, rt.driver_link) {
495
+ if (follower != driver && follower->linked)
496
+ do_prepare(follower);
497
+ }
498
+ do_start(driver);
499
+ spa_list_for_each(follower, &driver->rt.followers, rt.driver_link) {
500
+ if (follower != driver && follower->linked)
501
+ do_start(follower);
502
+ }
503
+
504
+ return res;
505
+}
506
507
- return do_start(state);
508
+static inline snd_pcm_sframes_t alsa_avail(struct state *state)
509
+{
510
+ if (state->disable_tsched)
511
+ return snd_pcm_avail_update(state->hndl);
512
+ else
513
+ return snd_pcm_avail(state->hndl);
514
}
515
516
static int get_avail(struct state *state, uint64_t current_time, snd_pcm_uframes_t *delay)
517
518
int res, suppressed;
519
snd_pcm_sframes_t avail;
520
521
- if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) {
522
+ if (SPA_UNLIKELY((avail = alsa_avail(state)) < 0)) {
523
if ((res = alsa_recover(state, avail)) < 0)
524
return res;
525
- if ((avail = snd_pcm_avail(state->hndl)) < 0) {
526
+ if ((avail = alsa_avail(state)) < 0) {
527
if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
528
spa_log_warn(state->log, "%s: (%d suppressed) snd_pcm_avail after recover: %s",
529
- state->props.device, suppressed, snd_strerror(avail));
530
+ state->name, suppressed, snd_strerror(avail));
531
}
532
avail = state->threshold * 2;
533
}
534
535
if ((res = snd_pcm_htimestamp(state->hndl, &havail, &tstamp)) < 0) {
536
if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
537
spa_log_warn(state->log, "%s: (%d suppressed) snd_pcm_htimestamp error: %s",
538
- state->props.device, suppressed, snd_strerror(res));
539
+ state->name, suppressed, snd_strerror(res));
540
}
541
return avail;
542
}
543
544
} else {
545
if (++state->htimestamp_error > MAX_HTIMESTAMP_ERROR) {
546
spa_log_error(state->log, "%s: wrong htimestamps from driver, disabling",
547
- state->props.device);
548
+ state->name);
549
state->htimestamp_error = 0;
550
state->htimestamp = false;
551
}
552
else if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
553
spa_log_warn(state->log, "%s: (%d suppressed) impossible htimestamp diff:%"PRIi64,
554
- state->props.device, suppressed, diff);
555
+ state->name, suppressed, diff);
556
}
557
}
558
}
559
560
561
spa_log_debug(state->log, "%s: follower:%d match:%d rate:%f "
562
"bw:%f thr:%u del:%ld target:%ld err:%f max:%f",
563
- state->props.device, follower, state->matching,
564
+ state->name, follower, state->matching,
565
corr, state->dll.bw, state->threshold, delay, target,
566
err, state->max_error);
567
}
568
569
570
if (SPA_LIKELY(!follower && state->clock)) {
571
state->clock->nsec = current_time;
572
- state->clock->rate = state->clock->target_rate;
573
+ state->clock->rate = state->driver_rate;
574
state->clock->position += state->clock->duration;
575
- state->clock->duration = state->duration;
576
+ state->clock->duration = state->driver_duration;
577
state->clock->delay = delay + state->delay;
578
state->clock->rate_diff = corr;
579
state->clock->next_nsec = state->next_time;
580
581
return 0;
582
}
583
584
-static inline bool is_following(struct state *state)
585
-{
586
- return state->position && state->clock && state->position->clock.id != state->clock->id;
587
-}
588
-
589
static int setup_matching(struct state *state)
590
{
591
state->matching = state->following;
592
593
if (spa_streq(state->position->clock.name, state->clock_name))
594
state->matching = false;
595
596
- state->resample = !state->pitch_elem && (((uint32_t)state->rate != state->rate_denom) || state->matching);
597
+ state->resample = !state->pitch_elem && (((uint32_t)state->rate != state->driver_rate.denom) || state->matching);
598
599
spa_log_info(state->log, "driver clock:'%s'@%d our clock:'%s'@%d matching:%d resample:%d",
600
- state->position->clock.name, state->rate_denom,
601
+ state->position->clock.name, state->driver_rate.denom,
602
state->clock_name, state->rate,
603
state->matching, state->resample);
604
return 0;
605
606
607
static void update_sources(struct state *state, bool active)
608
{
609
- if (state->disable_tsched && state->source0.data != NULL) {
610
+ if (state->disable_tsched && state->rt.sources_added) {
611
for (int i = 0; i < state->n_fds; i++) {
612
state->sourcei.mask = active ? state->pfdsi.events : 0;
613
spa_loop_update_source(state->data_loop, &state->sourcei);
614
615
{
616
uint64_t target_duration;
617
struct spa_fraction target_rate;
618
+ struct spa_io_position *pos;
619
620
- if (SPA_UNLIKELY(state->position == NULL))
621
+ if (SPA_UNLIKELY((pos = state->position) == NULL))
622
return 0;
623
624
if (state->disable_tsched && state->started && !state->following) {
625
target_duration = state->period_frames;
626
target_rate = SPA_FRACTION(1, state->rate);
627
- state->position->clock.target_duration = target_duration;
628
- state->position->clock.target_rate = target_rate;
629
+ pos->clock.target_duration = target_duration;
630
+ pos->clock.target_rate = target_rate;
631
} else {
632
- target_duration = state->position->clock.target_duration;
633
- target_rate = state->position->clock.target_rate;
634
+ target_duration = pos->clock.target_duration;
635
+ target_rate = pos->clock.target_rate;
636
}
637
+ if (target_duration == 0 || target_rate.denom == 0)
638
+ return -EIO;
639
640
- if (SPA_UNLIKELY((state->duration != target_duration) ||
641
- (state->rate_denom != target_rate.denom))) {
642
- state->duration = target_duration;
643
- state->rate_denom = target_rate.denom;
644
- if (state->rate_denom == 0 || state->duration == 0)
645
- return -EIO;
646
- state->threshold = SPA_SCALE32_UP(state->duration, state->rate, state->rate_denom);
647
+ if (SPA_UNLIKELY((state->driver_duration != target_duration) ||
648
+ (state->driver_rate.denom != target_rate.denom))) {
649
+ spa_log_info(state->log, "%p: follower:%d duration:%u->%"PRIu64" rate:%d->%d",
650
+ state, state->following, state->driver_duration, target_duration,
651
+ state->driver_rate.denom, target_rate.denom);
652
+
653
+ state->driver_duration = target_duration;
654
+ state->driver_rate = target_rate;
655
+ state->threshold = SPA_SCALE32_UP(state->driver_duration, state->rate, state->driver_rate.denom);
656
state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f);
657
state->max_resync = SPA_MIN(state->threshold, state->max_error);
658
- state->resample = ((uint32_t)state->rate != state->rate_denom) || state->matching;
659
+ state->resample = ((uint32_t)state->rate != state->driver_rate.denom) || state->matching;
660
state->alsa_sync = true;
661
}
662
return 0;
663
}
664
665
-int spa_alsa_write(struct state *state)
666
+static int alsa_write_sync(struct state *state, uint64_t current_time)
667
{
668
- snd_pcm_t *hndl = state->hndl;
669
- const snd_pcm_channel_area_t *my_areas;
670
- snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write;
671
- snd_pcm_sframes_t commitres;
672
int res, suppressed;
673
- size_t frame_size = state->frame_size;
674
+ snd_pcm_uframes_t avail, delay, target;
675
+ bool following = state->following;
676
677
- if ((res = check_position_config(state)) < 0)
678
+ if (SPA_UNLIKELY((res = check_position_config(state)) < 0))
679
return res;
680
681
- max_write = state->buffer_frames;
682
-
683
- if (state->following && state->alsa_started) {
684
- uint64_t current_time;
685
- snd_pcm_uframes_t avail, delay, target;
686
-
687
- current_time = state->position->clock.nsec;
688
-
689
- if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0))
690
- return res;
691
+ if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0))
692
+ return res;
693
694
- if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, true)) < 0))
695
- return res;
696
+ if (SPA_UNLIKELY(!following && delay > target + state->max_error)) {
697
+ spa_log_trace(state->log, "%p: early wakeup %ld %lu %lu", state,
698
+ avail, delay, target);
699
+ if (delay > target * 3)
700
+ delay = target * 3;
701
+ state->next_time = current_time + (delay - target) * SPA_NSEC_PER_SEC / state->rate;
702
+ return -EAGAIN;
703
+ }
704
+ if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, following)) < 0))
705
+ return res;
706
707
+ if (following && !state->linked) {
708
if (SPA_UNLIKELY(state->alsa_sync)) {
709
enum spa_log_level lev;
710
711
712
if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
713
spa_log_lev(state->log, lev, "%s: follower avail:%lu delay:%ld "
714
"target:%ld thr:%u, resync (%d suppressed)",
715
- state->props.device, avail, delay,
716
+ state->name, avail, delay,
717
target, state->threshold, suppressed);
718
}
719
720
721
} else
722
state->alsa_sync_warning = true;
723
}
724
+ return 0;
725
+}
726
+
727
+static int alsa_write_frames(struct state *state)
728
+{
729
+ snd_pcm_t *hndl = state->hndl;
730
+ const snd_pcm_channel_area_t *my_areas;
731
+ snd_pcm_uframes_t written, frames, offset, off, to_write, total_written;
732
+ snd_pcm_sframes_t commitres;
733
+ int res = 0;
734
+ size_t frame_size = state->frame_size;
735
736
total_written = 0;
737
again:
738
-
739
- frames = max_write;
740
+ frames = state->buffer_frames;
741
if (state->use_mmap && frames > 0) {
742
if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) {
743
spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s",
744
- state->props.device, snd_strerror(res));
745
+ state->name, snd_strerror(res));
746
alsa_recover(state, res);
747
return res;
748
}
749
750
if (state->use_mmap && written > 0) {
751
if (SPA_UNLIKELY((commitres = snd_pcm_mmap_commit(hndl, offset, written)) < 0)) {
752
spa_log_error(state->log, "%s: snd_pcm_mmap_commit error: %s",
753
- state->props.device, snd_strerror(commitres));
754
+ state->name, snd_strerror(commitres));
755
if (commitres != -EPIPE && commitres != -ESTRPIPE)
756
return res;
757
}
758
if (commitres > 0 && written != (snd_pcm_uframes_t) commitres) {
759
spa_log_warn(state->log, "%s: mmap_commit wrote %ld instead of %ld",
760
- state->props.device, commitres, written);
761
+ state->name, commitres, written);
762
}
763
}
764
765
766
return 0;
767
}
768
769
+int spa_alsa_write(struct state *state)
770
+{
771
+ int res = 0;
772
+ if (state->following && state->rt.driver == NULL) {
773
+ uint64_t current_time = state->position->clock.nsec;
774
+ if ((res = alsa_write_sync(state, current_time)) < 0)
775
+ return res;
776
+ }
777
+ return alsa_write_frames(state);
778
+}
779
+
780
void spa_alsa_recycle_buffer(struct state *this, uint32_t buffer_id)
781
{
782
struct buffer *b = &this->buffersbuffer_id;
783
784
snd_pcm_uframes_t total_frames = 0;
785
786
if (spa_list_is_empty(&state->free)) {
787
- spa_log_warn(state->log, "%s: no more buffers", state->props.device);
788
+ spa_log_warn(state->log, "%s: no more buffers", state->name);
789
total_frames = frames;
790
} else {
791
size_t n_bytes, left, frame_size = state->frame_size;
792
793
return total_frames;
794
}
795
796
-
797
-int spa_alsa_read(struct state *state)
798
+static int alsa_read_sync(struct state *state, uint64_t current_time)
799
{
800
- snd_pcm_t *hndl = state->hndl;
801
- snd_pcm_uframes_t total_read = 0, to_read, max_read;
802
- const snd_pcm_channel_area_t *my_areas;
803
- snd_pcm_uframes_t read, frames, offset;
804
- snd_pcm_sframes_t commitres;
805
int res, suppressed;
806
+ snd_pcm_uframes_t avail, delay, target, max_read;
807
+ bool following = state->following;
808
809
- if ((res = check_position_config(state)) < 0)
810
- return res;
811
-
812
- max_read = state->buffer_frames;
813
+ if (SPA_UNLIKELY(!state->alsa_started))
814
+ return 0;
815
816
- if (state->following && state->alsa_started) {
817
- uint64_t current_time;
818
- snd_pcm_uframes_t avail, delay, target;
819
+ if (SPA_UNLIKELY((res = check_position_config(state)) < 0))
820
+ return res;
821
822
- current_time = state->position->clock.nsec;
823
+ if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0))
824
+ return res;
825
826
- if ((res = get_status(state, current_time, &avail, &delay, &target)) < 0)
827
- return res;
828
+ if (SPA_UNLIKELY(!following && avail < state->read_size)) {
829
+ spa_log_trace(state->log, "%p: early wakeup %ld %ld %ld %d", state,
830
+ delay, avail, target, state->read_size);
831
+ state->next_time = current_time + (state->read_size - avail) * SPA_NSEC_PER_SEC /
832
+ state->rate;
833
+ return -EAGAIN;
834
+ }
835
836
- if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, true)) < 0))
837
- return res;
838
+ if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, following)) < 0))
839
+ return res;
840
841
+ max_read = state->buffer_frames;
842
+ if (following) {
843
if (state->alsa_sync) {
844
enum spa_log_level lev;
845
846
847
848
if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
849
spa_log_lev(state->log, lev, "%s: follower delay:%ld target:%ld thr:%u, "
850
- "resync (%d suppressed)", state->props.device, delay,
851
+ "resync (%d suppressed)", state->name, delay,
852
target, state->threshold, suppressed);
853
}
854
855
856
if (avail < state->read_size)
857
max_read = 0;
858
}
859
+ state->max_read = SPA_MIN(max_read, state->read_size);
860
+ return 0;
861
+}
862
+
863
+static int alsa_read_frames(struct state *state)
864
+{
865
+ snd_pcm_t *hndl = state->hndl;
866
+ snd_pcm_uframes_t total_read = 0, to_read;
867
+ const snd_pcm_channel_area_t *my_areas;
868
+ snd_pcm_uframes_t read, frames, offset;
869
+ snd_pcm_sframes_t commitres;
870
+ int res = 0;
871
872
- frames = SPA_MIN(max_read, state->read_size);
873
+ frames = state->max_read;
874
875
if (state->use_mmap) {
876
to_read = state->buffer_frames;
877
if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &to_read)) < 0) {
878
spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s",
879
- state->props.device, snd_strerror(res));
880
+ state->name, snd_strerror(res));
881
alsa_recover(state, res);
882
return res;
883
}
884
885
spa_log_trace_fp(state->log, "%p: commit offs:%ld read:%ld count:%"PRIi64, state,
886
offset, read, state->sample_count);
887
if ((commitres = snd_pcm_mmap_commit(hndl, offset, read)) < 0) {
888
- spa_log_error(state->log, "%s: snd_pcm_mmap_commit error %lu %lu: %s",
889
- state->props.device, frames, read, snd_strerror(commitres));
890
+ enum spa_log_level lev;
891
+
892
+ if (SPA_UNLIKELY(state->alsa_sync_warning))
893
+ lev = SPA_LOG_LEVEL_ERROR;
894
+ else
895
+ lev = SPA_LOG_LEVEL_INFO;
896
+
897
+ spa_log_lev(state->log, lev, "%s: snd_pcm_mmap_commit error %lu %lu %lu: %s",
898
+ state->name, frames, to_read, read, snd_strerror(commitres));
899
if (commitres != -EPIPE && commitres != -ESTRPIPE)
900
return res;
901
}
902
if (commitres > 0 && read != (snd_pcm_uframes_t) commitres) {
903
spa_log_warn(state->log, "%s: mmap_commit read %ld instead of %ld",
904
- state->props.device, commitres, read);
905
+ state->name, commitres, read);
906
}
907
}
908
909
910
return 0;
911
}
912
913
+int spa_alsa_read(struct state *state)
914
+{
915
+ int res;
916
+ if (state->following && state->rt.driver == NULL) {
917
+ uint64_t current_time = state->position->clock.nsec;
918
+ if ((res = alsa_read_sync(state, current_time)) < 0)
919
+ return res;
920
+ }
921
+ return alsa_read_frames(state);
922
+}
923
+
924
int spa_alsa_skip(struct state *state)
925
{
926
struct buffer *b;
927
struct spa_data *d;
928
uint32_t i, avail, total_frames, n_bytes, frames;
929
930
- if (spa_list_is_empty(&state->free)) {
931
- spa_log_warn(state->log, "%s: no more buffers", state->props.device);
932
+ if (SPA_UNLIKELY(spa_list_is_empty(&state->free))) {
933
+ spa_log_warn(state->log, "%s: no more buffers", state->name);
934
return -EPIPE;
935
}
936
937
938
}
939
940
941
-static int handle_play(struct state *state, uint64_t current_time, snd_pcm_uframes_t avail,
942
- snd_pcm_uframes_t delay, snd_pcm_uframes_t target)
943
+static int playback_ready(struct state *state)
944
{
945
struct spa_io_buffers *io = state->io;
946
- int res;
947
-
948
- if (state->alsa_started && SPA_UNLIKELY(delay > target + state->max_error)) {
949
- spa_log_trace(state->log, "%p: early wakeup %ld %lu %lu", state,
950
- avail, delay, target);
951
- if (delay > target * 3)
952
- delay = target * 3;
953
- state->next_time = current_time + (delay - target) * SPA_NSEC_PER_SEC / state->rate;
954
- return -EAGAIN;
955
- }
956
-
957
- if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, false)) < 0))
958
- return res;
959
960
spa_log_trace_fp(state->log, "%p: %d", state, io->status);
961
962
963
return spa_node_call_ready(&state->callbacks, SPA_STATUS_NEED_DATA);
964
}
965
966
-static int handle_capture(struct state *state, uint64_t current_time, snd_pcm_uframes_t avail,
967
- snd_pcm_uframes_t delay, snd_pcm_uframes_t target)
968
+static int capture_ready(struct state *state)
969
{
970
- int res;
971
struct spa_io_buffers *io;
972
+ bool have_data;
973
974
- if (SPA_UNLIKELY(avail < state->read_size)) {
975
- spa_log_trace(state->log, "%p: early wakeup %ld %ld %ld %d", state,
976
- delay, avail, target, state->read_size);
977
- state->next_time = current_time + (state->read_size - avail) * SPA_NSEC_PER_SEC /
978
- state->rate;
979
- return -EAGAIN;
980
- }
981
-
982
- if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, false)) < 0))
983
- return res;
984
-
985
- if ((res = spa_alsa_read(state)) < 0)
986
- return res;
987
-
988
- if (spa_list_is_empty(&state->ready))
989
- return 0;
990
+ have_data = !spa_list_is_empty(&state->ready);
991
992
io = state->io;
993
if (io != NULL &&
994
(io->status != SPA_STATUS_HAVE_DATA || state->rate_match != NULL)) {
995
struct buffer *b;
996
997
- if (io->buffer_id < state->n_buffers)
998
+ if (SPA_LIKELY(io->buffer_id < state->n_buffers))
999
spa_alsa_recycle_buffer(state, io->buffer_id);
1000
1001
- b = spa_list_first(&state->ready, struct buffer, link);
1002
- spa_list_remove(&b->link);
1003
- SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
1004
+ if (SPA_LIKELY(have_data)) {
1005
+ b = spa_list_first(&state->ready, struct buffer, link);
1006
+ spa_list_remove(&b->link);
1007
+ SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
1008
1009
- io->buffer_id = b->id;
1010
- io->status = SPA_STATUS_HAVE_DATA;
1011
- spa_log_trace_fp(state->log, "%p: output buffer:%d", state, b->id);
1012
+ io->buffer_id = b->id;
1013
+ io->status = SPA_STATUS_HAVE_DATA;
1014
+ } else {
1015
+ io->buffer_id = SPA_ID_INVALID;
1016
+ }
1017
+ spa_log_trace_fp(state->log, "%p: output buffer:%d", state, io->buffer_id);
1018
}
1019
- spa_node_call_ready(&state->callbacks, SPA_STATUS_HAVE_DATA);
1020
+ if (have_data)
1021
+ spa_node_call_ready(&state->callbacks, SPA_STATUS_HAVE_DATA);
1022
return 0;
1023
}
1024
1025
1026
1027
static void alsa_wakeup_event(struct spa_source *source)
1028
{
1029
- struct state *state = source->data;
1030
- snd_pcm_uframes_t avail, delay, target;
1031
+ struct state *state = source->data, *follower;
1032
uint64_t expire, current_time;
1033
int res, suppressed;
1034
1035
1036
current_time = state->next_time;
1037
}
1038
1039
- if (SPA_UNLIKELY((res = check_position_config(state)) < 0)) {
1040
- spa_log_warn(state->log, "%p: error invalid position: %s",
1041
- state, spa_strerror(res));
1042
- return;
1043
- }
1044
-
1045
- if (SPA_UNLIKELY(get_status(state, current_time, &avail, &delay, &target) < 0)) {
1046
- spa_log_error(state->log, "get_status error");
1047
- state->next_time += state->threshold * 1e9 / state->rate;
1048
+ /* first do all the sync */
1049
+ if (state->stream == SND_PCM_STREAM_CAPTURE)
1050
+ res = alsa_read_sync(state, current_time);
1051
+ else
1052
+ res = alsa_write_sync(state, current_time);
1053
+ /* we can get -EAGAIN when we need to wait some more */
1054
+ if (SPA_UNLIKELY(res == -EAGAIN))
1055
goto done;
1056
- }
1057
1058
-#ifndef FASTPATH
1059
- if (SPA_UNLIKELY(spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) {
1060
- uint64_t nsec = get_time_ns(state);
1061
- spa_log_trace_fp(state->log, "%p: wakeup %lu %lu %lu %"PRIu64" %"PRIu64" %"PRIi64
1062
- " %d %"PRIi64, state, avail, delay, target, nsec, nsec,
1063
- nsec - current_time, state->threshold, state->sample_count);
1064
+ spa_list_for_each(follower, &state->rt.followers, rt.driver_link) {
1065
+ if (follower == state)
1066
+ continue;
1067
+ if (follower->stream == SND_PCM_STREAM_CAPTURE)
1068
+ alsa_read_sync(follower, current_time);
1069
+ else
1070
+ alsa_write_sync(follower, current_time);
1071
}
1072
-#endif
1073
1074
+ /* then read this source, the sinks will be written to when the
1075
+ * graph completes. We can't read other follower sources yet because
1076
+ * the resampler first needs to run. */
1077
+ if (state->stream == SND_PCM_STREAM_CAPTURE)
1078
+ alsa_read_frames(state);
1079
+
1080
+ /* and then trigger the graph */
1081
if (state->stream == SND_PCM_STREAM_PLAYBACK)
1082
- handle_play(state, current_time, avail, delay, target);
1083
+ playback_ready(state);
1084
else
1085
- handle_capture(state, current_time, avail, delay, target);
1086
+ capture_ready(state);
1087
1088
done:
1089
- if (!state->disable_tsched &&
1090
- (state->next_time > current_time + SPA_NSEC_PER_SEC ||
1091
- current_time > state->next_time + SPA_NSEC_PER_SEC)) {
1092
- if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
1093
- spa_log_error(state->log, "%s: impossible timeout %lu %lu %lu %"
1094
+ if (!state->disable_tsched) {
1095
+ if (state->next_time > current_time + SPA_NSEC_PER_SEC ||
1096
+ current_time > state->next_time + SPA_NSEC_PER_SEC) {
1097
+ if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
1098
+ spa_log_error(state->log, "%s: impossible timeout %"
1099
PRIu64" %"PRIu64" %"PRIi64" %d %"PRIi64" (%d suppressed)",
1100
- state->props.device, avail, delay, target,
1101
- current_time, state->next_time, state->next_time - current_time,
1102
- state->threshold, state->sample_count, suppressed);
1103
+ state->name, current_time, state->next_time,
1104
+ state->next_time - current_time, state->threshold,
1105
+ state->sample_count, suppressed);
1106
+ }
1107
+ state->next_time = current_time + state->threshold * 1e9 / state->rate;
1108
}
1109
- state->next_time = current_time + state->threshold * 1e9 / state->rate;
1110
+ set_timeout(state, state->next_time);
1111
}
1112
- set_timeout(state, state->next_time);
1113
}
1114
1115
-static void reset_buffers(struct state *this)
1116
+static void remove_sources(struct state *state)
1117
{
1118
- uint32_t i;
1119
-
1120
- spa_list_init(&this->free);
1121
- spa_list_init(&this->ready);
1122
-
1123
- for (i = 0; i < this->n_buffers; i++) {
1124
- struct buffer *b = &this->buffersi;
1125
- if (this->stream == SND_PCM_STREAM_PLAYBACK) {
1126
- SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
1127
- spa_node_call_reuse_buffer(&this->callbacks, 0, b->id);
1128
- } else {
1129
- spa_list_append(&this->free, &b->link);
1130
- SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
1131
- }
1132
+ int i;
1133
+ if (state->rt.sources_added) {
1134
+ for (i = 0; i < state->n_fds; i++)
1135
+ spa_loop_remove_source(state->data_loop, &state->sourcei);
1136
+ state->rt.sources_added = false;
1137
}
1138
}
1139
1140
-static void clear_period_sources(struct state *state) {
1141
- /* This check is to make sure we've actually added the sources
1142
- * previously */
1143
- if (state->source0.data) {
1144
- for (int i = 0; i < state->n_fds; i++) {
1145
- spa_loop_remove_source(state->data_loop, &state->sourcei);
1146
- state->sourcei.func = NULL;
1147
- state->sourcei.data = NULL;
1148
- state->sourcei.fd = -1;
1149
- state->sourcei.mask = 0;
1150
- state->sourcei.rmask = 0;
1151
- }
1152
+static void add_sources(struct state *state)
1153
+{
1154
+ int i;
1155
+ if (!state->rt.sources_added) {
1156
+ for (i = 0; i < state->n_fds; i++)
1157
+ spa_loop_add_source(state->data_loop, &state->sourcei);
1158
+ state->rt.sources_added = true;
1159
}
1160
}
1161
1162
-static int setup_sources(struct state *state)
1163
+static int do_state_sync(struct spa_loop *loop, bool async, uint32_t seq,
1164
+ const void *data, size_t size, void *user_data)
1165
{
1166
- state->next_time = get_time_ns(state);
1167
+ struct state *state = user_data;
1168
+ struct rt_state *rt = &state->rt;
1169
+
1170
+ if (state->started) {
1171
+ state->next_time = get_time_ns(state);
1172
+
1173
+ if (rt->driver != state->driver) {
1174
+ spa_dll_init(&state->dll);
1175
1176
- if (state->following) {
1177
- /* Disable wakeups from this node */
1178
- if (!state->disable_tsched) {
1179
+ if (rt->driver != NULL)
1180
+ spa_list_remove(&rt->driver_link);
1181
+ if (state->driver != NULL)
1182
+ spa_list_append(&state->driver->rt.followers, &rt->driver_link);
1183
+ rt->driver = state->driver;
1184
+ spa_log_debug(state->log, "state:%p -> driver:%p", state, state->driver);
1185
+ }
1186
+ if (state->following) {
1187
+ remove_sources(state);
1188
set_timeout(state, 0);
1189
} else {
1190
- clear_period_sources(state);
1191
+ add_sources(state);
1192
+ if (!state->disable_tsched)
1193
+ set_timeout(state, state->next_time);
1194
}
1195
} else {
1196
- /* We're driving, so let's wake up when data is ready/needed */
1197
- if (!state->disable_tsched) {
1198
- set_timeout(state, state->next_time);
1199
- } else {
1200
- for (int i = 0; i < state->n_fds; i++) {
1201
- state->sourcei.func = alsa_wakeup_event;
1202
- state->sourcei.data = state;
1203
- state->sourcei.fd = state->pfdsi.fd;
1204
- state->sourcei.mask = state->pfdsi.events;
1205
- state->sourcei.rmask = 0;
1206
- spa_loop_add_source(state->data_loop, &state->sourcei);
1207
- }
1208
+ if (rt->driver) {
1209
+ spa_list_remove(&rt->driver_link);
1210
+ rt->driver = NULL;
1211
}
1212
+ if (!state->disable_tsched)
1213
+ set_timeout(state, 0);
1214
+ remove_sources(state);
1215
}
1216
return 0;
1217
}
1218
1219
-static int do_setup_sources(struct spa_loop *loop,
1220
- bool async,
1221
- uint32_t seq,
1222
- const void *data,
1223
- size_t size,
1224
- void *user_data)
1225
-{
1226
- struct state *state = user_data;
1227
- spa_dll_init(&state->dll);
1228
- setup_sources(state);
1229
- return 0;
1230
-}
1231
-
1232
-int spa_alsa_start(struct state *state)
1233
+int spa_alsa_prepare(struct state *state)
1234
{
1235
+ struct state *follower;
1236
int err;
1237
1238
- if (state->started)
1239
- return 0;
1240
+ spa_alsa_pause(state);
1241
1242
- state->following = is_following(state);
1243
+ if (state->prepared)
1244
+ return 0;
1245
1246
if (check_position_config(state) < 0) {
1247
- spa_log_error(state->log, "%s: invalid position config", state->props.device);
1248
+ spa_log_error(state->log, "%s: invalid position config", state->name);
1249
return -EIO;
1250
}
1251
+ if ((err = do_prepare(state)) < 0)
1252
+ return err;
1253
1254
- setup_matching(state);
1255
+ spa_list_for_each(follower, &state->followers, driver_link) {
1256
+ if (follower != state && !follower->matching) {
1257
+ spa_alsa_prepare(follower);
1258
+ if (!follower->linked)
1259
+ do_link(state, follower);
1260
+ }
1261
+ }
1262
1263
- spa_dll_init(&state->dll);
1264
- state->last_threshold = state->threshold;
1265
+ state->prepared = true;
1266
1267
- spa_log_debug(state->log, "%p: start %d duration:%d rate:%d follower:%d match:%d resample:%d",
1268
- state, state->threshold, state->duration, state->rate_denom,
1269
- state->following, state->matching, state->resample);
1270
+ return 0;
1271
+}
1272
1273
- CHECK(set_swparams(state), "swparams");
1274
+int spa_alsa_start(struct state *state)
1275
+{
1276
+ struct state *follower;
1277
+ int err;
1278
1279
- if ((err = snd_pcm_prepare(state->hndl)) < 0 && err != -EBUSY) {
1280
- spa_log_error(state->log, "%s: snd_pcm_prepare error: %s",
1281
- state->props.device, snd_strerror(err));
1282
- return err;
1283
- }
1284
+ if (state->started)
1285
+ return 0;
1286
+
1287
+ spa_alsa_prepare(state);
1288
1289
if (!state->disable_tsched) {
1290
/* Timer-based scheduling */
1291
1292
state->source0.fd = state->timerfd;
1293
state->source0.mask = SPA_IO_IN;
1294
state->source0.rmask = 0;
1295
- spa_loop_add_source(state->data_loop, &state->source0);
1296
+ state->n_fds = 1;
1297
} else {
1298
/* ALSA period-based scheduling */
1299
err = snd_pcm_poll_descriptors_count(state->hndl);
1300
1301
/* We only add the source to the data loop if we're driving.
1302
* This is done in setup_sources() */
1303
for (int i = 0; i < state->n_fds; i++) {
1304
- state->sourcei.func = NULL;
1305
- state->sourcei.data = NULL;
1306
- state->sourcei.fd = -1;
1307
- state->sourcei.mask = 0;
1308
+ state->sourcei.func = alsa_wakeup_event;
1309
+ state->sourcei.data = state;
1310
+ state->sourcei.fd = state->pfdsi.fd;
1311
+ state->sourcei.mask = state->pfdsi.events;
1312
state->sourcei.rmask = 0;
1313
}
1314
}
1315
1316
- reset_buffers(state);
1317
- state->alsa_sync = true;
1318
- state->alsa_sync_warning = false;
1319
- state->alsa_recovering = false;
1320
- state->alsa_started = false;
1321
+ spa_list_for_each(follower, &state->followers, driver_link)
1322
+ if (follower != state)
1323
+ spa_alsa_start(follower);
1324
1325
- /* start capture now, playback will start after first write. Without tsched, we start
1326
- * right away so that the fds become active in poll right away. */
1327
- if (state->stream == SND_PCM_STREAM_PLAYBACK) {
1328
- spa_alsa_silence(state, state->start_delay + state->threshold + state->headroom);
1329
- if (state->disable_tsched)
1330
- do_start(state);
1331
+ /* start capture now. We should have some data when the timer or IRQ
1332
+ * goes off later */
1333
+ if (state->stream == SND_PCM_STREAM_CAPTURE) {
1334
+ if ((err = do_start(state)) < 0)
1335
+ return err;
1336
}
1337
- else if ((err = do_start(state)) < 0)
1338
- return err;
1339
-
1340
- spa_loop_invoke(state->data_loop, do_setup_sources, 0, NULL, 0, true, state);
1341
1342
state->started = true;
1343
+ spa_loop_invoke(state->data_loop, do_state_sync, 0, NULL, 0, true, state);
1344
1345
+ /* playback will start after first write. Without tsched, we start
1346
+ * right away so that the fds become active in poll right away. */
1347
+ if (state->stream == SND_PCM_STREAM_PLAYBACK) {
1348
+ if (state->disable_tsched)
1349
+ if ((err = do_start(state)) < 0)
1350
+ return err;
1351
+ }
1352
return 0;
1353
}
1354
1355
+static struct state *find_state(uint32_t id)
1356
+{
1357
+ struct state *state;
1358
+ spa_list_for_each(state, &states, link) {
1359
+ if (state->clock != NULL && state->clock->id == id)
1360
+ return state;
1361
+ }
1362
+ return NULL;
1363
+}
1364
+
1365
int spa_alsa_reassign_follower(struct state *state)
1366
{
1367
bool following, freewheel;
1368
+ struct spa_io_position *pos = state->position;
1369
+ struct spa_io_clock *clock = state->clock;
1370
+ struct state *driver;
1371
1372
- if (!state->started)
1373
- return 0;
1374
+ if (clock != NULL)
1375
+ spa_scnprintf(clock->name, sizeof(clock->name), "%s", state->clock_name);
1376
1377
- following = is_following(state);
1378
+ following = pos && clock && pos->clock.id != clock->id;
1379
+
1380
+ driver = pos != NULL ? find_state(pos->clock.id) : NULL;
1381
+
1382
+ if (driver != state->driver) {
1383
+ spa_log_debug(state->log, "%p: reassign driver %p->%p", state, state->driver, driver);
1384
+ if (state->driver != NULL)
1385
+ spa_list_remove(&state->driver_link);
1386
+ if (driver != NULL) {
1387
+ spa_list_append(&driver->followers, &state->driver_link);
1388
+ }
1389
+ state->driver = driver;
1390
+ }
1391
if (following != state->following) {
1392
spa_log_debug(state->log, "%p: reassign follower %d->%d", state, state->following, following);
1393
state->following = following;
1394
- spa_loop_invoke(state->data_loop, do_setup_sources, 0, NULL, 0, true, state);
1395
+ setup_matching(state);
1396
}
1397
- setup_matching(state);
1398
-
1399
- freewheel = state->position &&
1400
- SPA_FLAG_IS_SET(state->position->clock.flags, SPA_IO_CLOCK_FLAG_FREEWHEEL);
1401
+ if (state->started)
1402
+ spa_loop_invoke(state->data_loop, do_state_sync, 0, NULL, 0, true, state);
1403
1404
+ freewheel = pos != NULL && SPA_FLAG_IS_SET(pos->clock.flags, SPA_IO_CLOCK_FLAG_FREEWHEEL);
1405
if (state->freewheel != freewheel) {
1406
spa_log_debug(state->log, "%p: freewheel %d->%d", state, state->freewheel, freewheel);
1407
state->freewheel = freewheel;
1408
- if (freewheel)
1409
- snd_pcm_pause(state->hndl, 1);
1410
- else
1411
- snd_pcm_pause(state->hndl, 0);
1412
+ if (state->started) {
1413
+ if (freewheel)
1414
+ snd_pcm_pause(state->hndl, 1);
1415
+ else
1416
+ snd_pcm_pause(state->hndl, 0);
1417
+ }
1418
}
1419
-
1420
state->alsa_sync_warning = false;
1421
return 0;
1422
}
1423
1424
-static int do_remove_source(struct spa_loop *loop,
1425
- bool async,
1426
- uint32_t seq,
1427
- const void *data,
1428
- size_t size,
1429
- void *user_data)
1430
-{
1431
- struct state *state = user_data;
1432
-
1433
- if (!state->disable_tsched) {
1434
- spa_loop_remove_source(state->data_loop, &state->source0);
1435
- set_timeout(state, 0);
1436
- } else {
1437
- clear_period_sources(state);
1438
- }
1439
- return 0;
1440
-}
1441
-
1442
int spa_alsa_pause(struct state *state)
1443
{
1444
- int err;
1445
+ struct state *follower;
1446
1447
if (!state->started)
1448
return 0;
1449
1450
spa_log_debug(state->log, "%p: pause", state);
1451
1452
- spa_loop_invoke(state->data_loop, do_remove_source, 0, NULL, 0, true, state);
1453
+ state->started = false;
1454
+ spa_loop_invoke(state->data_loop, do_state_sync, 0, NULL, 0, true, state);
1455
1456
- if ((err = snd_pcm_drop(state->hndl)) < 0)
1457
- spa_log_error(state->log, "%s: snd_pcm_drop %s", state->props.device,
1458
- snd_strerror(err));
1459
+ spa_list_for_each(follower, &state->followers, driver_link)
1460
+ spa_alsa_pause(follower);
1461
1462
- state->started = false;
1463
+ do_drop(state);
1464
+
1465
+ state->prepared = false;
1466
1467
return 0;
1468
}
1469
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
111
1
2
uint32_t rate;
3
};
4
5
+struct rt_state {
6
+ struct spa_list followers;
7
+ struct state *driver;
8
+ struct spa_list driver_link;
9
+
10
+ unsigned int sources_added:1;
11
+ unsigned int following:1;
12
+};
13
+
14
struct state {
15
struct spa_handle handle;
16
struct spa_node node;
17
18
struct card *card;
19
snd_pcm_stream_t stream;
20
snd_output_t *output;
21
+ char name64;
22
23
struct spa_hook_list hooks;
24
struct spa_callbacks callbacks;
25
26
struct spa_param_info paramsN_NODE_PARAMS;
27
struct props props;
28
29
- bool opened;
30
+ unsigned int opened:1;
31
+ unsigned int prepared:1;
32
+ unsigned int started:1;
33
snd_pcm_t *hndl;
34
35
bool have_format;
36
37
uint32_t allowed_ratesMAX_RATES;
38
uint32_t n_allowed_rates;
39
struct channel_map default_pos;
40
- unsigned int disable_mmap;
41
- unsigned int disable_batch;
42
- unsigned int disable_tsched;
43
+ unsigned int disable_mmap:1;
44
+ unsigned int disable_batch:1;
45
+ unsigned int disable_tsched:1;
46
char clock_name64;
47
uint32_t quantum_limit;
48
49
50
size_t frame_size;
51
size_t frame_scale;
52
int blocks;
53
- uint32_t rate_denom;
54
uint32_t delay;
55
uint32_t read_size;
56
+ uint32_t max_read;
57
58
uint64_t port_info_all;
59
struct spa_port_info port_info;
60
61
62
size_t ready_offset;
63
64
- bool started;
65
/* Either a single source for tsched, or a set of pollfds from ALSA */
66
struct spa_source sourceMAX_POLL;
67
int timerfd;
68
69
uint32_t max_delay;
70
uint32_t htimestamp_error;
71
72
- uint32_t duration;
73
+ struct spa_fraction driver_rate;
74
+ uint32_t driver_duration;
75
+
76
unsigned int alsa_started:1;
77
unsigned int alsa_sync:1;
78
unsigned int alsa_sync_warning:1;
79
80
unsigned int multi_rate:1;
81
unsigned int htimestamp:1;
82
unsigned int is_pro:1;
83
+ unsigned int sources_added:1;
84
+ unsigned int linked:1;
85
86
uint64_t iec958_codecs;
87
88
89
snd_ctl_t *ctl;
90
snd_ctl_elem_value_t *pitch_elem;
91
double last_rate;
92
+
93
+ struct spa_list link;
94
+
95
+ struct spa_list followers;
96
+ struct state *driver;
97
+ struct spa_list driver_link;
98
+
99
+ struct rt_state rt;
100
};
101
102
struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
103
104
int spa_alsa_clear(struct state *state);
105
106
int spa_alsa_open(struct state *state, const char *params);
107
+int spa_alsa_prepare(struct state *state);
108
int spa_alsa_start(struct state *state);
109
int spa_alsa_reassign_follower(struct state *state);
110
int spa_alsa_pause(struct state *state);
111
pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.81.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
79
1
2
struct spa_data *datas;
3
uint64_t follower_flags, conv_flags;
4
5
- if (this->target == this->follower)
6
- return 0;
7
-
8
spa_log_debug(this->log, "%p: n_buffers:%d", this, this->n_buffers);
9
10
if (this->n_buffers > 0)
11
12
this->have_format = format != NULL;
13
if (format == NULL) {
14
this->n_buffers = 0;
15
- } else {
16
+ } else if (this->target != this->follower) {
17
res = negotiate_buffers(this);
18
}
19
-
20
return res;
21
}
22
23
24
struct spa_latency_info latency;
25
int res;
26
27
- spa_log_info(this->log, "%p: %d:%d", this, direction, port_id);
28
+ spa_log_debug(this->log, "%p: %d:%d", this, direction, port_id);
29
30
if (this->target == this->follower)
31
return 0;
32
33
int res = 0;
34
struct spa_hook l;
35
36
- spa_log_info(this->log, "%p: passthrough mode %d", this, passthrough);
37
+ spa_log_debug(this->log, "%p: passthrough mode %d", this, passthrough);
38
39
if (this->passthrough != passthrough) {
40
if (passthrough) {
41
42
struct spa_pod_builder b = { 0 };
43
int res;
44
45
- if (this->target == this->follower)
46
- return 0;
47
-
48
spa_log_debug(this->log, "%p: have_format:%d", this, this->have_format);
49
50
if (this->have_format)
51
52
switch (SPA_NODE_COMMAND_ID(command)) {
53
case SPA_NODE_COMMAND_Start:
54
spa_log_debug(this->log, "%p: starting %d", this, this->started);
55
- if (this->started)
56
- return 0;
57
- if ((res = negotiate_format(this)) < 0)
58
- return res;
59
- if ((res = negotiate_buffers(this)) < 0)
60
- return res;
61
+ if (this->target != this->follower) {
62
+ if (this->started)
63
+ return 0;
64
+ if ((res = negotiate_format(this)) < 0)
65
+ return res;
66
+ }
67
this->ready = true;
68
this->warned = false;
69
break;
70
71
uint32_t i;
72
int res;
73
74
- spa_log_info(this->log, "%p: convert port info %s %p %08"PRIx64, this,
75
+ spa_log_debug(this->log, "%p: convert port info %s %p %08"PRIx64, this,
76
this->direction == SPA_DIRECTION_INPUT ?
77
"Input" : "Output", info, info->change_mask);
78
79
pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.81.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
120
1
2
}
3
spa_list_init(&port->queue);
4
5
- spa_log_info(this->log, "%p: add port %d:%d position:%s %d %d %d",
6
- this, direction, port_id, port->position, is_dsp, is_monitor, is_control);
7
+ spa_log_debug(this->log, "%p: add port %d:%d position:%s %d %d %d",
8
+ this, direction, port_id, port->position, is_dsp,
9
+ is_monitor, is_control);
10
emit_port_info(this, port, true);
11
12
return 0;
13
14
(info == NULL || memcmp(&dir->format, info, sizeof(*info)) == 0))
15
return 0;
16
17
- spa_log_info(this->log, "%p: port config direction:%d monitor:%d control:%d mode:%d %d", this,
18
- direction, monitor, control, mode, dir->n_ports);
19
+ spa_log_debug(this->log, "%p: port config direction:%d monitor:%d "
20
+ "control:%d mode:%d %d", this, direction, monitor,
21
+ control, mode, dir->n_ports);
22
23
for (i = 0; i < dir->n_ports; i++) {
24
spa_node_emit_port_info(&this->hooks, direction, i, NULL);
25
26
SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED);
27
}
28
29
+static void free_tmp(struct impl *this)
30
+{
31
+ uint32_t i;
32
+
33
+ spa_log_debug(this->log, "free tmp %d", this->empty_size);
34
+
35
+ free(this->empty);
36
+ this->empty = NULL;
37
+ this->empty_size = 0;
38
+ free(this->scratch);
39
+ this->scratch = NULL;
40
+ free(this->tmp0);
41
+ this->tmp0 = NULL;
42
+ free(this->tmp1);
43
+ this->tmp1 = NULL;
44
+ for (i = 0; i < MAX_PORTS; i++) {
45
+ this->tmp_datas0i = NULL;
46
+ this->tmp_datas1i = NULL;
47
+ }
48
+}
49
+
50
+static int ensure_tmp(struct impl *this, uint32_t maxsize)
51
+{
52
+ if (maxsize > this->empty_size) {
53
+ float *empty, *scratch, *tmp2;
54
+
55
+ spa_log_debug(this->log, "resize tmp %d -> %d", this->empty_size, maxsize);
56
+
57
+ if ((empty = realloc(this->empty, maxsize + MAX_ALIGN)) != NULL)
58
+ this->empty = empty;
59
+ if ((scratch = realloc(this->scratch, maxsize + MAX_ALIGN)) != NULL)
60
+ this->scratch = scratch;
61
+ if ((tmp0 = realloc(this->tmp0, (maxsize + MAX_ALIGN) * MAX_PORTS)) != NULL)
62
+ this->tmp0 = tmp0;
63
+ if ((tmp1 = realloc(this->tmp1, (maxsize + MAX_ALIGN) * MAX_PORTS)) != NULL)
64
+ this->tmp1 = tmp1;
65
+
66
+ if (empty == NULL || scratch == NULL || tmp0 == NULL || tmp1 == NULL) {
67
+ free_tmp(this);
68
+ return -ENOMEM;
69
+ }
70
+ memset(this->empty, 0, maxsize + MAX_ALIGN);
71
+ this->empty_size = maxsize;
72
+ }
73
+ return 0;
74
+}
75
+
76
static int
77
impl_node_port_use_buffers(void *object,
78
enum spa_direction direction,
79
80
struct impl *this = object;
81
struct port *port;
82
uint32_t i, j, maxsize;
83
+ int res;
84
85
spa_return_val_if_fail(this != NULL, -EINVAL);
86
87
88
if (direction == SPA_DIRECTION_OUTPUT)
89
queue_buffer(this, port, i);
90
}
91
- if (maxsize > this->empty_size) {
92
- this->empty = realloc(this->empty, maxsize + MAX_ALIGN);
93
- this->scratch = realloc(this->scratch, maxsize + MAX_ALIGN);
94
- this->tmp0 = realloc(this->tmp0, (maxsize + MAX_ALIGN) * MAX_PORTS);
95
- this->tmp1 = realloc(this->tmp1, (maxsize + MAX_ALIGN) * MAX_PORTS);
96
- if (this->empty == NULL || this->scratch == NULL ||
97
- this->tmp0 == NULL || this->tmp1 == NULL)
98
- return -errno;
99
- memset(this->empty, 0, maxsize + MAX_ALIGN);
100
- this->empty_size = maxsize;
101
- }
102
+ if ((res = ensure_tmp(this, maxsize)) < 0)
103
+ return res;
104
+
105
port->n_buffers = n_buffers;
106
107
return 0;
108
109
free_dir(&this->dirSPA_DIRECTION_INPUT);
110
free_dir(&this->dirSPA_DIRECTION_OUTPUT);
111
112
- free(this->empty);
113
- free(this->scratch);
114
- free(this->tmp0);
115
- free(this->tmp1);
116
+ free_tmp(this);
117
118
if (this->resample.free)
119
resample_free(&this->resample);
120
pipewire-0.3.80.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.81.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
14
1
2
this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
3
spa_log_topic_init(this->log, log_topic);
4
5
+ this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
6
+ if (this->data_loop == NULL) {
7
+ spa_log_error(this->log, "a data loop is needed");
8
+ return -EINVAL;
9
+ }
10
+
11
this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
12
if (this->cpu) {
13
this->cpu_flags = spa_cpu_get_flags(this->cpu);
14
pipewire-0.3.80.tar.gz/spa/plugins/bluez5/a2dp-codec-opus.c -> pipewire-0.3.81.tar.gz/spa/plugins/bluez5/a2dp-codec-opus.c
Changed
10
1
2
OPUS_05_SET_LOCATION(caps->bidi, props->bidi_location);
3
break;
4
default:
5
- spa_assert(false);
6
+ spa_assert_not_reached();
7
};
8
9
return 0;
10
pipewire-0.3.80.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.81.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
51
1
2
.destroy = sco_destroy_cb,
3
};
4
5
-static struct rfcomm *device_find_rfcomm(struct impl *backend, struct spa_bt_device *device)
6
+static struct rfcomm *device_find_rfcomm(struct impl *backend, struct spa_bt_device *device,
7
+ enum spa_bt_profile profile)
8
{
9
struct rfcomm *rfcomm;
10
spa_list_for_each(rfcomm, &backend->rfcomm_list, link) {
11
- if (rfcomm->device == device)
12
+ if (rfcomm->device == device && (rfcomm->profile & profile))
13
return rfcomm;
14
}
15
return NULL;
16
17
struct impl *backend = data;
18
struct rfcomm *rfcomm;
19
20
- rfcomm = device_find_rfcomm(backend, device);
21
- if (rfcomm == NULL || rfcomm->profile != SPA_BT_PROFILE_HFP_HF)
22
+ rfcomm = device_find_rfcomm(backend, device, SPA_BT_PROFILE_HFP_HF);
23
+ if (rfcomm == NULL)
24
return -ENOTSUP;
25
26
if (codec == HFP_AUDIO_CODEC_CVSD)
27
28
int res;
29
30
res = backend_native_supports_codec(data, device, codec);
31
- if (res <= 0)
32
+ if (res < 0)
33
+ return res;
34
+ else if (!res)
35
return -EINVAL;
36
37
- rfcomm = device_find_rfcomm(backend, device);
38
+ rfcomm = device_find_rfcomm(backend, device, SPA_BT_PROFILE_HFP_HF);
39
if (rfcomm == NULL)
40
return -ENOTSUP;
41
42
43
DBusMessageIter it4;
44
dbus_bool_t autoconnect;
45
dbus_uint16_t version, chan, features;
46
- char *str;
47
+ const char *str;
48
49
if (!(backend->enabled_profiles & spa_bt_profile_from_uuid(uuid)))
50
return -ECANCELED;
51
pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bap-codec-caps.h -> pipewire-0.3.81.tar.gz/spa/plugins/bluez5/bap-codec-caps.h
Changed
40
1
2
};
3
4
struct bap_endpoint_qos {
5
- uint8_t framing;
6
- uint8_t phy;
7
- uint8_t retransmission;
8
- uint16_t latency;
9
- uint32_t delay_min;
10
- uint32_t delay_max;
11
- uint32_t preferred_delay_min;
12
- uint32_t preferred_delay_max;
13
+ uint8_t framing;
14
+ uint8_t phy;
15
+ uint8_t retransmission;
16
+ uint16_t latency;
17
+ uint32_t delay_min;
18
+ uint32_t delay_max;
19
+ uint32_t preferred_delay_min;
20
+ uint32_t preferred_delay_max;
21
+ uint32_t locations;
22
+ uint16_t supported_context;
23
+ uint16_t context;
24
};
25
26
struct bap_codec_qos {
27
28
uint8_t target_latency;
29
};
30
31
+struct bap_codec_qos_full {
32
+ uint8_t cig;
33
+ uint8_t cis;
34
+ uint8_t big;
35
+ uint8_t bis;
36
+ struct bap_codec_qos qos;
37
+};
38
+
39
#endif
40
pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.81.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
606
1
2
static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, const char* key, const char* variant_type_str, const char* array_type_str, int array_type_int, void* data, int data_size);
3
static struct spa_bt_remote_endpoint *remote_endpoint_find(struct spa_bt_monitor *monitor, const char *path);
4
5
+static bool check_iter_signature(DBusMessageIter *it, const char *sig)
6
+{
7
+ char *v;
8
+ bool res;
9
+ v = dbus_message_iter_get_signature(it);
10
+ res = spa_streq(v, sig);
11
+ dbus_free(v);
12
+ return res;
13
+}
14
+
15
+static void parse_codec_qos(struct spa_bt_monitor *monitor, DBusMessageIter *iter, struct bap_codec_qos_full *qos)
16
+{
17
+ DBusMessageIter dict_iter = *iter;
18
+
19
+ memset(qos, 0, sizeof(*qos));
20
+ qos->cig = 0xff;
21
+ qos->cis = 0xff;
22
+ qos->big = 0xff;
23
+ qos->bis = 0xff;
24
+
25
+ if (!check_iter_signature(&dict_iter, "{sv}")) {
26
+ spa_log_warn(monitor->log, "Invalid BAP QoS in DBus");
27
+ return;
28
+ }
29
+
30
+ while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
31
+ DBusMessageIter it2;
32
+ const char *key;
33
+ int type;
34
+
35
+ dbus_message_iter_recurse(&dict_iter, &it0);
36
+ dbus_message_iter_get_basic(&it0, &key);
37
+ dbus_message_iter_next(&it0);
38
+ dbus_message_iter_recurse(&it0, &it1);
39
+
40
+ type = dbus_message_iter_get_arg_type(&it1);
41
+
42
+ if (type == DBUS_TYPE_BYTE) {
43
+ uint8_t value;
44
+
45
+ dbus_message_iter_get_basic(&it1, &value);
46
+ spa_log_debug(monitor->log, "qos: %s=%d", key, (int)value);
47
+
48
+ if (spa_streq(key, "PHY"))
49
+ qos->qos.phy = value;
50
+ else if (spa_streq(key, "Retransmissions"))
51
+ qos->qos.retransmission = value;
52
+ else if (spa_streq(key, "CIG"))
53
+ qos->cig = value;
54
+ else if (spa_streq(key, "CIS"))
55
+ qos->cis = value;
56
+ else if (spa_streq(key, "BIG"))
57
+ qos->big = value;
58
+ else if (spa_streq(key, "BIS"))
59
+ qos->bis = value;
60
+ else if (spa_streq(key, "TargetLatency"))
61
+ qos->qos.target_latency = value;
62
+ else if (spa_streq(key, "Framing"))
63
+ qos->qos.framing = value;
64
+ }
65
+ else if (type == DBUS_TYPE_UINT16) {
66
+ dbus_uint16_t value;
67
+
68
+ dbus_message_iter_get_basic(&it1, &value);
69
+ spa_log_debug(monitor->log, "qos: %s=%d", key, (int)value);
70
+
71
+ if (spa_streq(key, "SDU"))
72
+ qos->qos.sdu = value;
73
+ else if (spa_streq(key, "Latency") || spa_streq(key, "MaximumLatency"))
74
+ qos->qos.latency = value;
75
+ }
76
+ else if (type == DBUS_TYPE_UINT32) {
77
+ dbus_uint32_t value;
78
+
79
+ dbus_message_iter_get_basic(&it1, &value);
80
+ spa_log_debug(monitor->log, "qos: %s=%d", key, (int)value);
81
+
82
+ if (spa_streq(key, "Interval"))
83
+ qos->qos.interval = value;
84
+ else if (spa_streq(key, "PresentationDelay"))
85
+ qos->qos.delay = value;
86
+ }
87
+
88
+ dbus_message_iter_next(&dict_iter);
89
+ }
90
+}
91
+
92
+static void parse_endpoint_qos(struct spa_bt_monitor *monitor, DBusMessageIter *iter,
93
+ struct bap_endpoint_qos *qos)
94
+{
95
+ DBusMessageIter dict_iter = *iter;
96
+
97
+ if (!check_iter_signature(&dict_iter, "{sv}")) {
98
+ spa_log_warn(monitor->log, "Invalid BAP Endpoint QoS in DBus");
99
+ return;
100
+ }
101
+
102
+ while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
103
+ DBusMessageIter it2;
104
+ const char *key;
105
+ int type;
106
+
107
+ dbus_message_iter_recurse(&dict_iter, &it0);
108
+ dbus_message_iter_get_basic(&it0, &key);
109
+ dbus_message_iter_next(&it0);
110
+ dbus_message_iter_recurse(&it0, &it1);
111
+
112
+ type = dbus_message_iter_get_arg_type(&it1);
113
+
114
+ if (type == DBUS_TYPE_BYTE) {
115
+ uint8_t value;
116
+
117
+ dbus_message_iter_get_basic(&it1, &value);
118
+ spa_log_debug(monitor->log, "ep qos: %s=%d", key, (int)value);
119
+
120
+ if (spa_streq(key, "Framing"))
121
+ qos->framing = value;
122
+ else if (spa_streq(key, "PHY"))
123
+ qos->phy = value;
124
+ else if (spa_streq(key, "Retransmissions"))
125
+ qos->retransmission = value;
126
+ } else if (type == DBUS_TYPE_UINT16) {
127
+ dbus_uint16_t value;
128
+
129
+ dbus_message_iter_get_basic(&it1, &value);
130
+ spa_log_debug(monitor->log, "ep qos: %s=%d", key, (int)value);
131
+
132
+ if (spa_streq(key, "Latency") || spa_streq(key, "MaximumLatency"))
133
+ qos->latency = value;
134
+ else if (spa_streq(key, "Context"))
135
+ qos->context = value;
136
+ else if (spa_streq(key, "SupportedContext"))
137
+ qos->supported_context = value;
138
+ } else if (type == DBUS_TYPE_UINT32) {
139
+ dbus_uint32_t value;
140
+
141
+ dbus_message_iter_get_basic(&it1, &value);
142
+ spa_log_debug(monitor->log, "ep qos: %s=%d", key, (int)value);
143
+
144
+ if (spa_streq(key, "MinimumDelay"))
145
+ qos->delay_min = value;
146
+ else if (spa_streq(key, "MaximumDelay"))
147
+ qos->delay_max = value;
148
+ else if (spa_streq(key, "PreferredMinimumDelay"))
149
+ qos->preferred_delay_min = value;
150
+ else if (spa_streq(key, "PreferredMaximumDelay"))
151
+ qos->preferred_delay_max = value;
152
+ else if (spa_streq(key, "Locations") || spa_streq(key, "Location"))
153
+ qos->locations = value;
154
+ }
155
+
156
+ dbus_message_iter_next(&dict_iter);
157
+ }
158
+}
159
+
160
+static int parse_endpoint_props(struct spa_bt_monitor *monitor, DBusMessageIter *iter,
161
+ uint8_t capsA2DP_MAX_CAPS_SIZE, int *caps_size, const char **endpoint_path,
162
+ struct bap_endpoint_qos *qos)
163
+{
164
+ DBusMessageIter dict_iter = *iter;
165
+ const char *key = NULL;
166
+ int type = 0;
167
+
168
+ memset(caps, 0, A2DP_MAX_CAPS_SIZE);
169
+ *endpoint_path = NULL;
170
+ memset(qos, 0, sizeof(*qos));
171
+
172
+ if (!check_iter_signature(&dict_iter, "{sv}")) {
173
+ spa_log_warn(monitor->log, "Invalid BAP Endpoint QoS in DBus");
174
+ return -EINVAL;
175
+ }
176
+
177
+ while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
178
+ DBusMessageIter it3;
179
+
180
+ dbus_message_iter_recurse(&dict_iter, &it0);
181
+ dbus_message_iter_get_basic(&it0, &key);
182
+ dbus_message_iter_next(&it0);
183
+ dbus_message_iter_recurse(&it0, &it1);
184
+
185
+ type = dbus_message_iter_get_arg_type(&it1);
186
+
187
+ if (spa_streq(key, "Capabilities")) {
188
+ uint8_t *buf;
189
+
190
+ if (type != DBUS_TYPE_ARRAY)
191
+ goto bad_property;
192
+
193
+ dbus_message_iter_recurse(&it1, &it2);
194
+ type = dbus_message_iter_get_arg_type(&it2);
195
+ if (type != DBUS_TYPE_BYTE)
196
+ goto bad_property;
197
+
198
+ dbus_message_iter_get_fixed_array(&it2, &buf, caps_size);
199
+ if (*caps_size > A2DP_MAX_CAPS_SIZE) {
200
+ spa_log_error(monitor->log, "%s size:%d too large", key, (int)*caps_size);
201
+ return -EINVAL;
202
+ }
203
+ memcpy(caps, buf, *caps_size);
204
+
205
+ spa_log_info(monitor->log, "%p: %s size:%d", monitor, key, *caps_size);
206
+ spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', caps, (size_t)*caps_size);
207
+ } else if (spa_streq(key, "Endpoint")) {
208
+ if (type != DBUS_TYPE_OBJECT_PATH)
209
+ goto bad_property;
210
+
211
+ dbus_message_iter_get_basic(&it1, endpoint_path);
212
+
213
+ spa_log_info(monitor->log, "%p: %s %s", monitor, key, *endpoint_path);
214
+ } else if (spa_streq(key, "QoS")) {
215
+ if (!check_iter_signature(&it1, "a{sv}"))
216
+ goto bad_property;
217
+
218
+ dbus_message_iter_recurse(&it1, &it2);
219
+ parse_endpoint_qos(monitor, &it2, qos);
220
+ } else if (spa_streq(key, "Locations")) {
221
+ dbus_uint32_t value;
222
+
223
+ if (type != DBUS_TYPE_UINT32)
224
+ goto bad_property;
225
+
226
+ dbus_message_iter_get_basic(&it1, &value);
227
+ spa_log_debug(monitor->log, "ep qos: %s=%d", key, (int)value);
228
+ qos->locations = value;
229
+ }
230
+
231
+ dbus_message_iter_next(&dict_iter);
232
+ }
233
+
234
+ return 0;
235
+
236
+bad_property:
237
+ spa_log_error(monitor->log, "Property %s of wrong type %c", key, (char)type);
238
+ return -EINVAL;
239
+}
240
+
241
static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMessage *m, void *userdata)
242
{
243
struct spa_bt_monitor *monitor = userdata;
244
245
spa_autoptr(DBusMessage) r = NULL;
246
int res;
247
const struct media_codec *codec;
248
+ struct spa_bt_remote_endpoint *ep;
249
bool sink;
250
const char *err_msg = "Unknown error";
251
struct spa_dict settings;
252
253
*/
254
codec = media_endpoint_to_codec(monitor, path, &sink, NULL);
255
spa_log_debug(monitor->log, "%p: %s codec:%s", monitor, path, codec ? codec->name : "<null>");
256
- if (!codec) {
257
+ if (!codec || !codec->bap || !codec->get_qos) {
258
spa_log_error(monitor->log, "Unsupported codec");
259
err_msg = "Unsupported codec";
260
goto error;
261
}
262
263
- /* Parse transport properties */
264
- while (dbus_message_iter_get_arg_type(&props) == DBUS_TYPE_DICT_ENTRY) {
265
- const char *key;
266
- DBusMessageIter value, entry;
267
- int type;
268
-
269
- dbus_message_iter_recurse(&props, &entry);
270
- dbus_message_iter_get_basic(&entry, &key);
271
-
272
- dbus_message_iter_next(&entry);
273
- dbus_message_iter_recurse(&entry, &value);
274
-
275
- type = dbus_message_iter_get_arg_type(&value);
276
-
277
- if (spa_streq(key, "Capabilities")) {
278
- DBusMessageIter array;
279
- uint8_t *buf;
280
-
281
- if (type != DBUS_TYPE_ARRAY) {
282
- spa_log_error(monitor->log, "Property %s of wrong type %c", key, (char)type);
283
- goto error_invalid;
284
- }
285
-
286
- dbus_message_iter_recurse(&value, &array);
287
- type = dbus_message_iter_get_arg_type(&array);
288
- if (type != DBUS_TYPE_BYTE) {
289
- spa_log_error(monitor->log, "%s is an array of wrong type %c", key, (char)type);
290
- goto error_invalid;
291
- }
292
-
293
- dbus_message_iter_get_fixed_array(&array, &buf, &caps_size);
294
- if (caps_size > (int)sizeof(caps)) {
295
- spa_log_error(monitor->log, "%s size:%d too large", key, (int)caps_size);
296
- goto error_invalid;
297
- }
298
- memcpy(caps, buf, caps_size);
299
-
300
- spa_log_info(monitor->log, "%p: %s %s size:%d", monitor, path, key, caps_size);
301
- spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', caps, (size_t)caps_size);
302
- } else if (spa_streq(key, "Endpoint")) {
303
- if (type != DBUS_TYPE_OBJECT_PATH) {
304
- spa_log_error(monitor->log, "Property %s of wrong type %c", key, (char)type);
305
- goto error_invalid;
306
- }
307
-
308
- dbus_message_iter_get_basic(&value, &endpoint_path);
309
-
310
- spa_log_info(monitor->log, "%p: %s %s %s", monitor, path, key, endpoint_path);
311
- } else if (type == DBUS_TYPE_BYTE) {
312
- uint8_t v;
313
- dbus_message_iter_get_basic(&value, &v);
314
-
315
- spa_log_info(monitor->log, "%p: %s %s 0x%x", monitor, path, key, (unsigned int)v);
316
-
317
- if (spa_streq(key, "Framing"))
318
- endpoint_qos.framing = v;
319
- else if (spa_streq(key, "PHY"))
320
- endpoint_qos.phy = v;
321
- else
322
- spa_log_info(monitor->log, "Unknown property %s", key);
323
- } else if (type == DBUS_TYPE_UINT16) {
324
- dbus_uint16_t v;
325
- dbus_message_iter_get_basic(&value, &v);
326
-
327
- spa_log_info(monitor->log, "%p: %s %s 0x%x", monitor, path, key, (unsigned int)v);
328
-
329
- if (spa_streq(key, "Latency"))
330
- endpoint_qos.latency = v;
331
- else
332
- spa_log_info(monitor->log, "Unknown property %s", key);
333
- } else if (type == DBUS_TYPE_UINT32) {
334
- dbus_uint32_t v;
335
- dbus_message_iter_get_basic(&value, &v);
336
-
337
- spa_log_info(monitor->log, "%p: %s %s 0x%x", monitor, path, key, (unsigned int)v);
338
-
339
- if (spa_streq(key, "MinimumDelay"))
340
- endpoint_qos.delay_min = v;
341
- else if (spa_streq(key, "MaximumDelay"))
342
- endpoint_qos.delay_max = v;
343
- else if (spa_streq(key, "PreferredMinimumDelay"))
344
- endpoint_qos.preferred_delay_min = v;
345
- else if (spa_streq(key, "PreferredMaximumDelay"))
346
- endpoint_qos.preferred_delay_max = v;
347
- else if (spa_streq(key, "Location"))
348
- spa_scnprintf(locations, sizeof(locations), "%"PRIu32, v);
349
- else
350
- spa_log_info(monitor->log, "Unknown property %s", key);
351
- } else {
352
- spa_log_info(monitor->log, "Unknown property %s", key);
353
- }
354
+ /* Parse endpoint properties */
355
+ if (parse_endpoint_props(monitor, &props, caps, &caps_size, &endpoint_path, &endpoint_qos) < 0)
356
+ goto error_invalid;
357
+ if (endpoint_qos.locations)
358
+ spa_scnprintf(locations, sizeof(locations), "%"PRIu32, endpoint_qos.locations);
359
360
- dbus_message_iter_next(&props);
361
+ ep = remote_endpoint_find(monitor, endpoint_path);
362
+ if (!ep) {
363
+ spa_log_warn(monitor->log, "Unable to find remote endpoint for %s", endpoint_path);
364
+ goto error_invalid;
365
}
366
367
- if (codec->bap) {
368
- struct spa_bt_remote_endpoint *ep;
369
-
370
- ep = remote_endpoint_find(monitor, endpoint_path);
371
- if (!ep) {
372
- spa_log_warn(monitor->log, "Unable to find remote endpoint for %s", endpoint_path);
373
- goto error_invalid;
374
- }
375
-
376
- /* Call of SelectProperties means that local device acts as an initiator
377
- * and therefor remote endpoint is an acceptor
378
- */
379
- ep->acceptor = true;
380
- }
381
+ /* Call of SelectProperties means that local device acts as an initiator
382
+ * and therefor remote endpoint is an acceptor
383
+ */
384
+ ep->acceptor = true;
385
386
for (i = 0; i < (int)monitor->global_settings.n_items; ++i)
387
setting_itemsi = monitor->global_settings.itemsi;
388
389
&dict);
390
append_basic_array_variant_dict_entry(&dict, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, &config, conf_size);
391
392
- if (codec->get_qos) {
393
+ {
394
struct bap_codec_qos qos;
395
- dbus_bool_t framing;
396
- const char *phy_str;
397
+ DBusMessageIter entry, variant, qos_dict;
398
+ const char *entry_key = "QoS";
399
400
spa_zero(qos);
401
402
403
goto error_invalid;
404
}
405
406
- append_basic_variant_dict_entry(&dict, "Interval", DBUS_TYPE_UINT32, "u", &qos.interval);
407
- framing = (qos.framing ? TRUE : FALSE);
408
- append_basic_variant_dict_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN, "b", &framing);
409
- if (qos.phy == 0x1)
410
- phy_str = "1M";
411
- else if (qos.phy == 0x2)
412
- phy_str = "2M";
413
- else
414
- spa_assert_not_reached();
415
- append_basic_variant_dict_entry(&dict, "PHY", DBUS_TYPE_STRING, "s", &phy_str);
416
- append_basic_variant_dict_entry(&dict, "SDU", DBUS_TYPE_UINT16, "q", &qos.sdu);
417
- append_basic_variant_dict_entry(&dict, "Retransmissions", DBUS_TYPE_BYTE, "y", &qos.retransmission);
418
- append_basic_variant_dict_entry(&dict, "Latency", DBUS_TYPE_UINT16, "q", &qos.latency);
419
- append_basic_variant_dict_entry(&dict, "Delay", DBUS_TYPE_UINT32, "u", &qos.delay);
420
- append_basic_variant_dict_entry(&dict, "TargetLatency", DBUS_TYPE_BYTE, "y", &qos.target_latency);
421
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
422
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &entry_key);
423
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}", &variant);
424
+
425
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
426
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
427
+ DBUS_TYPE_STRING_AS_STRING
428
+ DBUS_TYPE_VARIANT_AS_STRING
429
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
430
+ &qos_dict);
431
+
432
+ append_basic_variant_dict_entry(&qos_dict, "Interval", DBUS_TYPE_UINT32, "u", &qos.interval);
433
+ append_basic_variant_dict_entry(&qos_dict, "Framing", DBUS_TYPE_BYTE, "y", &qos.framing);
434
+ append_basic_variant_dict_entry(&qos_dict, "PHY", DBUS_TYPE_BYTE, "y", &qos.phy);
435
+ append_basic_variant_dict_entry(&qos_dict, "SDU", DBUS_TYPE_UINT16, "q", &qos.sdu);
436
+ append_basic_variant_dict_entry(&qos_dict, "Retransmissions", DBUS_TYPE_BYTE, "y", &qos.retransmission);
437
+ append_basic_variant_dict_entry(&qos_dict, "Latency", DBUS_TYPE_UINT16, "q", &qos.latency);
438
+ append_basic_variant_dict_entry(&qos_dict, "PresentationDelay", DBUS_TYPE_UINT32, "u", &qos.delay);
439
+ append_basic_variant_dict_entry(&qos_dict, "TargetLatency", DBUS_TYPE_BYTE, "y", &qos.target_latency);
440
+
441
+ dbus_message_iter_close_container(&variant, &qos_dict);
442
+ dbus_message_iter_close_container(&entry, &variant);
443
+ dbus_message_iter_close_container(&dict, &entry);
444
}
445
446
dbus_message_iter_close_container(&iter, &dict);
447
448
return NULL;
449
}
450
451
-static bool check_iter_signature(DBusMessageIter *it, const char *sig)
452
-{
453
- char *v;
454
- bool res;
455
- v = dbus_message_iter_get_signature(it);
456
- res = spa_streq(v, sig);
457
- dbus_free(v);
458
- return res;
459
-}
460
-
461
static int parse_modalias(const char *modalias, uint16_t *source, uint16_t *vendor,
462
uint16_t *product, uint16_t *version)
463
{
464
465
int spa_bt_format_vendor_product_id(uint16_t source_id, uint16_t vendor_id, uint16_t product_id,
466
char *vendor_str, int vendor_str_size, char *product_str, int product_str_size)
467
{
468
- char *source_str;
469
+ const char *source_str;
470
471
switch (source_id) {
472
case SOURCE_ID_USB:
473
474
spa_bt_transport_volume_changed(transport);
475
}
476
else if (spa_streq(key, "Delay")) {
477
- if (transport->profile & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) {
478
- uint32_t value;
479
-
480
- if (type != DBUS_TYPE_UINT32)
481
- goto next;
482
- dbus_message_iter_get_basic(&it1, &value);
483
-
484
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
485
-
486
- transport->delay_us = value;
487
- } else {
488
- uint16_t value;
489
+ uint16_t value;
490
491
- if (type != DBUS_TYPE_UINT16)
492
- goto next;
493
- dbus_message_iter_get_basic(&it1, &value);
494
+ if (type != DBUS_TYPE_UINT16)
495
+ goto next;
496
+ dbus_message_iter_get_basic(&it1, &value);
497
498
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
499
+ spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
500
501
- transport->delay_us = value * 100;
502
- }
503
+ transport->delay_us = value * 100;
504
505
spa_bt_transport_emit_delay_changed(transport);
506
}
507
- else if (spa_streq(key, "Latency")) {
508
- uint16_t value;
509
+ else if (spa_streq(key, "QoS")) {
510
+ struct bap_codec_qos_full qos;
511
+ DBusMessageIter value;
512
513
- if (type != DBUS_TYPE_UINT16)
514
+ if (!check_iter_signature(&it1, "a{sv}"))
515
goto next;
516
- dbus_message_iter_get_basic(&it1, &value);
517
518
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
519
+ dbus_message_iter_recurse(&it1, &value);
520
+ parse_codec_qos(monitor, &value, &qos);
521
+
522
+ transport->bap_cig = qos.cig;
523
+ transport->bap_cis = qos.cis;
524
+ transport->bap_big = qos.big;
525
+ transport->bap_bis = qos.bis;
526
+ transport->delay_us = qos.qos.delay;
527
+ transport->latency_us = (unsigned int)qos.qos.latency * 1000;
528
+ transport->bap_interval = qos.qos.interval;
529
530
- transport->latency_us = value * 1000;
531
spa_bt_transport_emit_delay_changed(transport);
532
}
533
else if (spa_streq(key, "Links")) {
534
535
dbus_message_iter_next(&iter);
536
}
537
}
538
- else if (spa_streq(key, "Interval")) {
539
- uint32_t value;
540
-
541
- if (type != DBUS_TYPE_UINT32)
542
- goto next;
543
- dbus_message_iter_get_basic(&it1, &value);
544
-
545
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
546
- transport->bap_interval = value;
547
- }
548
- else if (spa_streq(key, "Framing")) {
549
- dbus_bool_t value;
550
-
551
- if (type != DBUS_TYPE_BOOLEAN)
552
- goto next;
553
- dbus_message_iter_get_basic(&it1, &value);
554
-
555
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
556
- }
557
- else if (spa_streq(key, "SDU")) {
558
- uint16_t value;
559
-
560
- if (type != DBUS_TYPE_UINT16)
561
- goto next;
562
- dbus_message_iter_get_basic(&it1, &value);
563
-
564
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
565
- }
566
- else if (spa_streq(key, "Retransmissions")) {
567
- uint8_t value;
568
-
569
- if (type != DBUS_TYPE_BYTE)
570
- goto next;
571
- dbus_message_iter_get_basic(&it1, &value);
572
-
573
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
574
- }
575
- else if (spa_streq(key, "CIG") || spa_streq(key, "CIS")) {
576
- uint8_t value;
577
578
- if (type != DBUS_TYPE_BYTE)
579
- goto next;
580
- dbus_message_iter_get_basic(&it1, &value);
581
-
582
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
583
-
584
- if (spa_streq(key, "CIG"))
585
- transport->bap_cig = value;
586
- else
587
- transport->bap_cis = value;
588
- }
589
- else if (spa_streq(key, "BIG") || spa_streq(key, "BIS")) {
590
- uint8_t value;
591
-
592
- if (type != DBUS_TYPE_BYTE)
593
- goto next;
594
- dbus_message_iter_get_basic(&it1, &value);
595
-
596
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
597
-
598
- if (spa_streq(key, "BIG"))
599
- transport->bap_big = value;
600
- else
601
- transport->bap_bis = value;
602
- }
603
next:
604
dbus_message_iter_next(props_iter);
605
}
606
pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.81.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
20
1
2
name = "audio-gateway";
3
desc = _("Audio Gateway (A2DP Source & HSP/HFP AG)");
4
}
5
- priority = 256;
6
+
7
+ /*
8
+ * If the remote is A2DP sink and HF, we likely should prioritize being
9
+ * A2DP sender, not gateway. This can occur in PW<->PW if RFCOMM gets
10
+ * connected both as AG and HF.
11
+ */
12
+ if ((device->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) &&
13
+ (device->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT))
14
+ priority = 15;
15
+ else
16
+ priority = 256;
17
break;
18
}
19
case DEVICE_PROFILE_A2DP:
20
pipewire-0.3.80.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.81.tar.gz/spa/plugins/support/loop.c
Changed
55
1
2
#include <spa/support/plugin.h>
3
#include <spa/utils/list.h>
4
#include <spa/utils/names.h>
5
+#include <spa/utils/ratelimit.h>
6
#include <spa/utils/result.h>
7
#include <spa/utils/type.h>
8
#include <spa/utils/ringbuffer.h>
9
10
11
struct spa_source *wakeup;
12
int ack_fd;
13
+ struct spa_ratelimit rate_limit;
14
15
struct spa_ringbuffer buffer;
16
uint8_t *buffer_data;
17
18
};
19
/** \endcond */
20
21
+static inline uint64_t get_time_ns(struct spa_system *system)
22
+{
23
+ struct timespec ts;
24
+ spa_system_clock_gettime(system, CLOCK_MONOTONIC, &ts);
25
+ return SPA_TIMESPEC_TO_NSEC(&ts);
26
+}
27
+
28
static int loop_add_source(void *object, struct spa_source *source)
29
{
30
struct impl *impl = object;
31
32
item->item_size = SPA_ROUND_UP_N(l0 + size, ITEM_ALIGN);
33
}
34
if (avail < item->item_size) {
35
- spa_log_warn(impl->log, "%p: queue full %d, need %zd", impl, avail,
36
- item->item_size);
37
+ int suppressed;
38
+ uint64_t nsec = get_time_ns(impl->system);
39
+ if ((suppressed = spa_ratelimit_test(&impl->rate_limit, nsec)) >= 0) {
40
+ spa_log_warn(impl->log, "%p: queue full %d, need %zd (%d suppressed)",
41
+ impl, avail, item->item_size, suppressed);
42
+ }
43
return -EPIPE;
44
}
45
if (data && size > 0)
46
47
res = -EINVAL;
48
goto error_exit;
49
}
50
+ impl->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
51
+ impl->rate_limit.burst = 1;
52
53
if ((res = spa_system_pollfd_create(impl->system, SPA_FD_CLOEXEC)) < 0) {
54
spa_log_error(impl->log, "%p: can't create pollfd: %s",
55
pipewire-0.3.80.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.81.tar.gz/spa/plugins/support/node-driver.c
Changed
22
1
2
#ifdef CLOCK_MONOTONIC_RAW
3
{ "monotonic-raw", CLOCK_MONOTONIC_RAW },
4
#endif
5
+#ifdef CLOCK_BOOTTIME
6
{ "boottime", CLOCK_BOOTTIME },
7
+#endif
8
};
9
10
static bool clock_for_timerfd(clockid_t id)
11
{
12
return id == CLOCK_REALTIME ||
13
- id == CLOCK_MONOTONIC ||
14
- id == CLOCK_BOOTTIME;
15
+#ifdef CLOCK_BOOTTIME
16
+ id == CLOCK_BOOTTIME ||
17
+#endif
18
+ id == CLOCK_MONOTONIC;
19
}
20
21
static clockid_t clock_name_to_id(const char *name)
22
pipewire-0.3.80.tar.gz/spa/tests/stress-ringbuffer.c -> pipewire-0.3.81.tar.gz/spa/tests/stress-ringbuffer.c
Changed
15
1
2
#define ARRAY_SIZE 63
3
#define MAX_VALUE 0x10000
4
5
-#if defined(__FreeBSD__) || defined(__MidnightBSD__)
6
+#if defined(__FreeBSD__) || defined(__MidnightBSD__) || defined (__GNU__)
7
#include <sys/param.h>
8
#if (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400043) \
9
- || (__FreeBSD_version < 1300523) || defined(__MidnightBSD__)
10
+ || (__FreeBSD_version < 1300523) || defined(__MidnightBSD__) \
11
+ || defined (__GNU__)
12
static int sched_getcpu(void) { return -1; };
13
#endif
14
#endif
15
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/demonic.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/demonic.conf
Changed
13
1
2
# ~/.config/pipewire/filter-chain.conf.d/
3
#
4
context.modules =
5
- { name = libpipewire-module-filter-chain
6
- args = {
7
+ { name = libpipewire-module-filter-chain
8
+ flags = nofail
9
+ args = {
10
#audio.format = F32
11
#audio.rate = 48000
12
audio.channels = 2
13
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf
Changed
9
1
2
#
3
context.modules =
4
{ name = libpipewire-module-filter-chain
5
+ flags = nofail
6
args = {
7
node.description = "Dolby Surround Sink"
8
media.name = "Dolby Surround Sink"
9
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf
Changed
9
1
2
3
context.modules =
4
{ name = libpipewire-module-filter-chain
5
+ flags = nofail
6
args = {
7
node.description = "Matrix Spatialiser"
8
media.name = "Matrix Spatialiser"
9
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf
Changed
13
1
2
# Copy this file into a conf.d/ directory such as
3
# ~/.config/pipewire/filter-chain.conf.d/
4
#
5
+# Adjust the paths to the convolver files to match your system
6
+#
7
context.modules =
8
{ name = libpipewire-module-filter-chain
9
+ flags = nofail
10
args = {
11
node.description = "Virtual Surround Sink"
12
media.name = "Virtual Surround Sink"
13
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf
Changed
13
1
2
# Copy this file into a conf.d/ directory such as
3
# ~/.config/pipewire/filter-chain.conf.d/
4
#
5
+# Adjust the paths to the convolver files to match your system
6
+#
7
context.modules =
8
{ name = libpipewire-module-filter-chain
9
+ flags = nofail
10
args = {
11
node.description = "Virtual Surround Sink"
12
media.name = "Virtual Surround Sink"
13
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/source-rnnoise.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/source-rnnoise.conf
Changed
28
1
2
# Copy this file into a conf.d/ directory such as
3
# ~/.config/pipewire/filter-chain.conf.d/
4
#
5
+# Adjust the paths to the rnnoise plugin to match your system
6
+#
7
context.modules =
8
{ name = libpipewire-module-filter-chain
9
+ flags = nofail
10
args = {
11
node.description = "Noise Canceling source"
12
media.name = "Noise Canceling source"
13
14
{
15
type = ladspa
16
name = rnnoise
17
- plugin = librnnoise_ladspa
18
+ # The path to the plugin. The suffix .so is appended to
19
+ # this string and then the file is then located in the directories
20
+ # listed in the environment variable LADSPA_PATH or
21
+ # /usr/lib64/ladspa, /usr/lib/ladspa or the system library directory
22
+ # as a fallback.
23
+ # You might want to use an absolute path here to avoid problems.
24
+ plugin = "librnnoise_ladspa"
25
label = noise_suppressor_stereo
26
control = {
27
"VAD Threshold (%)" 50.0
28
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/spatializer-7.1.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/spatializer-7.1.conf
Changed
13
1
2
# Copy this file into a conf.d/ directory such as
3
# ~/.config/pipewire/filter-chain.conf.d/
4
#
5
+# Adjust the paths to the sofa file to match your system.
6
+#
7
context.modules =
8
{ name = libpipewire-module-filter-chain
9
+ flags = nofail
10
args = {
11
node.description = "Spatial Sink"
12
media.name = "Spatial Sink"
13
pipewire-0.3.80.tar.gz/src/daemon/filter-chain/spatializer-single.conf -> pipewire-0.3.81.tar.gz/src/daemon/filter-chain/spatializer-single.conf
Changed
13
1
2
# Copy this file into a conf.d/ directory such as
3
# ~/.config/pipewire/filter-chain.conf.d/
4
#
5
+# Adjust the paths to the sofa files to match your system
6
+#
7
context.modules =
8
{ name = libpipewire-module-filter-chain
9
+ flags = nofail
10
args = {
11
node.description = "3D Sink"
12
media.name = "3D Sink"
13
pipewire-0.3.80.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.81.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
9
1
2
args = {
3
nice.level = -11
4
#rt.prio = 88
5
+ rt.prio = 65
6
#rt.time.soft = -1
7
#rt.time.hard = -1
8
}
9
pipewire-0.3.80.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.81.tar.gz/src/daemon/pipewire.conf.in
Changed
40
1
2
# enables autoloading of access module, when disabled an alternative
3
# access module needs to be loaded.
4
module.access = true
5
+ # enables autoloading of module-jackdbus-detect
6
+ module.jackdbus-detect = true
7
}
8
9
context.spa-libs = {
10
11
flags = ifexists nofail
12
condition = { module.x11.bell = true }
13
}
14
+ { name = libpipewire-module-jackdbus-detect
15
+ args {
16
+ #jack.library = libjack.so.0
17
+ #jack.server = null
18
+ #jack.client-name = PipeWire
19
+ #jack.connect = true
20
+ #tunnel.mode = duplex # source|sink|duplex
21
+ source.props = {
22
+ #audio.channels = 2
23
+ #midi.ports = 1
24
+ #audio.position = FL FR
25
+ # extra sink properties
26
+ }
27
+ sink.props = {
28
+ #audio.channels = 2
29
+ #midi.ports = 1
30
+ #audio.position = FL FR
31
+ # extra sink properties
32
+ }
33
+ }
34
+ flags = ifexists nofail
35
+ condition = { module.jackdbus-detect = true }
36
+ }
37
38
39
context.objects =
40
pipewire-0.3.80.tar.gz/src/modules/module-access.c -> pipewire-0.3.81.tar.gz/src/modules/module-access.c
Changed
10
1
2
* (in the current namespace).
3
*/
4
5
-#if defined(__linux__)
6
+#if defined(__linux__) || defined(__GNU__)
7
spa_scnprintf(path, sizeof(path), "/proc/%u/exe", pid);
8
#elif defined(__FreeBSD__) || defined(__MidnightBSD__)
9
spa_scnprintf(path, sizeof(path), "/proc/%u/file", pid);
10
pipewire-0.3.80.tar.gz/src/modules/module-ffado-driver.c -> pipewire-0.3.81.tar.gz/src/modules/module-ffado-driver.c
Changed
37
1
2
* ## Module Options
3
*
4
* - `driver.mode`: the driver mode, sink|source|duplex, default duplex
5
- * - `ffado.devices`: array of devices to open, default hw:0
6
+ * - `ffado.devices`: array of devices to open, default "hw:0"
7
* - `ffado.period-size`: period size,default 1024
8
* - `ffado.period-num`: period number,default 3
9
* - `ffado.sample-rate`: sample-rate, default 48000
10
11
* { name = libpipewire-module-ffado-driver
12
* args = {
13
* #driver.mode = duplex
14
- * #ffado.devices = hw:0
15
+ * #ffado.devices = "hw:0"
16
* #ffado.period-size = 1024
17
* #ffado.period-num = 3
18
* #ffado.sample-rate = 48000
19
20
21
#define MAX_PORTS 128
22
23
-#define DEFAULT_DEVICES " hw:0 "
24
+#define DEFAULT_DEVICES " \"hw:0\" "
25
#define DEFAULT_PERIOD_SIZE 1024
26
#define DEFAULT_PERIOD_NUM 3
27
#define DEFAULT_SAMPLE_RATE 48000
28
29
30
#define MODULE_USAGE "( remote.name=<remote> ) " \
31
"( driver.mode=<sink|source|duplex> ) " \
32
- "( ffado.devices=<devices array size, default hw:0> ) " \
33
+ "( ffado.devices=<devices array size, default \"hw:0\"> ) " \
34
"( ffado.period-size=<period size, default 1024> ) " \
35
"( ffado.period-num=<period num, default 3> ) " \
36
"( ffado.sample-rate=<sampe rate, default 48000> ) " \
37
pipewire-0.3.80.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.81.tar.gz/src/modules/module-filter-chain.c
Changed
530
1
2
*
3
* inputs = <portname> ...
4
* outputs = <portname> ...
5
+ * capture.volumes =
6
+ * { control = <portname> min = <value> max = <value> scale = <scale> } ...
7
+ *
8
+ * playback.volumes =
9
+ * { control = <portname> min = <value> max = <value> scale = <scale> } ...
10
+ *
11
* }
12
*\endcode
13
*
14
15
* graph will then be duplicated as many times to match the number of input/output
16
* channels of the streams.
17
*
18
+ * ### Volumes
19
+ *
20
+ * Normally the volume of the sink/source is handled by the stream software volume.
21
+ * With the capture.volumes and playback.volumes properties this can be handled
22
+ * by a control port in the graph instead.
23
+ *
24
+ * The min and max values (defaults 0.0 and 1.0) respectively can be used to scale
25
+ * and translate the volume min and max values.
26
+ *
27
+ * Normally the control values are linear and it is assumed that the plugin does not
28
+ * perform any scaling to the values. This can be changed with the scale property. By
29
+ * default this is linear but it can be set to cubic when the control applies a
30
+ * cubic transformation.
31
+ *
32
* ## Builtin filters
33
*
34
* There are some useful builtin filters available. You select them with the label
35
36
uint32_t n_links;
37
uint32_t external;
38
39
- float control_data;
40
+ float control_dataMAX_HNDL;
41
float *audio_dataMAX_HNDL;
42
};
43
44
45
void **hndl;
46
};
47
48
+struct volume {
49
+ bool mute;
50
+ uint32_t n_volumes;
51
+ float volumesSPA_AUDIO_MAX_CHANNELS;
52
+
53
+ uint32_t n_ports;
54
+ struct port *portsSPA_AUDIO_MAX_CHANNELS;
55
+ float minSPA_AUDIO_MAX_CHANNELS;
56
+ float maxSPA_AUDIO_MAX_CHANNELS;
57
+#define SCALE_LINEAR 0
58
+#define SCALE_CUBIC 1
59
+ int scaleSPA_AUDIO_MAX_CHANNELS;
60
+};
61
+
62
struct graph {
63
struct impl *impl;
64
65
66
uint32_t n_control;
67
struct port **control_port;
68
69
+ struct volume capture_volume;
70
+ struct volume playback_volume;
71
+
72
unsigned instantiated:1;
73
};
74
75
76
77
spa_pod_builder_string(b, name);
78
if (p->hint & FC_HINT_BOOLEAN) {
79
- spa_pod_builder_bool(b, port->control_data <= 0.0f ? false : true);
80
+ spa_pod_builder_bool(b, port->control_data0 <= 0.0f ? false : true);
81
} else if (p->hint & FC_HINT_INTEGER) {
82
- spa_pod_builder_int(b, port->control_data);
83
+ spa_pod_builder_int(b, port->control_data0);
84
} else {
85
- spa_pod_builder_float(b, port->control_data);
86
+ spa_pod_builder_float(b, port->control_data0);
87
}
88
}
89
spa_pod_builder_pop(b, &f1);
90
return spa_pod_builder_pop(b, &f0);
91
}
92
93
+static int port_set_control_value(struct port *port, float *value, uint32_t id)
94
+{
95
+ struct node *node = port->node;
96
+ struct descriptor *desc = node->desc;
97
+ float old;
98
+
99
+ old = port->control_dataid;
100
+ port->control_dataid = value ? *value : desc->default_controlport->idx;
101
+ pw_log_info("control %d %d ('%s') from %f to %f", port->idx, id,
102
+ desc->desc->portsport->p.name, old, port->control_dataid);
103
+ node->control_changed = old != port->control_dataid;
104
+ return node->control_changed ? 1 : 0;
105
+}
106
+
107
static int set_control_value(struct node *node, const char *name, float *value)
108
{
109
- struct descriptor *desc;
110
struct port *port;
111
- float old;
112
+ int count = 0;
113
+ uint32_t i, n_hndl;
114
115
port = find_port(node, name, FC_PORT_INPUT | FC_PORT_CONTROL);
116
if (port == NULL)
117
return -ENOENT;
118
119
- node = port->node;
120
- desc = node->desc;
121
+ /* if we don't have any instances yet, set the first control value, we will
122
+ * copy to other instances later */
123
+ n_hndl = SPA_MAX(1u, port->node->n_hndl);
124
+ for (i = 0; i < n_hndl; i++)
125
+ count += port_set_control_value(port, value, i);
126
127
- old = port->control_data;
128
- port->control_data = value ? *value : desc->default_controlport->idx;
129
- pw_log_info("control %d ('%s') from %f to %f", port->idx, name, old, port->control_data);
130
- node->control_changed = old != port->control_data;
131
- return node->control_changed ? 1 : 0;
132
+ return count;
133
}
134
135
static int parse_params(struct graph *graph, const struct spa_pod *pod)
136
137
spa_pod_dynamic_builder_clean(&b);
138
}
139
140
-static void param_props_changed(struct impl *impl, const struct spa_pod *param)
141
+static int sync_volume(struct graph *graph, struct volume *vol)
142
+{
143
+ uint32_t i;
144
+ int res = 0;
145
+
146
+ if (vol->n_ports == 0)
147
+ return 0;
148
+ for (i = 0; i < vol->n_volumes; i++) {
149
+ uint32_t n_port = i % vol->n_ports, n_hndl;
150
+ struct port *p = vol->portsn_port;
151
+ float v = vol->mute ? 0.0f : vol->volumesi;
152
+ switch (vol->scalen_port) {
153
+ case SCALE_CUBIC:
154
+ v = cbrt(v);
155
+ break;
156
+ }
157
+ v = v * (vol->maxn_port - vol->minn_port) + vol->minn_port;
158
+
159
+ n_hndl = SPA_MAX(1u, p->node->n_hndl);
160
+ res += port_set_control_value(p, &v, i % n_hndl);
161
+ }
162
+ return res;
163
+}
164
+
165
+static void param_props_changed(struct impl *impl, const struct spa_pod *param,
166
+ bool capture)
167
{
168
struct spa_pod_object *obj = (struct spa_pod_object *) param;
169
+ struct spa_pod_frame f1;
170
const struct spa_pod_prop *prop;
171
struct graph *graph = &impl->graph;
172
int changed = 0;
173
+ char buf1024;
174
+ struct spa_pod_dynamic_builder b;
175
+ struct volume *vol = capture ? &graph->capture_volume :
176
+ &graph->playback_volume;
177
+ bool do_volume = false;
178
+
179
+ spa_pod_dynamic_builder_init(&b, buf, sizeof(buf), 1024);
180
+ spa_pod_builder_push_object(&b.b, &f0, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
181
182
SPA_POD_OBJECT_FOREACH(obj, prop) {
183
- if (prop->key == SPA_PROP_params)
184
+ switch (prop->key) {
185
+ case SPA_PROP_params:
186
changed += parse_params(graph, &prop->value);
187
+ spa_pod_builder_raw_padded(&b.b, prop, SPA_POD_PROP_SIZE(prop));
188
+ break;
189
+ case SPA_PROP_mute:
190
+ {
191
+ bool mute;
192
+ if (spa_pod_get_bool(&prop->value, &mute) == 0) {
193
+ if (vol->mute != mute) {
194
+ vol->mute = mute;
195
+ do_volume = true;
196
+ }
197
+ }
198
+ spa_pod_builder_raw_padded(&b.b, prop, SPA_POD_PROP_SIZE(prop));
199
+ break;
200
+ }
201
+ case SPA_PROP_channelVolumes:
202
+ {
203
+ uint32_t i, n_vols;
204
+ float volsSPA_AUDIO_MAX_CHANNELS;
205
+
206
+ if ((n_vols = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, vols,
207
+ SPA_AUDIO_MAX_CHANNELS)) > 0) {
208
+ if (vol->n_volumes != n_vols)
209
+ do_volume = true;
210
+ vol->n_volumes = n_vols;
211
+ for (i = 0; i < n_vols; i++) {
212
+ float v = volsi;
213
+ if (v != vol->volumesi) {
214
+ vol->volumesi = v;
215
+ do_volume = true;
216
+ }
217
+ }
218
+ }
219
+ spa_pod_builder_raw_padded(&b.b, prop, SPA_POD_PROP_SIZE(prop));
220
+ break;
221
+ }
222
+ case SPA_PROP_softVolumes:
223
+ case SPA_PROP_softMute:
224
+ break;
225
+ default:
226
+ spa_pod_builder_raw_padded(&b.b, prop, SPA_POD_PROP_SIZE(prop));
227
+ break;
228
+ }
229
}
230
+ if (do_volume && vol->n_ports != 0) {
231
+ float soft_volsSPA_AUDIO_MAX_CHANNELS;
232
+ uint32_t i;
233
+
234
+ for (i = 0; i < vol->n_volumes; i++)
235
+ soft_volsi = (vol->mute || vol->volumesi == 0.0f) ? 0.0f : 1.0f;
236
+
237
+ spa_pod_builder_prop(&b.b, SPA_PROP_softMute, 0);
238
+ spa_pod_builder_bool(&b.b, vol->mute);
239
+ spa_pod_builder_prop(&b.b, SPA_PROP_softVolumes, 0);
240
+ spa_pod_builder_array(&b.b, sizeof(float), SPA_TYPE_Float,
241
+ vol->n_volumes, soft_vols);
242
+ param = spa_pod_builder_pop(&b.b, &f0);
243
+
244
+ sync_volume(graph, vol);
245
+ pw_stream_set_param(capture ? impl->capture :
246
+ impl->playback, SPA_PARAM_Props, param);
247
+ }
248
+
249
+ spa_pod_dynamic_builder_clean(&b);
250
+
251
if (changed > 0) {
252
struct node *node;
253
254
255
256
update_props_param(impl);
257
}
258
+
259
}
260
261
static void param_latency_changed(struct impl *impl, const struct spa_pod *param)
262
263
}
264
}
265
266
-static void param_changed(void *data, uint32_t id, const struct spa_pod *param)
267
+static void param_changed(void *data, uint32_t id, const struct spa_pod *param,
268
+ bool capture)
269
{
270
struct impl *impl = data;
271
struct graph *graph = &impl->graph;
272
273
}
274
case SPA_PARAM_Props:
275
if (param != NULL)
276
- param_props_changed(impl, param);
277
+ param_props_changed(impl, param, capture);
278
break;
279
case SPA_PARAM_Latency:
280
param_latency_changed(impl, param);
281
282
return;
283
284
error:
285
- pw_stream_set_error(impl->capture, res, "can't start graph: %s",
286
- spa_strerror(res));
287
+ pw_stream_set_error(capture ? impl->capture : impl->playback,
288
+ res, "can't start graph: %s", spa_strerror(res));
289
+}
290
+
291
+static void capture_param_changed(void *data, uint32_t id, const struct spa_pod *param)
292
+{
293
+ param_changed(data, id, param, true);
294
}
295
296
static const struct pw_stream_events in_stream_events = {
297
298
.process = capture_process,
299
.io_changed = io_changed,
300
.state_changed = state_changed,
301
- .param_changed = param_changed
302
+ .param_changed = capture_param_changed
303
};
304
305
+static void playback_param_changed(void *data, uint32_t id, const struct spa_pod *param)
306
+{
307
+ param_changed(data, id, param, false);
308
+}
309
+
310
static void playback_destroy(void *d)
311
{
312
struct impl *impl = d;
313
314
.process = playback_process,
315
.io_changed = io_changed,
316
.state_changed = state_changed,
317
- .param_changed = param_changed,
318
+ .param_changed = playback_param_changed,
319
};
320
321
static int setup_streams(struct impl *impl)
322
323
}
324
325
/**
326
+ * {
327
+ * control = name:portname
328
+ * min = <float, defaukt 0.0>
329
+ * max = <float, default 1.0>
330
+ * scale = <string, default "linear", options "linear","cubic">
331
+ * }
332
+ */
333
+static int parse_volume(struct graph *graph, struct spa_json *json, bool capture)
334
+{
335
+ char key256;
336
+ char control256 = "";
337
+ char scale64 = "linear";
338
+ float min = 0.0f, max = 1.0f;
339
+ const char *val;
340
+ struct node *def_control;
341
+ struct port *port;
342
+ struct volume *vol = capture ? &graph->capture_volume :
343
+ &graph->playback_volume;
344
+
345
+ if (spa_list_is_empty(&graph->node_list)) {
346
+ pw_log_error("can't set volume in graph without nodes");
347
+ return -EINVAL;
348
+ }
349
+ while (spa_json_get_string(json, key, sizeof(key)) > 0) {
350
+ if (spa_streq(key, "control")) {
351
+ if (spa_json_get_string(json, control, sizeof(control)) <= 0) {
352
+ pw_log_error("control expects a string");
353
+ return -EINVAL;
354
+ }
355
+ }
356
+ else if (spa_streq(key, "min")) {
357
+ if (spa_json_get_float(json, &min) <= 0) {
358
+ pw_log_error("min expects a float");
359
+ return -EINVAL;
360
+ }
361
+ }
362
+ else if (spa_streq(key, "max")) {
363
+ if (spa_json_get_float(json, &max) <= 0) {
364
+ pw_log_error("max expects a float");
365
+ return -EINVAL;
366
+ }
367
+ }
368
+ else if (spa_streq(key, "scale")) {
369
+ if (spa_json_get_string(json, scale, sizeof(scale)) <= 0) {
370
+ pw_log_error("scale expects a string");
371
+ return -EINVAL;
372
+ }
373
+ }
374
+ else if (spa_json_next(json, &val) < 0)
375
+ break;
376
+ }
377
+ if (capture)
378
+ def_control = spa_list_first(&graph->node_list, struct node, link);
379
+ else
380
+ def_control = spa_list_last(&graph->node_list, struct node, link);
381
+
382
+ port = find_port(def_control, control, FC_PORT_INPUT | FC_PORT_CONTROL);
383
+ if (port == NULL) {
384
+ pw_log_error("unknown control port %s", control);
385
+ return -ENOENT;
386
+ }
387
+ if (vol->n_ports >= SPA_AUDIO_MAX_CHANNELS) {
388
+ pw_log_error("too many volume controls");
389
+ return -ENOSPC;
390
+ }
391
+ if (spa_streq(scale, "linear")) {
392
+ vol->scalevol->n_ports = SCALE_LINEAR;
393
+ } else if (spa_streq(scale, "cubic")) {
394
+ vol->scalevol->n_ports = SCALE_CUBIC;
395
+ } else {
396
+ pw_log_error("Invalid scale value '%s', use one of linear or cubic", scale);
397
+ return -EINVAL;
398
+ }
399
+ pw_log_info("volume %d: \"%s:%s\" min:%f max:%f scale:%s", vol->n_ports, port->node->name,
400
+ port->node->desc->desc->portsport->p.name, min, max, scale);
401
+
402
+ vol->portsvol->n_ports = port;
403
+ vol->minvol->n_ports = min;
404
+ vol->maxvol->n_ports = max;
405
+ vol->n_ports++;
406
+
407
+ return 0;
408
+}
409
+
410
+/**
411
* type = ladspa
412
* name = rev
413
* plugin = g2reverb
414
415
port->external = SPA_ID_INVALID;
416
port->p = desc->controli;
417
spa_list_init(&port->link_list);
418
- port->control_data = desc->default_controli;
419
+ port->control_data0 = desc->default_controli;
420
}
421
for (i = 0; i < desc->n_notify; i++) {
422
struct port *port = &node->notify_porti;
423
424
}
425
for (j = 0; j < desc->n_control; j++) {
426
port = &node->control_portj;
427
- d->connect_port(node->hndli, port->p, &port->control_data);
428
+ d->connect_port(node->hndli, port->p, &port->control_datai);
429
430
spa_list_for_each(link, &port->link_list, input_link) {
431
struct port *peer = link->output;
432
pw_log_info("connect control port %s%d:%s %p",
433
node->name, i, d->portsport->p.name,
434
- &peer->control_data);
435
- d->connect_port(node->hndli, port->p, &peer->control_data);
436
+ &peer->control_datai);
437
+ d->connect_port(node->hndli, port->p, &peer->control_datai);
438
}
439
}
440
for (j = 0; j < desc->n_notify; j++) {
441
port = &node->notify_portj;
442
pw_log_info("connect notify port %s%d:%s %p",
443
node->name, i, d->portsport->p.name,
444
- &port->control_data);
445
- d->connect_port(node->hndli, port->p, &port->control_data);
446
+ &port->control_datai);
447
+ d->connect_port(node->hndli, port->p, &port->control_datai);
448
}
449
if (d->activate)
450
d->activate(node->hndli);
451
452
return res;
453
}
454
455
+/* any default values for the controls are set in the first instance
456
+ * of the control data. Duplicate this to the other instances now. */
457
+static void setup_node_controls(struct node *node)
458
+{
459
+ uint32_t i, j;
460
+ uint32_t n_hndl = node->n_hndl;
461
+ uint32_t n_ports = node->desc->n_control;
462
+ struct port *ports = node->control_port;
463
+
464
+ for (i = 0; i < n_ports; i++) {
465
+ struct port *port = &portsi;
466
+ for (j = 1; j < n_hndl; j++)
467
+ port->control_dataj = port->control_data0;
468
+ }
469
+}
470
+
471
static struct node *find_next_node(struct graph *graph)
472
{
473
struct node *node;
474
475
desc = node->desc;
476
n_control += desc->n_control;
477
n_nodes++;
478
+ setup_node_controls(node);
479
}
480
graph->n_input = 0;
481
graph->input = calloc(n_input * 16 * n_hndl, sizeof(struct graph_port));
482
483
{
484
struct spa_json it3;
485
struct spa_json inputs, outputs, *pinputs = NULL, *poutputs = NULL;
486
+ struct spa_json cvolumes, pvolumes, *pcvolumes = NULL, *ppvolumes = NULL;
487
struct spa_json nodes, *pnodes = NULL, links, *plinks = NULL;
488
const char *json, *val;
489
char key256;
490
491
return -EINVAL;
492
}
493
poutputs = &outputs;
494
+ }
495
+ else if (spa_streq("capture.volumes", key)) {
496
+ if (spa_json_enter_array(&it1, &cvolumes) <= 0) {
497
+ pw_log_error("capture.volumes expects an array");
498
+ return -EINVAL;
499
+ }
500
+ pcvolumes = &cvolumes;
501
+ }
502
+ else if (spa_streq("playback.volumes", key)) {
503
+ if (spa_json_enter_array(&it1, &pvolumes) <= 0) {
504
+ pw_log_error("playback.volumes expects an array");
505
+ return -EINVAL;
506
+ }
507
+ ppvolumes = &pvolumes;
508
} else if (spa_json_next(&it1, &val) < 0)
509
break;
510
}
511
512
return res;
513
}
514
}
515
+ if (pcvolumes != NULL) {
516
+ while (spa_json_enter_object(pcvolumes, &it2) > 0) {
517
+ if ((res = parse_volume(graph, &it2, true)) < 0)
518
+ return res;
519
+ }
520
+ }
521
+ if (ppvolumes != NULL) {
522
+ while (spa_json_enter_object(ppvolumes, &it2) > 0) {
523
+ if ((res = parse_volume(graph, &it2, false)) < 0)
524
+ return res;
525
+ }
526
+ }
527
return setup_graph(graph, pinputs, poutputs);
528
}
529
530
pipewire-0.3.80.tar.gz/src/modules/module-filter-chain/dsp-ops-c.c -> pipewire-0.3.81.tar.gz/src/modules/module-filter-chain/dsp-ops-c.c
Changed
11
1
2
uint32_t i;
3
if (n_src == 0) {
4
dsp_clear_c(ops, dst, n_samples);
5
- } else if (n_src == 1) {
6
- if (dst != src0)
7
- dsp_copy_c(ops, dst, src0, n_samples);
8
} else {
9
if (gain0 == 1.0f)
10
dsp_copy_c(ops, dst, src0, n_samples);
11
pipewire-0.3.80.tar.gz/src/modules/module-filter-chain/dsp-ops-sse.c -> pipewire-0.3.81.tar.gz/src/modules/module-filter-chain/dsp-ops-sse.c
Changed
10
1
2
{
3
if (n_src == 0) {
4
memset(dst, 0, n_samples * sizeof(float));
5
- } else if (n_src == 1) {
6
+ } else if (n_src == 1 && gain0 == 1.0f) {
7
if (dst != src0)
8
spa_memcpy(dst, src0, n_samples * sizeof(float));
9
} else {
10
pipewire-0.3.80.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.81.tar.gz/src/modules/module-pipe-tunnel.c
Changed
9
1
2
#include <errno.h>
3
#include <sys/types.h>
4
#include <sys/stat.h>
5
+#include <sys/uio.h>
6
#include <fcntl.h>
7
#include <unistd.h>
8
#include <stdlib.h>
9
pipewire-0.3.80.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.81.tar.gz/src/modules/module-profiler.c
Changed
10
1
2
n->count++;
3
}
4
5
-static struct pw_impl_node_rt_events node_rt_events = {
6
+static const struct pw_impl_node_rt_events node_rt_events = {
7
PW_VERSION_IMPL_NODE_RT_EVENTS,
8
.complete = context_do_profile,
9
.incomplete = context_do_profile,
10
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/client.c
Changed
9
1
2
spa_list_init(&client->out_messages);
3
spa_list_init(&client->operations);
4
spa_list_init(&client->pending_samples);
5
- spa_list_init(&client->pending_streams);
6
spa_hook_list_init(&client->listener_list);
7
8
spa_list_append(&server->clients, &client->link);
9
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/client.h -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/client.h
Changed
10
1
2
3
struct spa_list pending_samples;
4
5
- struct spa_list pending_streams;
6
-
7
unsigned int disconnect:1;
8
unsigned int new_msg_since_last_flush:1;
9
unsigned int authenticated:1;
10
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
12
1
2
case SPA_PARAM_PropInfo:
3
case SPA_PARAM_Format:
4
case SPA_PARAM_EnumFormat:
5
+ /* also emit changed for the Latency param because the stream might
6
+ * now be linked. FIXME, we should check if a new link is made for
7
+ * a stream and only emit a changed event in that case. */
8
+ case SPA_PARAM_Latency:
9
changed++;
10
break;
11
default:
12
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c
Changed
13
1
2
char *args;
3
size_t size;
4
5
+ pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+ pw_properties_setf(data->source_props, "pulse.module.id", "%u", module->index);
7
+ pw_properties_setf(data->sink_props, "pulse.module.id", "%u", module->index);
8
+ pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
9
+
10
if ((f = open_memstream(&args, &size)) == NULL)
11
return -errno;
12
13
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
160
1
2
}
3
4
if (spa_streq(o->type, PW_TYPE_INTERFACE_Link)) {
5
- struct stream *s, *t;
6
struct pw_manager_object *peer = NULL;
7
union pw_map_item *item;
8
pw_array_for_each(item, &client->streams.items) {
9
struct stream *s = item->data;
10
const char *peer_name;
11
12
- if (pw_map_item_is_free(item) || s->pending)
13
+ if (pw_map_item_is_free(item))
14
continue;
15
- if (s->peer_index == SPA_ID_INVALID)
16
+
17
+ if (!s->pending && s->peer_index == SPA_ID_INVALID)
18
continue;
19
20
peer = find_peer_for_link(manager, o, s->id, s->direction);
21
- if (peer == NULL || peer->props == NULL ||
22
- peer->index == s->peer_index)
23
+ if (peer == NULL)
24
continue;
25
26
- s->peer_index = peer->index;
27
-
28
- peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME);
29
- if (peer_name && s->direction == PW_DIRECTION_INPUT &&
30
- pw_manager_object_is_monitor(peer)) {
31
- int len = strlen(peer_name) + 10;
32
- char *tmp = alloca(len);
33
- snprintf(tmp, len, "%s.monitor", peer_name);
34
- peer_name = tmp;
35
- }
36
- if (peer_name != NULL)
37
- stream_send_moved(s, peer->index, peer_name);
38
- }
39
- spa_list_for_each_safe(s, t, &client->pending_streams, link) {
40
- peer = find_peer_for_link(manager, o, s->id, s->direction);
41
- if (peer) {
42
+ if (s->pending) {
43
reply_create_stream(s, peer);
44
- spa_list_remove(&s->link);
45
s->pending = false;
46
+ } else {
47
+ if (s->peer_index == peer->index)
48
+ continue;
49
+ if (peer->props == NULL)
50
+ continue;
51
+
52
+ s->peer_index = peer->index;
53
+
54
+ peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME);
55
+ if (peer_name && s->direction == PW_DIRECTION_INPUT &&
56
+ pw_manager_object_is_monitor(peer)) {
57
+ int len = strlen(peer_name) + 10;
58
+ char *tmp = alloca(len);
59
+ snprintf(tmp, len, "%s.monitor", peer_name);
60
+ peer_name = tmp;
61
+ }
62
+ if (peer_name != NULL)
63
+ stream_send_moved(s, peer->index, peer_name);
64
}
65
}
66
}
67
68
if (peer) {
69
reply_create_stream(stream, peer);
70
} else {
71
- spa_list_append(&stream->client->pending_streams, &stream->link);
72
stream->pending = true;
73
}
74
}
75
76
const char *str;
77
int res = 0;
78
79
+ debug_messages = pw_log_topic_enabled(SPA_LOG_LEVEL_INFO, pulse_conn);
80
+
81
impl = calloc(1, sizeof(*impl) + user_data_size);
82
if (impl == NULL)
83
- goto error_exit;
84
+ goto error_free_props;
85
+
86
+ impl->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
87
+ impl->rate_limit.burst = 1;
88
+ spa_hook_list_init(&impl->hooks);
89
+ spa_list_init(&impl->servers);
90
+ pw_map_init(&impl->samples, 16, 16);
91
+ pw_map_init(&impl->modules, 16, 16);
92
+ spa_list_init(&impl->cleanup_clients);
93
+ spa_list_init(&impl->free_messages);
94
+
95
+ impl->loop = pw_context_get_main_loop(context);
96
+ impl->work_queue = pw_context_get_work_queue(context);
97
98
if (props == NULL)
99
props = pw_properties_new(NULL, NULL);
100
101
pw_properties_set(props, "vm.overrides", NULL);
102
}
103
104
- load_defaults(&impl->defs, props);
105
-
106
- debug_messages = pw_log_topic_enabled(SPA_LOG_LEVEL_INFO, pulse_conn);
107
-
108
- impl->context = context;
109
- impl->loop = pw_context_get_main_loop(context);
110
- impl->props = props;
111
-
112
- impl->work_queue = pw_context_get_work_queue(context);
113
-
114
- spa_hook_list_init(&impl->hooks);
115
- spa_list_init(&impl->servers);
116
- impl->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
117
- impl->rate_limit.burst = 1;
118
- pw_map_init(&impl->samples, 16, 16);
119
- pw_map_init(&impl->modules, 16, 16);
120
- spa_list_init(&impl->cleanup_clients);
121
- spa_list_init(&impl->free_messages);
122
-
123
str = pw_properties_get(props, "server.address");
124
if (str == NULL) {
125
pw_properties_setf(props, "server.address",
126
127
pw_log_warn("%p: can't create pid file: %s",
128
impl, spa_strerror(res));
129
}
130
- pw_context_add_listener(context, &impl->context_listener,
131
- &context_events, impl);
132
133
#ifdef HAVE_DBUS
134
str = pw_properties_get(props, "server.dbus-name");
135
136
if (strlen(str) > 0)
137
impl->dbus_name = dbus_request_name(context, str);
138
#endif
139
+
140
+ load_defaults(&impl->defs, props);
141
+ impl->props = spa_steal_ptr(props);
142
+
143
+ pw_context_add_listener(context, &impl->context_listener,
144
+ &context_events, impl);
145
+ impl->context = context;
146
+
147
cmd_run(impl);
148
149
return (struct pw_protocol_pulse *) impl;
150
151
error_free:
152
- free(impl);
153
+ impl_free(impl);
154
155
-error_exit:
156
+error_free_props:
157
pw_properties_free(props);
158
159
if (res < 0)
160
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/stream.c
Changed
11
1
2
3
pw_log_debug("client %p: stream %p channel:%d", client, stream, stream->channel);
4
5
- if (stream->pending)
6
- spa_list_remove(&stream->link);
7
-
8
if (stream->drain_tag)
9
reply_error(client, -1, stream->drain_tag, -ENOENT);
10
11
pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/stream.h -> pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/stream.h
Changed
9
1
2
};
3
4
struct stream {
5
- struct spa_list link;
6
uint32_t create_tag;
7
uint32_t channel; /* index in map */
8
uint32_t id; /* id of global */
9
pipewire-0.3.80.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.81.tar.gz/src/modules/module-raop-sink.c
Changed
623
1
2
#include <pipewire/i18n.h>
3
4
#include "module-raop/rtsp-client.h"
5
+#include "module-rtp/rtp.h"
6
7
/** \page page_module_raop_sink PipeWire Module: AirPlay Sink
8
*
9
10
#endif
11
#define MD5_HASH_LENGTH (2*MD5_DIGEST_LENGTH)
12
13
-#define DEFAULT_USER_AGENT "iTunes/11.0.4 (Windows; N)"
14
-#define DEFAULT_USER_NAME "iTunes"
15
+#define DEFAULT_USER_NAME "PipeWire"
16
+#define RAOP_AUTH_USER_NAME "iTunes"
17
18
#define MAX_PORT_RETRY 128
19
20
21
#define DEFAULT_CHANNELS 2
22
#define DEFAULT_POSITION " FL FR "
23
24
-#define VOLUME_MAX 0.0
25
-#define VOLUME_DEF -30.0
26
-#define VOLUME_MIN -144.0
27
+#define VOLUME_MAX 0.0
28
+#define VOLUME_MIN -30.0
29
+#define VOLUME_MUTE -144.0
30
31
#define MODULE_USAGE "( raop.ip=<ip address of host> ) " \
32
"( raop.port=<remote port> ) " \
33
34
35
unsigned int do_disconnect:1;
36
37
- uint8_t keyAES_CHUNK_SIZE; /* Key for aes-cbc */
38
- uint8_t ivAES_CHUNK_SIZE; /* Initialization vector for cbc */
39
+ uint8_t aes_keyAES_CHUNK_SIZE; /* Key for aes-cbc */
40
+ uint8_t aes_ivAES_CHUNK_SIZE; /* Initialization vector for cbc */
41
EVP_CIPHER_CTX *ctx;
42
43
uint16_t control_port;
44
int control_fd;
45
struct spa_source *control_source;
46
+ struct spa_source *feedback_timer;
47
48
uint16_t timing_port;
49
int timing_fd;
50
51
uint32_t block_size;
52
uint32_t latency;
53
54
- uint16_t seq;
55
+ uint16_t seq, cseq;
56
uint32_t rtptime;
57
uint32_t ssrc;
58
uint32_t sync;
59
60
static int aes_encrypt(struct impl *impl, uint8_t *data, int len)
61
{
62
int i = len & ~0xf, clen = i;
63
- EVP_EncryptInit(impl->ctx, EVP_aes_128_cbc(), impl->key, impl->iv);
64
+ EVP_EncryptInit(impl->ctx, EVP_aes_128_cbc(), impl->aes_key, impl->aes_iv);
65
EVP_EncryptUpdate(impl->ctx, data, &clen, data, i);
66
return i;
67
}
68
69
static int send_udp_sync_packet(struct impl *impl,
70
struct sockaddr *dest_addr, socklen_t addrlen)
71
{
72
- uint32_t pkt5;
73
+ uint32_t out3;
74
uint32_t rtptime = impl->rtptime;
75
uint32_t latency = impl->latency;
76
uint64_t transmitted;
77
+ struct rtp_header header;
78
+ struct iovec iov2;
79
+ struct msghdr msg;
80
+ int res;
81
82
- pkt0 = htonl(0x80d40007);
83
+ spa_zero(header);
84
+ header.v = 2;
85
if (impl->first)
86
- pkt0 |= htonl(0x10000000);
87
- pkt1 = htonl(rtptime - latency);
88
+ header.x = 1;
89
+ header.m = 1;
90
+ header.pt = 84;
91
+ header.sequence_number = htons(impl->cseq);
92
+ header.timestamp = htonl(rtptime - latency);
93
+
94
+ iov0.iov_base = &header;
95
+ iov0.iov_len = 8;
96
+
97
transmitted = ntp_now();
98
- pkt2 = htonl(transmitted >> 32);
99
- pkt3 = htonl(transmitted & 0xffffffff);
100
- pkt4 = htonl(rtptime);
101
+ out0 = htonl(transmitted >> 32);
102
+ out1 = htonl(transmitted & 0xffffffff);
103
+ out2 = htonl(rtptime);
104
+
105
+ iov1.iov_base = out;
106
+ iov1.iov_len = sizeof(out);
107
+
108
+ msg.msg_name = dest_addr;
109
+ msg.msg_namelen = addrlen;
110
+ msg.msg_iov = iov;
111
+ msg.msg_iovlen = 2;
112
+ msg.msg_control = NULL;
113
+ msg.msg_controllen = 0;
114
+ msg.msg_flags = 0;
115
+
116
+ res = sendmsg(impl->control_fd, &msg, MSG_NOSIGNAL);
117
+ if (res < 0) {
118
+ res = -errno;
119
+ pw_log_warn("error sending control packet: %d", res);
120
+ }
121
+
122
+ impl->cseq = (impl->cseq + 1) & 0xffff;
123
124
- pw_log_debug("sync: first:%d latency:%u now:%"PRIx64" rtptime:%u",
125
- impl->first, latency, transmitted, rtptime);
126
+ pw_log_debug("raop control sync: cseq:%d first:%d latency:%u now:%"PRIx64" rtptime:%u",
127
+ impl->cseq, impl->first, latency, transmitted, rtptime);
128
129
- return sendto(impl->control_fd, pkt, sizeof(pkt), 0, dest_addr, addrlen);
130
+ return res;
131
}
132
133
static int send_udp_timing_packet(struct impl *impl, uint64_t remote, uint64_t received,
134
struct sockaddr *dest_addr, socklen_t addrlen)
135
{
136
- uint32_t pkt8;
137
+ uint32_t out6;
138
uint64_t transmitted;
139
+ struct rtp_header header;
140
+ struct iovec iov2;
141
+ struct msghdr msg;
142
+ int res;
143
144
- pkt0 = htonl(0x80d30007);
145
- pkt1 = 0x00000000;
146
- pkt2 = htonl(remote >> 32);
147
- pkt3 = htonl(remote & 0xffffffff);
148
- pkt4 = htonl(received >> 32);
149
- pkt5 = htonl(received & 0xffffffff);
150
- transmitted = ntp_now();
151
- pkt6 = htonl(transmitted >> 32);
152
- pkt7 = htonl(transmitted & 0xffffffff);
153
+ spa_zero(header);
154
+ header.v = 2;
155
+ header.pt = 83;
156
+ header.m = 1;
157
+
158
+ iov0.iov_base = &header;
159
+ iov0.iov_len = 8;
160
+
161
+ out0 = htonl(remote >> 32);
162
+ out1 = htonl(remote & 0xffffffff);
163
164
- pw_log_debug("sync: remote:%"PRIx64" received:%"PRIx64" transmitted:%"PRIx64,
165
+ out2 = htonl(received >> 32);
166
+ out3 = htonl(received & 0xffffffff);
167
+ transmitted = ntp_now();
168
+ out4 = htonl(transmitted >> 32);
169
+ out5 = htonl(transmitted & 0xffffffff);
170
+
171
+ iov1.iov_base = out;
172
+ iov1.iov_len = sizeof(out);
173
+
174
+ msg.msg_name = dest_addr;
175
+ msg.msg_namelen = addrlen;
176
+ msg.msg_iov = iov;
177
+ msg.msg_iovlen = 2;
178
+ msg.msg_control = NULL;
179
+ msg.msg_controllen = 0;
180
+ msg.msg_flags = 0;
181
+
182
+ res = sendmsg(impl->timing_fd, &msg, MSG_NOSIGNAL);
183
+ if (res < 0) {
184
+ res = -errno;
185
+ pw_log_warn("error sending timing packet: %d", res);
186
+ }
187
+ pw_log_debug("raop timing sync: remote:%"PRIx64" received:%"PRIx64" transmitted:%"PRIx64,
188
remote, received, transmitted);
189
190
- return sendto(impl->timing_fd, pkt, sizeof(pkt), 0, dest_addr, addrlen);
191
+ return res;
192
}
193
194
static int write_codec_pcm(void *dst, void *frames, uint32_t n_frames)
195
196
197
static int flush_to_udp_packet(struct impl *impl)
198
{
199
- const size_t max = 12 + 8 + impl->block_size;
200
- uint32_t pktmax, len, n_frames;
201
+ const size_t max = 8 + impl->block_size;
202
+ uint32_t outmax, len, n_frames;
203
+ struct rtp_header header;
204
+ struct iovec iov2;
205
+ struct msghdr msg;
206
uint8_t *dst;
207
int res;
208
209
210
impl->sync = 0;
211
send_udp_sync_packet(impl, NULL, 0);
212
}
213
- pkt0 = htonl(0x80600000);
214
+
215
+ spa_zero(header);
216
+ header.v = 2;
217
+ header.pt = 96;
218
if (impl->first)
219
- pkt0 |= htonl((uint32_t)0x80 << 16);
220
- pkt0 |= htonl((uint32_t)impl->seq);
221
- pkt1 = htonl(impl->rtptime);
222
- pkt2 = htonl(impl->ssrc);
223
+ header.m = 1;
224
+ header.sequence_number = htons(impl->seq);
225
+ header.timestamp = htonl(impl->rtptime);
226
+ header.ssrc = htonl(impl->ssrc);
227
+
228
+ iov0.iov_base = &header;
229
+ iov0.iov_len = 12;
230
231
n_frames = impl->filled / impl->frame_size;
232
- dst = (uint8_t*)&pkt3;
233
+ dst = (uint8_t*)&out0;
234
235
switch (impl->codec) {
236
case CODEC_PCM:
237
238
if (impl->encryption == CRYPTO_RSA)
239
aes_encrypt(impl, dst, len);
240
241
+ iov1.iov_base = out;
242
+ iov1.iov_len = len;
243
+
244
impl->rtptime += n_frames;
245
impl->seq = (impl->seq + 1) & 0xffff;
246
247
- pw_log_debug("send %u", len + 12);
248
- res = send(impl->server_fd, pkt, len + 12, 0);
249
+ msg.msg_name = NULL;
250
+ msg.msg_namelen = 0;
251
+ msg.msg_iov = iov;
252
+ msg.msg_iovlen = 2;
253
+ msg.msg_control = NULL;
254
+ msg.msg_controllen = 0;
255
+ msg.msg_flags = 0;
256
+
257
+ res = sendmsg(impl->server_fd, &msg, MSG_NOSIGNAL);
258
+ if (res < 0) {
259
+ res = -errno;
260
+ pw_log_warn("error streaming packet: %d", res);
261
+ }
262
263
impl->first = false;
264
265
266
267
static int flush_to_tcp_packet(struct impl *impl)
268
{
269
- const size_t max = 16 + 8 + impl->block_size;
270
- uint32_t pktmax, len, n_frames;
271
+ const size_t max = 8 + impl->block_size;
272
+ uint32_t tcp_pkt1, outmax, len, n_frames;
273
+ struct rtp_header header;
274
+ struct iovec iov3;
275
+ struct msghdr msg;
276
uint8_t *dst;
277
int res;
278
279
if (!impl->recording)
280
return 0;
281
282
- pkt0 = htonl(0x24000000);
283
- pkt1 = htonl(0x80e00000);
284
- pkt1 |= htonl((uint32_t)impl->seq);
285
- pkt2 = htonl(impl->rtptime);
286
- pkt3 = htonl(impl->ssrc);
287
+ tcp_pkt0 = htonl(0x24000000);
288
+
289
+ iov0.iov_base = &tcp_pkt;
290
+ iov0.iov_len = 4;
291
+
292
+ spa_zero(header);
293
+ header.v = 2;
294
+ header.pt = 96;
295
+ header.sequence_number = htons(impl->seq);
296
+ header.timestamp = htonl(impl->rtptime);
297
+ header.ssrc = htonl(impl->ssrc);
298
+
299
+ iov1.iov_base = &header;
300
+ iov1.iov_len = 12;
301
302
n_frames = impl->filled / impl->frame_size;
303
- dst = (uint8_t*)&pkt4;
304
+ dst = (uint8_t*)&out0;
305
306
switch (impl->codec) {
307
case CODEC_PCM:
308
309
if (impl->encryption == CRYPTO_RSA)
310
aes_encrypt(impl, dst, len);
311
312
- pkt0 |= htonl((uint32_t) len + 12);
313
+ out0 |= htonl((uint32_t) len + 12);
314
+
315
+ iov2.iov_base = out;
316
+ iov2.iov_len = len;
317
318
impl->rtptime += n_frames;
319
impl->seq = (impl->seq + 1) & 0xffff;
320
321
- pw_log_debug("send %u", len + 16);
322
- res = send(impl->server_fd, pkt, len + 16, 0);
323
+ msg.msg_name = NULL;
324
+ msg.msg_namelen = 0;
325
+ msg.msg_iov = iov;
326
+ msg.msg_iovlen = 2;
327
+ msg.msg_control = NULL;
328
+ msg.msg_controllen = 0;
329
+ msg.msg_flags = 0;
330
+
331
+ res = sendmsg(impl->server_fd, &msg, MSG_NOSIGNAL);
332
+ if (res < 0) {
333
+ res = -errno;
334
+ pw_log_warn("error streaming packet: %d", res);
335
+ }
336
337
impl->first = false;
338
339
340
return 0;
341
}
342
343
-static int rtsp_add_auth(struct impl *impl, const char *method)
344
+static int rtsp_add_raop_auth_header(struct impl *impl, const char *method)
345
{
346
char auth1024;
347
348
349
if (spa_streq(impl->auth_method, "Basic")) {
350
char buf256;
351
char enc512;
352
- spa_scnprintf(buf, sizeof(buf), "%s:%s", DEFAULT_USER_NAME, impl->password);
353
+ spa_scnprintf(buf, sizeof(buf), "%s:%s", RAOP_AUTH_USER_NAME, impl->password);
354
base64_encode((uint8_t*)buf, strlen(buf), enc, '=');
355
spa_scnprintf(auth, sizeof(auth), "Basic %s", enc);
356
}
357
358
359
url = pw_rtsp_client_get_url(impl->rtsp);
360
361
- MD5_hash(h1, "%s:%s:%s", DEFAULT_USER_NAME, impl->realm, impl->password);
362
+ MD5_hash(h1, "%s:%s:%s", RAOP_AUTH_USER_NAME, impl->realm, impl->password);
363
MD5_hash(h2, "%s:%s", method, url);
364
MD5_hash(resp, "%s:%s:%s", h1, impl->nonce, h2);
365
366
spa_scnprintf(auth, sizeof(auth),
367
"username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
368
- DEFAULT_USER_NAME, impl->realm, impl->nonce, url, resp);
369
+ RAOP_AUTH_USER_NAME, impl->realm, impl->nonce, url, resp);
370
}
371
else
372
goto error;
373
374
375
return 0;
376
error:
377
- pw_log_error("error adding auth");
378
+ pw_log_error("error adding raop RSA auth");
379
return -EINVAL;
380
}
381
382
383
{
384
int res;
385
386
- rtsp_add_auth(impl, method);
387
+ rtsp_add_raop_auth_header(impl, method);
388
389
res = pw_rtsp_client_send(impl->rtsp, method, &impl->headers->dict,
390
content_type, content, reply, impl);
391
392
393
char header128, volstr64;
394
snprintf(header, sizeof(header), "volume: %s\r\n",
395
- spa_dtoa(volstr, sizeof(volstr), impl->volume));
396
+ spa_dtoa(volstr, sizeof(volstr), impl->mute ? VOLUME_MUTE : impl->volume));
397
return rtsp_send(impl, "SET_PARAMETER", "text/parameters", header, rtsp_log_reply_status);
398
}
399
400
+static void rtsp_do_post_feedback(void *data, uint64_t expirations)
401
+{
402
+ struct impl *impl = data;
403
+
404
+ pw_rtsp_client_url_send(impl->rtsp, "/feedback", "POST", &impl->headers->dict,
405
+ NULL, NULL, 0, rtsp_log_reply_status, impl);
406
+}
407
+
408
static int rtsp_record_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
409
{
410
struct impl *impl = data;
411
412
struct spa_pod_builder b;
413
struct spa_latency_info latency;
414
char progress128;
415
+ struct timespec timeout, interval;
416
417
pw_log_info("record status: %d", status);
418
419
+ timeout.tv_sec = 2;
420
+ timeout.tv_nsec = 0;
421
+ interval.tv_sec = 2;
422
+ interval.tv_nsec = 0;
423
+
424
+ if (!impl->feedback_timer)
425
+ impl->feedback_timer = pw_loop_add_timer(impl->loop, rtsp_do_post_feedback, impl);
426
+ pw_loop_update_timer(impl->loop, impl->feedback_timer, &timeout, &interval, false);
427
+
428
if ((str = spa_dict_lookup(headers, "Audio-Latency")) != NULL) {
429
uint32_t l;
430
if (spa_atou32(str, &l, 0))
431
432
if (!sdp)
433
return -errno;
434
break;
435
-
436
case CRYPTO_AUTH_SETUP:
437
sdp = spa_aprintf("v=0\r\n"
438
"o=iTunes %s 0 IN IP%d %s\r\n"
439
440
break;
441
442
case CRYPTO_RSA:
443
- if ((res = pw_getrandom(impl->key, sizeof(impl->key), 0)) < 0 ||
444
- (res = pw_getrandom(impl->iv, sizeof(impl->iv), 0)) < 0)
445
+ {
446
+ uint8_t rac16;
447
+ char sac16*4;
448
+
449
+ if ((res = pw_getrandom(rac, sizeof(rac), 0)) < 0 ||
450
+ (res = pw_getrandom(impl->aes_key, sizeof(impl->aes_key), 0)) < 0 ||
451
+ (res = pw_getrandom(impl->aes_iv, sizeof(impl->aes_iv), 0)) < 0)
452
return res;
453
454
- rsa_len = rsa_encrypt(impl->key, 16, rsakey);
455
+ base64_encode(rac, sizeof(rac), sac, '\0');
456
+ pw_properties_set(impl->headers, "Apple-Challenge", sac);
457
+
458
+ rsa_len = rsa_encrypt(impl->aes_key, 16, rsakey);
459
if (rsa_len < 0)
460
return -rsa_len;
461
462
- base64_encode(rsakey, rsa_len, key, '=');
463
- base64_encode(impl->iv, 16, iv, '=');
464
+ base64_encode(rsakey, rsa_len, key, '=');
465
+ base64_encode(impl->aes_iv, 16, iv, '=');
466
467
sdp = spa_aprintf("v=0\r\n"
468
"o=iTunes %s 0 IN IP%d %s\r\n"
469
470
if (!sdp)
471
return -errno;
472
break;
473
+ }
474
default:
475
return -ENOTSUP;
476
}
477
478
return rtsp_send(impl, "ANNOUNCE", "application/sdp", sdp, rtsp_announce_reply);
479
}
480
481
-static int rtsp_auth_setup_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
482
+static int rtsp_post_auth_setup_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
483
{
484
struct impl *impl = data;
485
486
487
return rtsp_do_announce(impl);
488
}
489
490
-static int rtsp_do_auth_setup(struct impl *impl)
491
+static int rtsp_do_post_auth_setup(struct impl *impl)
492
{
493
static const unsigned char content33 =
494
"\x01"
495
496
497
return pw_rtsp_client_url_send(impl->rtsp, "/auth-setup", "POST", &impl->headers->dict,
498
"application/octet-stream", content, sizeof(content),
499
- rtsp_auth_setup_reply, impl);
500
+ rtsp_post_auth_setup_reply, impl);
501
}
502
503
-static int rtsp_auth_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
504
+static int rtsp_options_auth_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
505
{
506
struct impl *impl = data;
507
int res = 0;
508
509
switch (status) {
510
case 200:
511
if (impl->encryption == CRYPTO_AUTH_SETUP)
512
- res = rtsp_do_auth_setup(impl);
513
+ res = rtsp_do_post_auth_setup(impl);
514
else
515
res = rtsp_do_announce(impl);
516
break;
517
518
return NULL;
519
}
520
521
-static int rtsp_do_auth(struct impl *impl, const struct spa_dict *headers)
522
+static int rtsp_do_options_auth(struct impl *impl, const struct spa_dict *headers)
523
{
524
const char *str, *realm, *nonce;
525
int n_tokens;
526
527
impl->nonce = strdup(nonce);
528
}
529
530
- return rtsp_send(impl, "OPTIONS", NULL, NULL, rtsp_auth_reply);
531
+ return rtsp_send(impl, "OPTIONS", NULL, NULL, rtsp_options_auth_reply);
532
}
533
534
static int rtsp_options_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
535
536
537
switch (status) {
538
case 401:
539
- res = rtsp_do_auth(impl, headers);
540
+ res = rtsp_do_options_auth(impl, headers);
541
break;
542
case 200:
543
if (impl->encryption == CRYPTO_AUTH_SETUP)
544
- res = rtsp_do_auth_setup(impl);
545
+ res = rtsp_do_post_auth_setup(impl);
546
else
547
res = rtsp_do_announce(impl);
548
break;
549
550
{
551
struct impl *impl = data;
552
uint32_t sci2;
553
- uint8_t rac16;
554
- char sac16*4;
555
int res;
556
557
pw_log_info("connected");
558
559
impl->connected = true;
560
561
- if ((res = pw_getrandom(sci, sizeof(sci), 0)) < 0 ||
562
- (res = pw_getrandom(rac, sizeof(rac), 0)) < 0) {
563
+ if ((res = pw_getrandom(sci, sizeof(sci), 0)) < 0) {
564
pw_log_error("error generating random data: %s", spa_strerror(res));
565
return;
566
}
567
568
pw_properties_setf(impl->headers, "Client-Instance",
569
- "%08x%08x", sci0, sci1);
570
+ "%08X%08X", sci0, sci1);
571
572
- base64_encode(rac, sizeof(rac), sac, '\0');
573
- pw_properties_set(impl->headers, "Apple-Challenge", sac);
574
+ pw_properties_setf(impl->headers, "DACP-ID",
575
+ "%08X%08X", sci0, sci1);
576
577
- pw_properties_set(impl->headers, "User-Agent", DEFAULT_USER_AGENT);
578
+ pw_properties_set(impl->headers, "User-Agent", DEFAULT_USER_NAME "/" PACKAGE_VERSION);
579
580
pw_rtsp_client_send(impl->rtsp, "OPTIONS", &impl->headers->dict,
581
NULL, NULL, rtsp_options_reply, impl);
582
583
close(impl->timing_fd);
584
impl->timing_fd = -1;
585
}
586
+ if (impl->feedback_timer != NULL) {
587
+ pw_loop_destroy_source(impl->loop, impl->feedback_timer);
588
+ impl->feedback_timer = NULL;
589
+ }
590
free(impl->auth_method);
591
impl->auth_method = NULL;
592
free(impl->realm);
593
594
{
595
bool mute;
596
if (spa_pod_get_bool(&prop->value, &mute) == 0) {
597
- impl->mute = mute;
598
+ if (impl->mute != mute) {
599
+ impl->mute = mute;
600
+ rtsp_send_volume(impl);
601
+ }
602
}
603
spa_pod_builder_prop(&b, SPA_PROP_softMute, 0);
604
- spa_pod_builder_bool(&b, impl->mute);
605
+ spa_pod_builder_bool(&b, false);
606
spa_pod_builder_raw_padded(&b, prop, SPA_POD_PROP_SIZE(prop));
607
break;
608
}
609
610
soft_volsi = 1.0f;
611
}
612
volume /= n_vols;
613
- volume = SPA_CLAMPF(20.0 * log10(volume), VOLUME_MIN, VOLUME_MAX);
614
+ volume = SPA_CLAMPF(cbrt(volume) * 30 - 30, VOLUME_MIN, VOLUME_MAX);
615
impl->volume = volume;
616
617
rtsp_send_volume(impl);
618
}
619
-
620
spa_pod_builder_prop(&b, SPA_PROP_softVolumes, 0);
621
spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
622
n_vols, soft_vols);
623
pipewire-0.3.80.tar.gz/src/modules/module-raop/rtsp-client.c -> pipewire-0.3.81.tar.gz/src/modules/module-raop/rtsp-client.c
Changed
23
1
2
3
struct message {
4
struct spa_list link;
5
- void *data;
6
size_t len;
7
size_t offset;
8
uint32_t cseq;
9
int (*reply) (void *user_data, int status, const struct spa_dict *headers, const struct pw_array *content);
10
void *user_data;
11
+ unsigned char data;
12
};
13
14
enum client_recv_state {
15
16
17
fclose(f);
18
19
- msg->data = SPA_PTROFF(msg, sizeof(*msg), void);
20
msg->len = len - sizeof(*msg);
21
msg->offset = 0;
22
msg->reply = reply;
23
pipewire-0.3.80.tar.gz/src/modules/module-rt.c -> pipewire-0.3.81.tar.gz/src/modules/module-rt.c
Changed
21
1
2
#if defined(__FreeBSD__) || defined(__MidnightBSD__)
3
#include <sys/thr.h>
4
#endif
5
+#if defined(__GNU__)
6
+#include <mach.h>
7
+#endif
8
#include <fcntl.h>
9
#include <unistd.h>
10
#include <pthread.h>
11
12
long pid;
13
thr_self(&pid);
14
return (pid_t)pid;
15
+#elif defined(__GNU__)
16
+ mach_port_t thread = mach_thread_self();
17
+ return (pid_t)thread;
18
#else
19
#error "No gettid impl"
20
#endif
21
pipewire-0.3.80.tar.gz/src/modules/module-rtp-session.c -> pipewire-0.3.81.tar.gz/src/modules/module-rtp-session.c
Changed
11
1
2
if (spa_streq(service_name, "_pipewire-audio._udp")) {
3
uint32_t mask = 0;
4
for (l = txt; l && compatible; l = l->next) {
5
- char *key, *value, *k = NULL;
6
+ const char *k = NULL;
7
+ char *key, *value;
8
9
if (avahi_string_list_get_pair(l, &key, &value, NULL) != 0)
10
break;
11
pipewire-0.3.80.tar.gz/src/pipewire/conf.c -> pipewire-0.3.81.tar.gz/src/pipewire/conf.c
Changed
23
1
2
#ifdef HAVE_PWD_H
3
#include <pwd.h>
4
#endif
5
-#if defined(__FreeBSD__) || defined(__MidnightBSD__)
6
+#if defined(__FreeBSD__) || defined(__MidnightBSD__) || defined(__GNU__)
7
#ifndef O_PATH
8
#define O_PATH 0
9
#endif
10
11
char key256, val1024;
12
const char *str, *value;
13
int match = 0, fail = 0;
14
- int len, skip = 0;
15
+ int len;
16
17
while (spa_json_get_string(&it0, key, sizeof(key)) > 0) {
18
bool success = false;
19
+ int skip = 0;
20
21
if ((len = spa_json_next(&it0, &value)) <= 0)
22
break;
23
pipewire-0.3.80.tar.gz/src/pipewire/context.c -> pipewire-0.3.81.tar.gz/src/pipewire/context.c
Changed
145
1
2
struct spa_fraction latency = SPA_FRACTION(0, 0);
3
struct spa_fraction max_latency = SPA_FRACTION(0, 0);
4
struct spa_fraction rate = SPA_FRACTION(0, 0);
5
- uint32_t quantum, target_rate, current_rate;
6
+ uint32_t target_quantum, target_rate, current_rate, current_quantum;
7
uint64_t quantum_stamp = 0, rate_stamp = 0;
8
- bool force_rate, force_quantum, restore_rate = false;
9
+ bool force_rate, force_quantum, restore_rate = false, restore_quantum = false;
10
+ bool do_reconfigure = false, was_target_pending;
11
const uint32_t *node_rates;
12
uint32_t node_n_rates, node_def_rate;
13
uint32_t node_max_quantum, node_min_quantum, node_def_quantum, node_rate_quantum;
14
15
fraction_compare(&s->max_latency, &max_latency) < 0))
16
max_latency = s->max_latency;
17
18
- /* largest rate */
19
+ /* largest rate, which is in fact the smallest fraction */
20
if (rate.denom == 0 ||
21
(s->rate.denom > 0 &&
22
- fraction_compare(&s->rate, &rate) > 0))
23
+ fraction_compare(&s->rate, &rate) < 0))
24
rate = s->rate;
25
26
if (s->active)
27
28
pw_log_info("(%s-%u) restore rate", n->name, n->info.id);
29
restore_rate = true;
30
}
31
+ if (n->forced_quantum && !force_quantum && n->runnable) {
32
+ /* A node that was forced to a quantum but is no longer being
33
+ * forced can restore its quantum */
34
+ pw_log_info("(%s-%u) restore quantum", n->name, n->info.id);
35
+ restore_quantum = true;
36
+ }
37
38
if (force_quantum)
39
lock_quantum = false;
40
41
rate.denom, target_rate);
42
}
43
44
+ was_target_pending = n->target_pending;
45
+
46
if (target_rate != current_rate) {
47
- bool do_reconfigure = false;
48
/* we doing a rate switch */
49
pw_log_info("(%s-%u) state:%s new rate:%u/(%u)->%u",
50
n->name, n->info.id,
51
52
53
if (force_rate) {
54
if (settings->clock_rate_update_mode == CLOCK_RATE_UPDATE_MODE_HARD)
55
- do_reconfigure = !n->target_pending;
56
+ do_reconfigure |= !was_target_pending;
57
} else {
58
if (n->info.state >= PW_NODE_STATE_SUSPENDED)
59
- do_reconfigure = !n->target_pending;
60
+ do_reconfigure |= !was_target_pending;
61
}
62
- if (do_reconfigure)
63
- reconfigure_driver(context, n);
64
-
65
/* we're setting the pending rate. This will become the new
66
* current rate in the next iteration of the graph. */
67
n->target_rate = SPA_FRACTION(1, target_rate);
68
- n->target_pending = true;
69
n->forced_rate = force_rate;
70
+ n->target_pending = true;
71
current_rate = target_rate;
72
- /* we might be suspended now and the links need to be prepared again */
73
- if (do_reconfigure)
74
- goto again;
75
}
76
77
if (node_rate_quantum != 0 && current_rate != node_rate_quantum) {
78
79
node_max_quantum = tmp;
80
}
81
82
- quantum = node_def_quantum;
83
- if (latency.denom != 0)
84
- quantum = (latency.num * current_rate / latency.denom);
85
- quantum = SPA_CLAMP(quantum, node_min_quantum, node_max_quantum);
86
- quantum = SPA_MIN(quantum, lim_quantum);
87
-
88
- if (settings->clock_power_of_two_quantum)
89
- quantum = flp2(quantum);
90
+ current_quantum = n->target_quantum;
91
+ if (!restore_quantum &&
92
+ (lock_quantum || n->reconfigure || !running ||
93
+ (!force_quantum && (n->info.state > PW_NODE_STATE_IDLE))))
94
+ target_quantum = current_quantum;
95
+ else {
96
+ target_quantum = node_def_quantum;
97
+ if (latency.denom != 0)
98
+ target_quantum = (latency.num * current_rate / latency.denom);
99
+ target_quantum = SPA_CLAMP(target_quantum, node_min_quantum, node_max_quantum);
100
+ target_quantum = SPA_MIN(target_quantum, lim_quantum);
101
+
102
+ if (settings->clock_power_of_two_quantum)
103
+ target_quantum = flp2(target_quantum);
104
+ }
105
106
- if (running && quantum != n->target_quantum && !lock_quantum) {
107
+ if (target_quantum != current_quantum) {
108
pw_log_info("(%s-%u) new quantum:%"PRIu64"->%u",
109
n->name, n->info.id,
110
n->target_quantum,
111
- quantum);
112
+ target_quantum);
113
/* this is the new pending quantum */
114
- n->target_quantum = quantum;
115
+ n->target_quantum = target_quantum;
116
+ n->forced_quantum = force_quantum;
117
n->target_pending = true;
118
+
119
+ if (force_quantum)
120
+ do_reconfigure |= !was_target_pending;
121
}
122
123
if (n->target_pending) {
124
+ if (do_reconfigure) {
125
+ reconfigure_driver(context, n);
126
+ /* we might be suspended now and the links need to be prepared again */
127
+ goto again;
128
+ }
129
/* we have a pending change. We place the new values in the
130
* pending fields so that they are picked up by the driver in
131
* the next cycle */
132
133
n->target_rate = n->rt.position->clock.target_rate;
134
}
135
136
- pw_log_debug("%p: driver %p running:%d runnable:%d quantum:%u '%s'",
137
- context, n, running, n->runnable, quantum, n->name);
138
+ pw_log_debug("%p: driver %p running:%d runnable:%d quantum:%u rate:%u (%"PRIu64"/%u)'%s'",
139
+ context, n, running, n->runnable, target_quantum, target_rate,
140
+ n->rt.position->clock.target_duration,
141
+ n->rt.position->clock.target_rate.denom, n->name);
142
143
/* first change the node states of the followers to the new target */
144
spa_list_for_each(s, &n->follower_list, follower_link) {
145
pipewire-0.3.80.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.81.tar.gz/src/pipewire/impl-link.c
Changed
18
1
2
void pw_impl_link_destroy(struct pw_impl_link *link)
3
{
4
struct impl *impl = SPA_CONTAINER_OF(link, struct impl, this);
5
+ bool was_prepared = link->prepared;
6
7
pw_log_debug("%p: destroy", impl);
8
pw_log_info("(%s) destroy", link->name);
9
10
pw_global_destroy(link->global);
11
}
12
13
- if (link->prepared)
14
+ if (was_prepared)
15
pw_context_recalc_graph(link->context, "link destroy");
16
17
pw_log_debug("%p: free", impl);
18
pipewire-0.3.80.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.81.tar.gz/src/pipewire/impl-node.c
Changed
42
1
2
#include <unistd.h>
3
#include <errno.h>
4
#include <time.h>
5
+#include <malloc.h>
6
7
#include <spa/support/system.h>
8
#include <spa/pod/parser.h>
9
10
11
this->target_rate = SPA_FRACTION(1, rate);
12
this->target_quantum = quantum;
13
+ this->elapsed = 0;
14
15
pos->clock.rate = pos->clock.target_rate = this->target_rate;
16
pos->clock.duration = pos->clock.target_duration = this->target_quantum;
17
18
if (all_ready)
19
a->position.state = SPA_IO_POSITION_STATE_RUNNING;
20
}
21
- if (SPA_LIKELY(a->position.state != SPA_IO_POSITION_STATE_RUNNING))
22
- a->position.offset += a->position.clock.duration;
23
+ if (SPA_LIKELY(a->position.state == SPA_IO_POSITION_STATE_RUNNING))
24
+ node->elapsed += a->position.clock.duration;
25
+
26
+ a->position.offset = a->position.clock.position - node->elapsed;
27
}
28
29
/* Called from the data-loop and it is the starting point for driver nodes.
30
31
32
spa_system_close(node->data_system, node->source.fd);
33
free(impl);
34
+
35
+#ifdef HAVE_MALLOC_TRIM
36
+ int res = malloc_trim(0);
37
+ pw_log_debug("malloc_trim(): %d", res);
38
+#endif
39
}
40
41
SPA_EXPORT
42
pipewire-0.3.80.tar.gz/src/pipewire/mem.c -> pipewire-0.3.81.tar.gz/src/pipewire/mem.c
Changed
20
1
2
PW_LOG_TOPIC_EXTERN(log_mem);
3
#define PW_LOG_TOPIC_DEFAULT log_mem
4
5
-#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(HAVE_MEMFD_CREATE)
6
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(__GNU__) \
7
+ && !defined(HAVE_MEMFD_CREATE)
8
/*
9
* No glibc wrappers exist for memfd_create(2), so provide our own.
10
*
11
12
#define HAVE_MEMFD_CREATE 1
13
#endif
14
15
-#if defined(__FreeBSD__) || defined(__MidnightBSD__)
16
+#if defined(__FreeBSD__) || defined(__MidnightBSD__) || defined(__GNU__)
17
#define MAP_LOCKED 0
18
#endif
19
20
pipewire-0.3.80.tar.gz/src/pipewire/pipewire.c -> pipewire-0.3.81.tar.gz/src/pipewire/pipewire.c
Changed
28
1
2
#include <unistd.h>
3
#include <limits.h>
4
#include <stdio.h>
5
-#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
6
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(__GNU__)
7
#include <sys/prctl.h>
8
#endif
9
#include <pwd.h>
10
11
static char namePATH_MAX;
12
13
spa_memzero(name, sizeof(name));
14
-#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__MidnightBSD_kernel__)
15
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__MidnightBSD_kernel__) || defined(__GNU__)
16
{
17
if (readlink("/proc/self/exe", name, sizeof(name)-1) > 0) {
18
prgname = strrchr(name, '/') + 1;
19
20
}
21
}
22
#endif
23
-#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
24
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(__GNU__)
25
{
26
if (prctl(PR_GET_NAME, (unsigned long) name, 0, 0, 0) == 0) {
27
prgname = name;
28
pipewire-0.3.80.tar.gz/src/pipewire/private.h -> pipewire-0.3.81.tar.gz/src/pipewire/private.h
Changed
26
1
2
#include <spa/utils/result.h>
3
#include <spa/utils/type-info.h>
4
5
-#if defined(__FreeBSD__) || defined(__MidnightBSD__)
6
+#if defined(__FreeBSD__) || defined(__MidnightBSD__) || defined(__GNU__)
7
struct ucred {
8
};
9
#endif
10
11
unsigned int suspend_on_idle:1;
12
unsigned int reconfigure:1;
13
unsigned int forced_rate:1;
14
+ unsigned int forced_quantum:1;
15
unsigned int trigger:1; /**< has the TRIGGER property and needs an extra
16
* trigger to start processing. */
17
unsigned int can_suspend:1;
18
19
uint64_t target_quantum;
20
21
uint64_t driver_start;
22
+ uint64_t elapsed; /* elapsed time in playing */
23
24
void *user_data; /**< extra user data */
25
};
26
pipewire-0.3.80.tar.gz/src/pipewire/stream.c -> pipewire-0.3.81.tar.gz/src/pipewire/stream.c
Changed
35
1
2
unsigned int driving:1;
3
unsigned int using_trigger:1;
4
unsigned int trigger:1;
5
+ unsigned int early_process:1;
6
int in_set_param;
7
int in_emit_param_changed;
8
};
9
10
* rate matching node (audioconvert) has been scheduled to
11
* update the values. */
12
ask_more = !impl->process_rt && impl->rate_match == NULL &&
13
- queue_is_empty(impl, &impl->queued) &&
14
+ (impl->early_process || queue_is_empty(impl, &impl->queued)) &&
15
!queue_is_empty(impl, &impl->dequeued);
16
pw_log_trace_fp("%p: pop %d %p ask_more:%u %p", stream, b->id, io,
17
ask_more, impl->rate_match);
18
19
}
20
} else {
21
ask_more = !impl->process_rt &&
22
- queue_is_empty(impl, &impl->queued) &&
23
+ (impl->early_process || queue_is_empty(impl, &impl->queued)) &&
24
!queue_is_empty(impl, &impl->dequeued);
25
}
26
27
28
impl->node_methods.process = impl_node_process_output;
29
30
impl->process_rt = SPA_FLAG_IS_SET(flags, PW_STREAM_FLAG_RT_PROCESS);
31
+ impl->early_process = SPA_FLAG_IS_SET(flags, PW_STREAM_FLAG_EARLY_PROCESS);
32
33
impl->impl_node.iface = SPA_INTERFACE_INIT(
34
SPA_TYPE_INTERFACE_Node,
35
pipewire-0.3.80.tar.gz/src/pipewire/stream.h -> pipewire-0.3.81.tar.gz/src/pipewire/stream.h
Changed
13
1
2
* does a trigger_process() that will then
3
* dequeue/queue a buffer from another process()
4
* function. since 0.3.73 */
5
+ PW_STREAM_FLAG_EARLY_PROCESS = (1 << 11), /**< Call process as soon as there is a buffer
6
+ * to dequeue. This is only relevant for
7
+ * playback and when not using RT_PROCESS. It
8
+ * can be used to keep the maximum number of
9
+ * buffers queued. Since 0.3.81 */
10
};
11
12
/** Create a new unconneced \ref pw_stream
13
pipewire-0.3.80.tar.gz/src/pipewire/thread.c -> pipewire-0.3.81.tar.gz/src/pipewire/thread.c
Changed
11
1
2
}
3
#endif
4
#endif
5
+#if defined(__GNU__)
6
+int pthread_setname_np(pthread_t thread, const char *name) { return 0; }
7
+#endif
8
9
static struct spa_thread *impl_create(void *object,
10
const struct spa_dict *props,
11
pipewire-0.3.80.tar.gz/src/pipewire/utils.h -> pipewire-0.3.81.tar.gz/src/pipewire/utils.h
Changed
9
1
2
#ifndef _POSIX_C_SOURCE
3
# include <sys/mount.h>
4
#endif
5
+#include <errno.h>
6
7
#ifndef ENODATA
8
#define ENODATA 9919
9
pipewire-0.3.81.tar.gz/src/tools/dfffile.c
Added
315
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <errno.h>
7
+#include <sys/mman.h>
8
+#include <sys/stat.h>
9
+#include <unistd.h>
10
+#include <fcntl.h>
11
+#include <math.h>
12
+
13
+#include <spa/utils/string.h>
14
+#include <spa/debug/mem.h>
15
+
16
+#include "dfffile.h"
17
+
18
+struct dff_file {
19
+ uint8_t *data;
20
+ size_t size;
21
+
22
+ int mode;
23
+ int fd;
24
+
25
+ struct dff_file_info info;
26
+
27
+ uint8_t *p;
28
+ size_t offset;
29
+};
30
+
31
+struct dff_chunk {
32
+ uint32_t id;
33
+ uint64_t size;
34
+ void *data;
35
+};
36
+
37
+#define FOURCC(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
38
+
39
+static inline uint16_t parse_be16(const uint8_t *in)
40
+{
41
+ return (in0 << 8) | in1;
42
+}
43
+static inline uint32_t parse_be32(const uint8_t *in)
44
+{
45
+ return FOURCC(in0, in1, in2, in3);
46
+}
47
+
48
+static inline uint64_t parse_be64(const uint8_t *in)
49
+{
50
+ uint64_t res = in7;
51
+ res |= ((uint64_t)in6) << 8;
52
+ res |= ((uint64_t)in5) << 16;
53
+ res |= ((uint64_t)in4) << 24;
54
+ res |= ((uint64_t)in3) << 32;
55
+ res |= ((uint64_t)in2) << 40;
56
+ res |= ((uint64_t)in1) << 48;
57
+ res |= ((uint64_t)in0) << 56;
58
+ return res;
59
+}
60
+
61
+static inline int f_avail(struct dff_file *f)
62
+{
63
+ if (f->p < f->data + f->size)
64
+ return f->size + f->data - f->p;
65
+ return 0;
66
+}
67
+
68
+static int read_chunk(struct dff_file *f, struct dff_chunk *c)
69
+{
70
+ if (f_avail(f) < 12)
71
+ return -ENOSPC;
72
+
73
+ c->id = parse_be32(f->p); /* id of this chunk */
74
+ c->size = parse_be64(f->p + 4); /* size of this chunk */
75
+ f->p += 12;
76
+ c->data = f->p;
77
+ return 0;
78
+}
79
+
80
+static int skip_chunk(struct dff_file *f, const struct dff_chunk *c)
81
+{
82
+ f->p = SPA_PTROFF(c->data, c->size, uint8_t);
83
+ return 0;
84
+}
85
+
86
+static int read_PROP(struct dff_file *f, struct dff_chunk *prop)
87
+{
88
+ struct dff_chunk c1;
89
+ int res;
90
+
91
+ if (f_avail(f) < 4 ||
92
+ memcmp(prop->data, "SND ", 4) != 0)
93
+ return -EINVAL;
94
+ f->p += 4;
95
+
96
+ while (f->p < SPA_PTROFF(prop->data, prop->size, uint8_t)) {
97
+ if ((res = read_chunk(f, &c0)) < 0)
98
+ return res;
99
+
100
+ switch (c0.id) {
101
+ case FOURCC('F', 'S', ' ', ' '):
102
+ f->info.rate = parse_be32(f->p);
103
+ break;
104
+ case FOURCC('C', 'H', 'N', 'L'):
105
+ f->info.channels = parse_be16(f->p);
106
+ switch (f->info.channels) {
107
+ case 2:
108
+ f->info.channel_type = 2;
109
+ break;
110
+ case 5:
111
+ f->info.channel_type = 6;
112
+ break;
113
+ case 6:
114
+ f->info.channel_type = 7;
115
+ break;
116
+ }
117
+ break;
118
+ case FOURCC('C', 'M', 'P', 'R'):
119
+ {
120
+ uint32_t cmpr = parse_be32(f->p);
121
+ if (cmpr != FOURCC('D', 'S', 'D', ' '))
122
+ return -ENOTSUP;
123
+ break;
124
+ }
125
+ case FOURCC('A', 'B', 'S', 'S'):
126
+ break;
127
+ case FOURCC('L', 'S', 'C', 'O'):
128
+ break;
129
+ default:
130
+ break;
131
+ }
132
+ skip_chunk(f, &c0);
133
+ }
134
+ return 0;
135
+}
136
+
137
+static int read_FRM8(struct dff_file *f)
138
+{
139
+ struct dff_chunk c2;
140
+ int res;
141
+ bool found_dsd = false;
142
+
143
+ if ((res = read_chunk(f, &c0)) < 0)
144
+ return res;
145
+ if (c0.id != FOURCC('F','R','M','8'))
146
+ return -EINVAL;
147
+ if (f_avail(f) < 4 ||
148
+ memcmp(c0.data, "DSD ", 4) != 0)
149
+ return -EINVAL;
150
+ f->p += 4;
151
+
152
+ while (true) {
153
+ if ((res = read_chunk(f, &c1)) < 0)
154
+ return res;
155
+
156
+ switch (c1.id) {
157
+ case FOURCC('F', 'V', 'E', 'R'):
158
+ break;
159
+ case FOURCC('P', 'R', 'O', 'P'):
160
+ read_PROP(f, &c1);
161
+ break;
162
+ case FOURCC('D', 'S', 'D', ' '):
163
+ {
164
+ f->info.length = c1.size;
165
+ f->info.samples = c1.size / f->info.channels;
166
+ f->info.lsb = 0;
167
+ f->info.blocksize = 1;
168
+ found_dsd = true;
169
+ break;
170
+ }
171
+ default:
172
+ break;
173
+ }
174
+ if (found_dsd)
175
+ break;
176
+
177
+ skip_chunk(f, &c1);
178
+ }
179
+ return 0;
180
+}
181
+
182
+static int open_read(struct dff_file *f, const char *filename, struct dff_file_info *info)
183
+{
184
+ int res;
185
+ struct stat st;
186
+
187
+ if ((f->fd = open(filename, O_RDONLY)) < 0) {
188
+ res = -errno;
189
+ goto exit;
190
+ }
191
+ if (fstat(f->fd, &st) < 0) {
192
+ res = -errno;
193
+ goto exit_close;
194
+ }
195
+ f->size = st.st_size;
196
+
197
+ f->data = mmap(NULL, f->size, PROT_READ, MAP_SHARED, f->fd, 0);
198
+ if (f->data == MAP_FAILED) {
199
+ res = -errno;
200
+ goto exit_close;
201
+ }
202
+
203
+ f->p = f->data;
204
+
205
+ if ((res = read_FRM8(f)) < 0)
206
+ goto exit_unmap;
207
+
208
+ f->mode = 1;
209
+ *info = f->info;
210
+ return 0;
211
+
212
+exit_unmap:
213
+ munmap(f->data, f->size);
214
+exit_close:
215
+ close(f->fd);
216
+exit:
217
+ return res;
218
+}
219
+
220
+struct dff_file *
221
+dff_file_open(const char *filename, const char *mode, struct dff_file_info *info)
222
+{
223
+ int res;
224
+ struct dff_file *f;
225
+
226
+ f = calloc(1, sizeof(struct dff_file));
227
+ if (f == NULL)
228
+ return NULL;
229
+
230
+ if (spa_streq(mode, "r")) {
231
+ if ((res = open_read(f, filename, info)) < 0)
232
+ goto exit_free;
233
+ } else {
234
+ res = -EINVAL;
235
+ goto exit_free;
236
+ }
237
+ return f;
238
+
239
+exit_free:
240
+ free(f);
241
+ errno = -res;
242
+ return NULL;
243
+}
244
+
245
+static const uint8_t bitrev256 = {
246
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
247
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
248
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
249
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
250
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
251
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
252
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
253
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
254
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
255
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
256
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
257
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
258
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
259
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
260
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
261
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
262
+};
263
+
264
+ssize_t
265
+dff_file_read(struct dff_file *f, void *data, size_t samples, const struct dff_layout *layout)
266
+{
267
+ uint8_t *d = data;
268
+ int32_t step = SPA_ABS(layout->interleave);
269
+ uint32_t channels = f->info.channels;
270
+ bool rev = layout->lsb != f->info.lsb;
271
+ size_t total, offset, scale;
272
+
273
+ offset = f->offset;
274
+ scale = SPA_CLAMP(f->info.rate / (44100u * 64u), 1u, 4u);
275
+
276
+ samples *= step;
277
+ samples *= scale;
278
+
279
+ for (total = 0; total < samples && offset < f->info.length; total++) {
280
+ uint32_t i;
281
+ int32_t j;
282
+ const uint8_t *s = f->p + offset;
283
+
284
+ for (i = 0; i < layout->channels; i++) {
285
+ if (layout->interleave > 0) {
286
+ for (j = 0; j < step; j++)
287
+ *d++ = rev ?
288
+ bitrevsj * channels + i :
289
+ sj * channels + i;
290
+ } else {
291
+ for (j = step-1; j >= 0; j--)
292
+ *d++ = rev ?
293
+ bitrevsj * channels + i :
294
+ sj * channels + i;
295
+ }
296
+ }
297
+ offset += step * channels;
298
+ }
299
+ f->offset = offset;
300
+
301
+ return total;
302
+}
303
+
304
+int dff_file_close(struct dff_file *f)
305
+{
306
+ if (f->mode == 1) {
307
+ munmap(f->data, f->size);
308
+ } else
309
+ return -EINVAL;
310
+
311
+ close(f->fd);
312
+ free(f);
313
+ return 0;
314
+}
315
pipewire-0.3.81.tar.gz/src/tools/dfffile.h
Added
33
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <stdio.h>
7
+
8
+#include <spa/utils/defs.h>
9
+
10
+struct dff_file;
11
+
12
+struct dff_file_info {
13
+ uint32_t channel_type;
14
+ uint32_t channels;
15
+ uint32_t rate;
16
+ bool lsb;
17
+ uint64_t samples;
18
+ uint64_t length;
19
+ uint32_t blocksize;
20
+};
21
+
22
+struct dff_layout {
23
+ int32_t interleave;
24
+ uint32_t channels;
25
+ bool lsb;
26
+};
27
+
28
+struct dff_file * dff_file_open(const char *filename, const char *mode, struct dff_file_info *info);
29
+
30
+ssize_t dff_file_read(struct dff_file *f, void *data, size_t samples, const struct dff_layout *layout);
31
+
32
+int dff_file_close(struct dff_file *f);
33
pipewire-0.3.80.tar.gz/src/tools/meson.build -> pipewire-0.3.81.tar.gz/src/tools/meson.build
Changed
9
1
2
pwcat_sources =
3
'pw-cat.c',
4
'midifile.c',
5
+ 'dfffile.c',
6
'dsffile.c',
7
8
9
pipewire-0.3.80.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.81.tar.gz/src/tools/pw-cat.c
Changed
130
1
2
#endif
3
4
#include "midifile.h"
5
+#include "dfffile.h"
6
#include "dsffile.h"
7
8
#define DEFAULT_MEDIA_TYPE "Audio"
9
10
struct dsf_file_info info;
11
struct dsf_layout layout;
12
} dsf;
13
+ struct {
14
+ struct dff_file *file;
15
+ struct dff_file_info info;
16
+ struct dff_layout layout;
17
+ } dff;
18
19
#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
20
struct {
21
22
data->dsf.layout.channels = info.info.dsd.channels;
23
data->dsf.layout.lsb = info.info.dsd.bitorder == SPA_PARAM_BITORDER_lsb;
24
25
+ data->dff.layout.interleave = info.info.dsd.interleave,
26
+ data->dff.layout.channels = info.info.dsd.channels;
27
+ data->dff.layout.lsb = info.info.dsd.bitorder == SPA_PARAM_BITORDER_lsb;
28
+
29
data->stride = data->dsf.layout.channels * SPA_ABS(data->dsf.layout.interleave);
30
31
if (data->verbose) {
32
33
return dsf_file_read(d->dsf.file, src, n_frames, &d->dsf.layout);
34
}
35
36
-static int setup_dsffile(struct data *data)
37
+static int dff_play(struct data *d, void *src, unsigned int n_frames, bool *null_frame)
38
+{
39
+ return dff_file_read(d->dff.file, src, n_frames, &d->dff.layout);
40
+}
41
+
42
+static int setup_dsdfile(struct data *data)
43
{
44
if (data->mode == mode_record)
45
return -ENOTSUP;
46
47
data->dsf.file = dsf_file_open(data->filename, "r", &data->dsf.info);
48
if (data->dsf.file == NULL) {
49
- fprintf(stderr, "dsffile: can't read dsf file '%s': %m\n", data->filename);
50
- return -errno;
51
+ data->dff.file = dff_file_open(data->filename, "r", &data->dff.info);
52
+ if (data->dff.file == NULL) {
53
+ fprintf(stderr, "dsdfile: can't read dsd file '%s': %m\n", data->filename);
54
+ return -errno;
55
+ }
56
}
57
58
- if (data->verbose)
59
- printf("dsffile: opened file \"%s\" channels:%d rate:%d samples:%"PRIu64" bitorder:%s\n",
60
+ if (data->dsf.file != NULL) {
61
+ if (data->verbose)
62
+ printf("dsffile: opened file \"%s\" channels:%d rate:%d "
63
+ "samples:%"PRIu64" bitorder:%s\n",
64
data->filename,
65
data->dsf.info.channels, data->dsf.info.rate,
66
data->dsf.info.samples,
67
data->dsf.info.lsb ? "lsb" : "msb");
68
69
- data->fill = dsf_play;
70
+ data->fill = dsf_play;
71
+ } else {
72
+ if (data->verbose)
73
+ printf("dfffile: opened file \"%s\" channels:%d rate:%d "
74
+ "samples:%"PRIu64" bitorder:%s\n",
75
+ data->filename,
76
+ data->dff.info.channels, data->dff.info.rate,
77
+ data->dff.info.samples,
78
+ data->dff.info.lsb ? "lsb" : "msb");
79
80
+ data->fill = dff_play;
81
+ }
82
return 0;
83
}
84
85
86
ret = setup_midifile(&data);
87
break;
88
case TYPE_DSD:
89
- ret = setup_dsffile(&data);
90
+ ret = setup_dsdfile(&data);
91
break;
92
#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
93
case TYPE_ENCODED:
94
95
case TYPE_DSD:
96
{
97
struct spa_audio_info_dsd info;
98
+ uint32_t channel_type;
99
100
spa_zero(info);
101
- info.channels = data.dsf.info.channels;
102
- info.rate = data.dsf.info.rate / 8;
103
+ if (data.dsf.file != NULL) {
104
+ info.channels = data.dsf.info.channels;
105
+ info.rate = data.dsf.info.rate / 8;
106
+ channel_type = data.dsf.info.channel_type;
107
+ } else {
108
+ info.channels = data.dff.info.channels;
109
+ info.rate = data.dff.info.rate / 8;
110
+ channel_type = data.dff.info.channel_type;
111
+ }
112
113
SPA_FOR_EACH_ELEMENT_VAR(dsd_layouts, i) {
114
- if (i->type != data.dsf.info.channel_type)
115
+ if (i->type != channel_type)
116
continue;
117
info.channels = i->info.n_channels;
118
memcpy(info.position, i->info.position,
119
120
sf_close(data.file);
121
if (data.midi.file)
122
midi_file_close(data.midi.file);
123
+ if (data.dsf.file)
124
+ dsf_file_close(data.dsf.file);
125
+ if (data.dff.file)
126
+ dff_file_close(data.dff.file);
127
#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
128
if (data.encoded.packet)
129
av_packet_free(&data.encoded.packet);
130
pipewire-0.3.80.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.81.tar.gz/src/tools/pw-cli.c
Changed
250
1
2
bool ret;
3
4
global = calloc(1, sizeof(struct global));
5
+ if (global == NULL) {
6
+ fprintf(stderr, "Allocation failed: %m");
7
+ return;
8
+ }
9
global->rd = rd;
10
global->id = id;
11
global->permissions = permissions;
12
13
struct pw_core_info *info = pd->info;
14
15
info_global(pd);
16
+ if (info == NULL)
17
+ return;
18
printf("\tcookie: %u\n", info->cookie);
19
printf("\tuser-name: \"%s\"\n", info->user_name);
20
printf("\thost-name: \"%s\"\n", info->host_name);
21
22
struct pw_module_info *info = pd->info;
23
24
info_global(pd);
25
+ if (info == NULL)
26
+ return;
27
printf("\tname: \"%s\"\n", info->name);
28
printf("\tfilename: \"%s\"\n", info->filename);
29
printf("\targs: \"%s\"\n", info->args);
30
31
struct pw_node_info *info = pd->info;
32
33
info_global(pd);
34
+ if (info == NULL)
35
+ return;
36
printf("%c\tinput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS),
37
info->n_input_ports, info->max_input_ports);
38
printf("%c\toutput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS),
39
40
struct pw_port_info *info = pd->info;
41
42
info_global(pd);
43
+ if (info == NULL)
44
+ return;
45
printf("\tdirection: \"%s\"\n", pw_direction_as_string(info->direction));
46
print_properties(info->props, MARK_CHANGE(PW_PORT_CHANGE_MASK_PROPS), true);
47
print_params(info->params, info->n_params, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS), true);
48
49
struct pw_factory_info *info = pd->info;
50
51
info_global(pd);
52
+ if (info == NULL)
53
+ return;
54
printf("\tname: \"%s\"\n", info->name);
55
printf("\tobject-type: %s/%d\n", info->type, info->version);
56
print_properties(info->props, MARK_CHANGE(PW_FACTORY_CHANGE_MASK_PROPS), true);
57
58
struct pw_client_info *info = pd->info;
59
60
info_global(pd);
61
+ if (info == NULL)
62
+ return;
63
print_properties(info->props, MARK_CHANGE(PW_CLIENT_CHANGE_MASK_PROPS), true);
64
info->change_mask = 0;
65
}
66
67
struct pw_link_info *info = pd->info;
68
69
info_global(pd);
70
+ if (info == NULL)
71
+ return;
72
printf("\toutput-node-id: %u\n", info->output_node_id);
73
printf("\toutput-port-id: %u\n", info->output_port_id);
74
printf("\tinput-node-id: %u\n", info->input_node_id);
75
76
struct pw_device_info *info = pd->info;
77
78
info_global(pd);
79
+ if (info == NULL)
80
+ return;
81
print_properties(info->props, MARK_CHANGE(PW_DEVICE_CHANGE_MASK_PROPS), true);
82
print_params(info->params, info->n_params, MARK_CHANGE(PW_DEVICE_CHANGE_MASK_PARAMS), true);
83
info->change_mask = 0;
84
85
struct pw_session_info *info = pd->info;
86
87
info_global(pd);
88
+ if (info == NULL)
89
+ return;
90
print_properties(info->props, MARK_CHANGE(0), true);
91
print_params(info->params, info->n_params, MARK_CHANGE(1), true);
92
info->change_mask = 0;
93
94
const char *direction;
95
96
info_global(pd);
97
+ if (info == NULL)
98
+ return;
99
printf("\tname: %s\n", info->name);
100
printf("\tmedia-class: %s\n", info->media_class);
101
switch(info->direction) {
102
103
struct pw_endpoint_stream_info *info = pd->info;
104
105
info_global(pd);
106
+ if (info == NULL)
107
+ return;
108
printf("\tid: %u\n", info->id);
109
printf("\tendpoint-id: %u\n", info->endpoint_id);
110
printf("\tname: %s\n", info->name);
111
112
struct remote_data *rd = pd->rd;
113
struct pw_session_info *info = pd->info;
114
115
- if (!info) {
116
+ if (info == NULL)
117
info = pd->info = calloc(1, sizeof(*info));
118
+ if (info != NULL) {
119
info->id = update->id;
120
+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
121
+ info->n_params = update->n_params;
122
+ free(info->params);
123
+ info->params = malloc(info->n_params * sizeof(struct spa_param_info));
124
+ memcpy(info->params, update->params,
125
+ info->n_params * sizeof(struct spa_param_info));
126
+ }
127
+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
128
+ pw_properties_free ((struct pw_properties *)info->props);
129
+ info->props =
130
+ (struct spa_dict *) pw_properties_new_dict (update->props);
131
+ }
132
}
133
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
134
- info->n_params = update->n_params;
135
- free(info->params);
136
- info->params = malloc(info->n_params * sizeof(struct spa_param_info));
137
- memcpy(info->params, update->params,
138
- info->n_params * sizeof(struct spa_param_info));
139
- }
140
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
141
- pw_properties_free ((struct pw_properties *)info->props);
142
- info->props =
143
- (struct spa_dict *) pw_properties_new_dict (update->props);
144
- }
145
-
146
if (pd->global == NULL)
147
- pd->global = pw_map_lookup(&rd->globals, info->id);
148
+ pd->global = pw_map_lookup(&rd->globals, update->id);
149
if (pd->global && pd->global->info_pending) {
150
info_session(pd);
151
pd->global->info_pending = false;
152
153
struct remote_data *rd = pd->rd;
154
struct pw_endpoint_info *info = pd->info;
155
156
- if (!info) {
157
+ if (info == NULL)
158
info = pd->info = calloc(1, sizeof(*info));
159
+ if (info != NULL) {
160
info->id = update->id;
161
info->name = update->name ? strdup(update->name) : NULL;
162
info->media_class = update->media_class ? strdup(update->media_class) : NULL;
163
info->direction = update->direction;
164
info->flags = update->flags;
165
- }
166
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_STREAMS)
167
- info->n_streams = update->n_streams;
168
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION)
169
- info->session_id = update->session_id;
170
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
171
- info->n_params = update->n_params;
172
- free(info->params);
173
- info->params = malloc(info->n_params * sizeof(struct spa_param_info));
174
- memcpy(info->params, update->params,
175
- info->n_params * sizeof(struct spa_param_info));
176
- }
177
- if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
178
- pw_properties_free ((struct pw_properties *)info->props);
179
- info->props =
180
- (struct spa_dict *) pw_properties_new_dict (update->props);
181
- }
182
183
+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_STREAMS)
184
+ info->n_streams = update->n_streams;
185
+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION)
186
+ info->session_id = update->session_id;
187
+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
188
+ info->n_params = update->n_params;
189
+ free(info->params);
190
+ info->params = malloc(info->n_params * sizeof(struct spa_param_info));
191
+ memcpy(info->params, update->params,
192
+ info->n_params * sizeof(struct spa_param_info));
193
+ }
194
+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
195
+ pw_properties_free ((struct pw_properties *)info->props);
196
+ info->props =
197
+ (struct spa_dict *) pw_properties_new_dict (update->props);
198
+ }
199
+ }
200
if (pd->global == NULL)
201
- pd->global = pw_map_lookup(&rd->globals, info->id);
202
+ pd->global = pw_map_lookup(&rd->globals, update->id);
203
if (pd->global && pd->global->info_pending) {
204
info_endpoint(pd);
205
pd->global->info_pending = false;
206
207
struct remote_data *rd = pd->rd;
208
struct pw_endpoint_stream_info *info = pd->info;
209
210
- if (!info) {
211
+ if (info == NULL)
212
info = pd->info = calloc(1, sizeof(*info));
213
+ if (info != NULL) {
214
info->id = update->id;
215
info->endpoint_id = update->endpoint_id;
216
info->name = update->name ? strdup(update->name) : NULL;
217
- }
218
- if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PARAMS) {
219
- info->n_params = update->n_params;
220
- free(info->params);
221
- info->params = malloc(info->n_params * sizeof(struct spa_param_info));
222
- memcpy(info->params, update->params,
223
- info->n_params * sizeof(struct spa_param_info));
224
- }
225
- if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS) {
226
- pw_properties_free ((struct pw_properties *)info->props);
227
- info->props =
228
- (struct spa_dict *) pw_properties_new_dict (update->props);
229
- }
230
231
+ if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PARAMS) {
232
+ info->n_params = update->n_params;
233
+ free(info->params);
234
+ info->params = malloc(info->n_params * sizeof(struct spa_param_info));
235
+ memcpy(info->params, update->params,
236
+ info->n_params * sizeof(struct spa_param_info));
237
+ }
238
+ if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS) {
239
+ pw_properties_free ((struct pw_properties *)info->props);
240
+ info->props =
241
+ (struct spa_dict *) pw_properties_new_dict (update->props);
242
+ }
243
+ }
244
if (pd->global == NULL)
245
- pd->global = pw_map_lookup(&rd->globals, info->id);
246
+ pd->global = pw_map_lookup(&rd->globals, update->id);
247
if (pd->global && pd->global->info_pending) {
248
info_endpoint_stream(pd);
249
pd->global->info_pending = false;
250
pipewire-0.3.80.tar.gz/src/tools/pw-link.c -> pipewire-0.3.81.tar.gz/src/tools/pw-link.c
Changed
12
1
2
static void print_port(struct data *data, const char *prefix, struct object *n,
3
struct object *p, bool verbose)
4
{
5
- char buffer1024, id64 = "", *prefix2 = "";
6
+ char buffer1024, id64 = "";
7
+ const char *prefix2 = "";
8
+
9
if (data->opt_id) {
10
snprintf(id, sizeof(id), "%4d ", p->id);
11
prefix2 = " ";
12
pipewire-0.3.80.tar.gz/test/pwtest.c -> pipewire-0.3.81.tar.gz/test/pwtest.c
Changed
10
1
2
time_t t = time(NULL);
3
struct tm *tm = localtime(&t);
4
char *dir;
5
- char *tmpdir = getenv("TMPDIR");
6
+ const char *tmpdir = getenv("TMPDIR");
7
char pathPATH_MAX;
8
FILE *fp;
9
10
pipewire-0.3.80.tar.gz/test/test-logger.c -> pipewire-0.3.81.tar.gz/test/test-logger.c
Changed
19
1
2
enum spa_log_level level = pwtest_get_iteration(current_test);
3
enum spa_log_level default_level = pw_log_level;
4
struct spa_log *default_logger = pw_log_get();
5
- char *lvl = NULL;
6
+ const char *lvl = NULL;
7
char *oldenv = getenv("PIPEWIRE_DEBUG");
8
9
if (oldenv)
10
11
struct spa_log *default_logger = pw_log_get();
12
char *oldenv = getenv("PIPEWIRE_DEBUG");
13
char lvlstr32;
14
- char *lvl = "X";
15
+ const char *lvl = "X";
16
17
if (oldenv)
18
oldenv = strdup(oldenv);
19
pipewire-0.3.80.tar.gz/test/test-spa-json.c -> pipewire-0.3.81.tar.gz/test/test-spa-json.c
Changed
29
1
2
return PWTEST_PASS;
3
}
4
5
-static void test_array(char *str, char **vals)
6
+static void test_array(const char *str, const char * const vals)
7
{
8
struct spa_json it2;
9
char val256;
10
11
12
PWTEST(json_array)
13
{
14
- test_array("FL,FR", (char *){ "FL", "FR", NULL });
15
- test_array(" FL , FR ", (char *){ "FL", "FR", NULL });
16
- test_array(" FL , FR ", (char *){ "FL", "FR", NULL });
17
- test_array("FL FR", (char *){ "FL", "FR", NULL });
18
- test_array("FL FR", (char *){ "FL", "FR", NULL });
19
- test_array(" FL FR ", (char *){ "FL", "FR", NULL });
20
+ test_array("FL,FR", (const char *){ "FL", "FR", NULL });
21
+ test_array(" FL , FR ", (const char *){ "FL", "FR", NULL });
22
+ test_array(" FL , FR ", (const char *){ "FL", "FR", NULL });
23
+ test_array("FL FR", (const char *){ "FL", "FR", NULL });
24
+ test_array("FL FR", (const char *){ "FL", "FR", NULL });
25
+ test_array(" FL FR ", (const char *){ "FL", "FR", NULL });
26
27
return PWTEST_PASS;
28
}
29
Refresh
No build results available
Refresh
No rpmlint results available
Login required, please
login
or
signup
in order to comment