Changes of Revision 4

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,14 @@
2
 -------------------------------------------------------------------
3
+Fri Feb 18 14:59:46 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.47
6
+
7
+-------------------------------------------------------------------
8
+Thu Feb 17 13:55:01 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
9
+
10
+- Update to version 0.3.46
11
+
12
+-------------------------------------------------------------------
13
 Fri Feb  4 06:41:51 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
14
 
15
 - Update to version 0.3.45
16
pipewire-aptx.spec Changed
10
 
1
@@ -7,7 +7,7 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        0.3.45
6
+Version:        0.3.47
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
pipewire-0.3.45.tar.gz/pipewire-jack/src/match-rules.c Deleted
143
 
1
@@ -1,141 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2021 Wim Taymans
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a
7
- * copy of this software and associated documentation files (the "Software"),
8
- * to deal in the Software without restriction, including without limitation
9
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
- * and/or sell copies of the Software, and to permit persons to whom the
11
- * Software is furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice (including the next
14
- * paragraph) shall be included in all copies or substantial portions of the
15
- * Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
- * DEALINGS IN THE SOFTWARE.
24
- */
25
-
26
-#include <string.h>
27
-#include <stdio.h>
28
-#include <errno.h>
29
-#include <math.h>
30
-#include <time.h>
31
-#include <regex.h>
32
-
33
-#include "config.h"
34
-
35
-#include <spa/utils/json.h>
36
-#include <spa/utils/string.h>
37
-
38
-#include <pipewire/pipewire.h>
39
-
40
-static bool find_match(struct spa_json *arr, const struct spa_dict *props)
41
-{
42
-   struct spa_json it[1];
43
-
44
-   while (spa_json_enter_object(arr, &it[0]) > 0) {
45
-       char key[256], val[1024];
46
-       const char *str, *value;
47
-       int match = 0, fail = 0;
48
-       int len;
49
-
50
-       while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
51
-           bool success = false;
52
-
53
-           if ((len = spa_json_next(&it[0], &value)) <= 0)
54
-               break;
55
-
56
-           str = spa_dict_lookup(props, key);
57
-
58
-           if (spa_json_is_null(value, len)) {
59
-               success = str == NULL;
60
-           } else {
61
-               if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
62
-                   continue;
63
-               value = val;
64
-               len = strlen(val);
65
-           }
66
-           if (str != NULL) {
67
-               if (value[0] == '~') {
68
-                   regex_t preg;
69
-                   if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
70
-                       if (regexec(&preg, str, 0, NULL, 0) == 0)
71
-                           success = true;
72
-                       regfree(&preg);
73
-                   }
74
-               } else if (strncmp(str, value, len) == 0 &&
75
-                   strlen(str) == (size_t)len) {
76
-                   success = true;
77
-               }
78
-           }
79
-           if (success) {
80
-               match++;
81
-               pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
82
-           }
83
-           else
84
-               fail++;
85
-       }
86
-       if (match > 0 && fail == 0)
87
-           return true;
88
-   }
89
-   return false;
90
-}
91
-
92
-int pw_jack_match_rules(const char *rules, size_t size, const struct spa_dict *props,
93
-       int (*matched) (void *data, const char *action, const char *val, size_t len),
94
-       void *data)
95
-{
96
-   const char *val;
97
-   struct spa_json it[4], actions;
98
-   int count = 0;
99
-
100
-   spa_json_init(&it[0], rules, size);
101
-   if (spa_json_enter_array(&it[0], &it[1]) < 0)
102
-       return 0;
103
-
104
-   while (spa_json_enter_object(&it[1], &it[2]) > 0) {
105
-       char key[64];
106
-       bool have_match = false, have_actions = false;
107
-
108
-       while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
109
-           if (spa_streq(key, "matches")) {
110
-               if (spa_json_enter_array(&it[2], &it[3]) < 0)
111
-                   break;
112
-
113
-               have_match = find_match(&it[3], props);
114
-           }
115
-           else if (spa_streq(key, "actions")) {
116
-               if (spa_json_enter_object(&it[2], &actions) > 0)
117
-                   have_actions = true;
118
-           }
119
-           else if (spa_json_next(&it[2], &val) <= 0)
120
-                                break;
121
-       }
122
-       if (!have_match || !have_actions)
123
-           continue;
124
-
125
-       while (spa_json_get_string(&actions, key, sizeof(key)) > 0) {
126
-           int res, len;
127
-           pw_log_debug("action %s", key);
128
-
129
-           if ((len = spa_json_next(&actions, &val)) <= 0)
130
-               break;
131
-
132
-           if (spa_json_is_container(val, len))
133
-               len = spa_json_container_len(&actions, val, len);
134
-
135
-           if ((res = matched(data, key, val, len)) < 0)
136
-               return res;
137
-
138
-           count += res;
139
-       }
140
-   }
141
-   return count;
142
-}
143
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel Deleted
2
 
1
-(directory)
2
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel/aec-null.c Deleted
66
 
1
@@ -1,64 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a
7
- * copy of this software and associated documentation files (the "Software"),
8
- * to deal in the Software without restriction, including without limitation
9
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
- * and/or sell copies of the Software, and to permit persons to whom the
11
- * Software is furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice (including the next
14
- * paragraph) shall be included in all copies or substantial portions of the
15
- * Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
- * DEALINGS IN THE SOFTWARE.
24
- */
25
-
26
-#include "echo-cancel.h"
27
-
28
-struct impl {
29
-   uint32_t channels;
30
-};
31
-
32
-static void *null_create(const struct pw_properties *args, const struct spa_audio_info_raw *info)
33
-{
34
-   struct impl *impl;
35
-   impl = calloc(1, sizeof(struct impl));
36
-   impl->channels = info->channels;
37
-   return impl;
38
-}
39
-
40
-static void null_destroy(void *ec)
41
-{
42
-   free(ec);
43
-}
44
-
45
-static int null_run(void *ec, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
46
-{
47
-   struct impl *impl = ec;
48
-   uint32_t i;
49
-   for (i = 0; i < impl->channels; i++)
50
-       memcpy(out[i], rec[i], n_samples * sizeof(float));
51
-   return 0;
52
-}
53
-
54
-static const struct echo_cancel_info echo_cancel_null_impl = {
55
-   .name = "null",
56
-   .info = SPA_DICT_INIT(NULL, 0),
57
-   .latency = NULL,
58
-
59
-   .create = null_create,
60
-   .destroy = null_destroy,
61
-
62
-   .run = null_run,
63
-};
64
-
65
-const struct echo_cancel_info *echo_cancel_null = &echo_cancel_null_impl;
66
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel/aec-webrtc.cpp Deleted
165
 
1
@@ -1,163 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
5
- *           © 2021 Arun Raghavan <arun@asymptotic.io>
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a
8
- * copy of this software and associated documentation files (the "Software"),
9
- * to deal in the Software without restriction, including without limitation
10
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
- * and/or sell copies of the Software, and to permit persons to whom the
12
- * Software is furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice (including the next
15
- * paragraph) shall be included in all copies or substantial portions of the
16
- * Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
- * DEALINGS IN THE SOFTWARE.
25
- */
26
-
27
-#include <memory>
28
-#include <utility>
29
-
30
-#include "echo-cancel.h"
31
-
32
-#include <pipewire/pipewire.h>
33
-
34
-#include <webrtc/modules/audio_processing/include/audio_processing.h>
35
-#include <webrtc/modules/interface/module_common_types.h>
36
-#include <webrtc/system_wrappers/include/trace.h>
37
-
38
-struct impl {
39
-   std::unique_ptr<webrtc::AudioProcessing> apm;
40
-   spa_audio_info_raw info;
41
-   std::unique_ptr<float *[]> play_buffer, rec_buffer, out_buffer;
42
-
43
-   impl(std::unique_ptr<webrtc::AudioProcessing> apm, const spa_audio_info_raw& info)
44
-       : apm(std::move(apm)),
45
-         info(info),
46
-         play_buffer(std::make_unique<float *[]>(info.channels)),
47
-         rec_buffer(std::make_unique<float *[]>(info.channels)),
48
-         out_buffer(std::make_unique<float *[]>(info.channels))
49
-   { }
50
-};
51
-
52
-static void *webrtc_create(const struct pw_properties *args, const spa_audio_info_raw *info)
53
-{
54
-   bool extended_filter = pw_properties_get_bool(args, "webrtc.extended_filter", true);
55
-   bool delay_agnostic = pw_properties_get_bool(args, "webrtc.delay_agnostic", true);
56
-   bool high_pass_filter = pw_properties_get_bool(args, "webrtc.high_pass_filter", true);
57
-   bool noise_suppression = pw_properties_get_bool(args, "webrtc.noise_suppression", true);
58
-   bool voice_detection = pw_properties_get_bool(args, "webrtc.voice_detection", true);
59
-
60
-   // Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech,
61
-   // result in very poor performance, disable by default
62
-   bool gain_control = pw_properties_get_bool(args, "webrtc.gain_control", false);
63
-
64
-   // Disable experimental flags by default
65
-   bool experimental_agc = pw_properties_get_bool(args, "webrtc.experimental_agc", false);
66
-   bool experimental_ns = pw_properties_get_bool(args, "webrtc.experimental_ns", false);
67
-
68
-   // FIXME: Intelligibility enhancer is not currently supported
69
-   // This filter will modify playback buffer (when calling ProcessReverseStream), but now
70
-   // playback buffer modifications are discarded.
71
-
72
-   webrtc::Config config;
73
-   config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter));
74
-   config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic));
75
-   config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc));
76
-   config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns));
77
-
78
-   webrtc::ProcessingConfig pconfig = {{
79
-       webrtc::StreamConfig(info->rate, info->channels, false), /* input stream */
80
-       webrtc::StreamConfig(info->rate, info->channels, false), /* output stream */
81
-       webrtc::StreamConfig(info->rate, info->channels, false), /* reverse input stream */
82
-       webrtc::StreamConfig(info->rate, info->channels, false), /* reverse output stream */
83
-   }};
84
-
85
-   auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config));
86
-   if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) {
87
-       pw_log_error("Error initialising webrtc audio processing module");
88
-       return nullptr;
89
-   }
90
-
91
-   apm->high_pass_filter()->Enable(high_pass_filter);
92
-   // Always disable drift compensation since it requires drift sampling
93
-   apm->echo_cancellation()->enable_drift_compensation(false);
94
-   apm->echo_cancellation()->Enable(true);
95
-   // TODO: wire up supression levels to args
96
-   apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression);
97
-   apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh);
98
-   apm->noise_suppression()->Enable(noise_suppression);
99
-   apm->voice_detection()->Enable(voice_detection);
100
-   // TODO: wire up AGC parameters to args
101
-   apm->gain_control()->set_analog_level_limits(0, 255);
102
-   apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
103
-   apm->gain_control()->Enable(gain_control);
104
-
105
-   return new impl(std::move(apm), *info);
106
-}
107
-
108
-static void webrtc_destroy(void *ec)
109
-{
110
-   auto impl = static_cast<struct impl *>(ec);
111
-
112
-   delete impl;
113
-}
114
-
115
-static int webrtc_run(void *ec, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
116
-{
117
-   auto impl = static_cast<struct impl *>(ec);
118
-   webrtc::StreamConfig config =
119
-       webrtc::StreamConfig(impl->info.rate, impl->info.channels, false);
120
-   unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10;
121
-
122
-   if (n_samples * 1000 / impl->info.rate % 10 != 0) {
123
-       pw_log_error("Buffers must be multiples of 10ms in length (currently %u samples)", n_samples);
124
-       return -1;
125
-   }
126
-
127
-   for (size_t i = 0; i < num_blocks; i ++) {
128
-       for (size_t j = 0; j < impl->info.channels; j++) {
129
-           impl->play_buffer[j] = const_cast<float *>(play[j]) + config.num_frames() * i;
130
-           impl->rec_buffer[j] = const_cast<float *>(rec[j]) + config.num_frames() * i;
131
-           impl->out_buffer[j] = out[j] + config.num_frames() * i;
132
-       }
133
-       /* FIXME: ProcessReverseStream may change the playback buffer, in which
134
-       * case we should use that, if we ever expose the intelligibility
135
-       * enhancer */
136
-       if (impl->apm->ProcessReverseStream(impl->play_buffer.get(), config, config, impl->play_buffer.get()) !=
137
-               webrtc::AudioProcessing::kNoError) {
138
-           pw_log_error("Processing reverse stream failed");
139
-       }
140
-
141
-       // Extra delay introduced by multiple frames
142
-       impl->apm->set_stream_delay_ms((num_blocks - 1) * 10);
143
-
144
-       if (impl->apm->ProcessStream(impl->rec_buffer.get(), config, config, impl->out_buffer.get()) !=
145
-               webrtc::AudioProcessing::kNoError) {
146
-           pw_log_error("Processing stream failed");
147
-       }
148
-   }
149
-
150
-   return 0;
151
-}
152
-
153
-static const struct echo_cancel_info echo_cancel_webrtc_impl = {
154
-   .name = "webrtc",
155
-   .info = SPA_DICT_INIT(NULL, 0),
156
-   .latency = "480/48000",
157
-
158
-   .create = webrtc_create,
159
-   .destroy = webrtc_destroy,
160
-
161
-   .run = webrtc_run,
162
-};
163
-
164
-const struct echo_cancel_info *echo_cancel_webrtc = &echo_cancel_webrtc_impl;
165
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel/echo-cancel.h Deleted
52
 
1
@@ -1,50 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a
7
- * copy of this software and associated documentation files (the "Software"),
8
- * to deal in the Software without restriction, including without limitation
9
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
- * and/or sell copies of the Software, and to permit persons to whom the
11
- * Software is furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice (including the next
14
- * paragraph) shall be included in all copies or substantial portions of the
15
- * Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
- * DEALINGS IN THE SOFTWARE.
24
- */
25
-
26
-#include "config.h"
27
-
28
-#include <spa/utils/dict.h>
29
-#include <spa/param/audio/raw.h>
30
-
31
-#include <pipewire/properties.h>
32
-
33
-struct echo_cancel_info {
34
-   const char *name;
35
-   const struct spa_dict info;
36
-   const char *latency;
37
-
38
-   void *(*create) (const struct pw_properties *args, const struct spa_audio_info_raw *info);
39
-   void (*destroy) (void *ec);
40
-
41
-   int (*run) (void *ec, const float *rec[], const float *play[], float *out[], uint32_t n_samples);
42
-};
43
-
44
-#define echo_cancel_create(i,...)  (i)->create(__VA_ARGS__)
45
-#define echo_cancel_destroy(i,...) (i)->destroy(__VA_ARGS__)
46
-#define echo_cancel_run(i,...)     (i)->run(__VA_ARGS__)
47
-
48
-#ifdef HAVE_WEBRTC
49
-extern const struct echo_cancel_info *echo_cancel_webrtc;
50
-#endif
51
-extern const struct echo_cancel_info *echo_cancel_null;
52
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/media-roles.c Deleted
42
 
1
@@ -1,40 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2020 Wim Taymans
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a
7
- * copy of this software and associated documentation files (the "Software"),
8
- * to deal in the Software without restriction, including without limitation
9
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
- * and/or sell copies of the Software, and to permit persons to whom the
11
- * Software is furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice (including the next
14
- * paragraph) shall be included in all copies or substantial portions of the
15
- * Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
- * DEALINGS IN THE SOFTWARE.
24
- */
25
-
26
-#include <stddef.h>
27
-
28
-#include "media-roles.h"
29
-
30
-const struct str_map media_role_map[] = {
31
-   { "Movie", "video", },
32
-   { "Music", "music", },
33
-   { "Game", "game", },
34
-   { "Notification", "event", },
35
-   { "Communication", "phone", },
36
-   { "Movie", "animation", },
37
-   { "Production", "production", },
38
-   { "Accessibility", "a11y", },
39
-   { "Test", "test", },
40
-   { NULL, NULL },
41
-};
42
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/media-roles.h Deleted
52
 
1
@@ -1,50 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2020 Wim Taymans
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a
7
- * copy of this software and associated documentation files (the "Software"),
8
- * to deal in the Software without restriction, including without limitation
9
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
- * and/or sell copies of the Software, and to permit persons to whom the
11
- * Software is furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice (including the next
14
- * paragraph) shall be included in all copies or substantial portions of the
15
- * Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
- * DEALINGS IN THE SOFTWARE.
24
- */
25
-
26
-#ifndef PULSE_SERVER_MEDIA_ROLES_H
27
-#define PULSE_SERVER_MEDIA_ROLES_H
28
-
29
-#include <stddef.h>
30
-
31
-#include <spa/utils/string.h>
32
-
33
-struct str_map {
34
-   const char *pw_str;
35
-   const char *pa_str;
36
-   const struct str_map *child;
37
-};
38
-
39
-extern const struct str_map media_role_map[];
40
-
41
-static inline const struct str_map *str_map_find(const struct str_map *map, const char *pw, const char *pa)
42
-{
43
-   size_t i;
44
-   for (i = 0; map[i].pw_str; i++)
45
-       if ((pw && spa_streq(map[i].pw_str, pw)) ||
46
-           (pa && spa_streq(map[i].pa_str, pa)))
47
-           return &map[i];
48
-   return NULL;
49
-}
50
-
51
-#endif /* PULSE_SERVER_MEDIA_ROLES_H */
52
pipewire-0.3.45.tar.gz/.gitlab-ci.yml -> pipewire-0.3.47.tar.gz/.gitlab-ci.yml Changed
19
 
1
@@ -25,7 +25,7 @@
2
 .fedora:
3
   variables:
4
     # Update this tag when you want to trigger a rebuild
5
-    FDO_DISTRIBUTION_TAG: '2022-01-28.0'
6
+    FDO_DISTRIBUTION_TAG: '2022-02-16.0'
7
     FDO_DISTRIBUTION_VERSION: '35'
8
     FDO_DISTRIBUTION_PACKAGES: >-
9
       alsa-lib-devel
10
@@ -142,7 +142,7 @@
11
     FDO_DISTRIBUTION_EXEC: >-
12
       mkdir -p /opt ;
13
       cd /opt ;
14
-      curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
15
+      curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/cxx/linux64
16
       --form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN ;
17
       tar xf /tmp/cov-analysis-linux64.tgz ;
18
       mv cov-analysis-linux64-* coverity ;
19
pipewire-0.3.45.tar.gz/NEWS -> pipewire-0.3.47.tar.gz/NEWS Changed
122
 
1
@@ -1,3 +1,110 @@
2
+# PipeWire 0.3.47 (2022-02-18)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+This is a quick emergency release to fix some severe
8
+problems with the previous release.
9
+
10
+## Highlights
11
+  - Fixes a bug in pulse-server that caused cached notifications
12
+    to play multiple times. (#2142)
13
+  - Removed check and warnings to catch leaked listeners on the
14
+    proxy. This might access invalid memory and cause infinite
15
+    loops in older wireplumber.
16
+
17
+Older versions:
18
+
19
+# PipeWire 0.3.46 (2022-02-17)
20
+
21
+This is a bugfix release that is API and ABI compatible with previous
22
+0.3.x releases.
23
+
24
+## Highlights
25
+  - Fix a critical bug in pipewire-pulse buffer size handling that made some
26
+    apps (MuseScore, ... ) stutter.
27
+  - Fix a critical bug where devices would not show when the kernel was
28
+    compiled without VERBOSE_PROCSFS.
29
+  - JACK clients will now use lock-quantum by default. This makes sure that
30
+    all dynamic quantum changes are disabled while a JACK app is running.
31
+    The only way to force a quantum chance is through a JACK app or with
32
+    the metadata.
33
+  - Almost all limits on number of ports, clients and nodes are removed.
34
+  - A Dummy fallback sink is now automatically created when there are no
35
+    other sinks. This avoids stalling browsers.
36
+  - Sound sharing with Zoom should work better. A new WirePlumber release
37
+    might be required.
38
+  - Many more fixes and improvements.
39
+
40
+
41
+## PipeWire
42
+  - Update docs with new config overrides.
43
+  - The rule matching logic was moved to config and code is now shared with
44
+    pulse-server and JACK.
45
+  - Add new Romanian translation.
46
+  - When a quantum is forced with metadata, any node that asked to lock-quantum
47
+    is ignored so that the quantum change can happen.
48
+  - Fix a bug where a mixer was removed twice, leading to potential memory
49
+    corruption.
50
+  - The port limits on nodes and filters are now removed. Some code was
51
+    simplified.
52
+  - Fix a potential leak because listeners where removed while they could be
53
+    emitted.
54
+  - Improve context.exec and avoid zombie processes.
55
+
56
+## Modules
57
+  - The RAOP module now has a default latency of 2 seconds, like PulseAudio.
58
+  - The echo-cancel module now uses the plugin loader to load the backends.
59
+    This makes it possible to add custom, out of tree, echo cancel plugins.
60
+
61
+## Tools
62
+  - Improve help of pw-link.
63
+  - Output to stdout and error to stderr. Use setlinebuf for stdout to improve
64
+    piping between apps. (#2110)
65
+
66
+## SPA
67
+  - Improve removing sources when dispatching. Also improve performance now
68
+    that a destroy loop can be removed. (#2114)
69
+  - Fix an fd leak in the logger when logging to a file.
70
+  - Improve loop enter/leave checks and support recursive loops.
71
+
72
+## pulse-server
73
+  - Clamp various buffer attributes to the max length. Fixes some issues
74
+    with various applications. (#2100)
75
+  - Module properties are now remapped correctly from their pulseaudio variant
76
+    to the PipeWire ones.
77
+  - Fix module index in introspect. Use the right index when loaded from our
78
+    internal modules. (#2101)
79
+  - Improve argument parsing and node.description. (#2086)
80
+  - The sink-index should now be filled in correctly when playing a sample.
81
+    (#2129)
82
+  - module-always-sink is now implemented and loaded by default. (#1838)
83
+  - Add support for loading some modules only once.
84
+  - Module load and unload now does extra sync to make it appear synchronous,
85
+    like in PulseAudio. This improves sounds sharing in Zoom.
86
+
87
+## ALSA
88
+  - Fix critial bug where alsa devices would not show when the kernel was
89
+    compiled without VERBOSE_PROCFS.
90
+  - Some corner cases were fixed in the ALSA timing code. When the capture node
91
+    is follower, it will now not try to read too much data and xrun but it will
92
+    instead produce a cycle of silence.
93
+  - Various fixes and improvements to make ALSA devices resync to the driver
94
+    more quickly and accurately.
95
+
96
+## JACK
97
+  - Add an option to name the defauld device as `system` to improve
98
+    compatibility with some applications,
99
+  - Use lock-quantum by default. This makes sure that all dynamic quantum
100
+    changes are disabled while a JACK app is running. The only way to force
101
+    a quantum chance is through a JACK app or with the metadata.
102
+  - It is now possible to do IPC calls from the data thread. Note that this
103
+    is a very bad idea but required for compatibility with JACK2.
104
+
105
+## GStreamer
106
+  - GStreamer sink will now set a default channelmap to make it possible to 
107
+    remap to the channel layout of the device.
108
+
109
 # PipeWire 0.3.45 (2022-02-03)
110
 
111
 This is a bugfix release that is API and ABI compatible with previous
112
@@ -62,9 +169,6 @@
113
     switch quantum and ensure it can't change for the lifetime of the JACK
114
     app. (#2079)
115
 
116
-Older versions:
117
-
118
-
119
 # PipeWire 0.3.44 (2022-01-27)
120
 
121
 This is a bugfix release that is API and ABI compatible with previous
122
pipewire-0.3.45.tar.gz/doc/pipewire-daemon.dox -> pipewire-0.3.47.tar.gz/doc/pipewire-daemon.dox Changed
22
 
1
@@ -62,8 +62,18 @@
2
 - `$sysconfdir/pipewire/pipewire.conf` (usually `/etc/pipewire/pipewire.conf`)
3
 - `$datadir/pipewire/pipewire.conf` (usually `/usr/share/pipewire/pipewire.conf`)
4
 
5
-The first configuration file found is loaded, the PipeWire daemon does not
6
-currently combine configuration files.
7
+The first configuration file found is loaded as the base configuration.
8
+
9
+Next, configuration sections are collected in the directories in this
10
+order:
11
+
12
+- `$datadir/pipewire/pipewire.conf.d/` (usually `/usr/share/pipewire/pipewire.conf.d/`)
13
+- `$sysconfdir/pipewire/pipewire.conf.d/` (usually `/etc/pipewire/pipewire.conf.d/`)
14
+- `$XDG_CONFIG_HOME/pipewire/pipewire.conf.d/` (usually `$HOME/.config/pipewire/pipewire.conf.d/`)
15
+
16
+They are applied to the global configuration file. Properties are overwritten
17
+and array elements are appended. This makes it possible to make small custom customizations
18
+or additions to the main configuration file.
19
 
20
 The environment variables `PIPEWIRE_CONFIG_DIR`, `PIPEWIRE_CONFIG_PREFIX`
21
 and `PIPEWIRE_CONFIG_NAME` can be used to specify an alternative config
22
pipewire-0.3.45.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.47.tar.gz/doc/pipewire-modules.dox Changed
9
 
1
@@ -59,6 +59,7 @@
2
 - \subpage page_module_echo_cancel
3
 - \subpage page_module_example_sink
4
 - \subpage page_module_example_source
5
+- \subpage page_module_fallback_sink
6
 - \subpage page_module_filter_chain
7
 - \subpage page_module_link_factory
8
 - \subpage page_module_loopback
9
pipewire-0.3.45.tar.gz/man/meson.build -> pipewire-0.3.47.tar.gz/man/meson.build Changed
10
 
1
@@ -19,7 +19,7 @@
2
   'pw-profiler.1.rst.in',
3
 ]
4
 
5
-if not get_option('pipewire-jack').disabled()
6
+if get_option('pipewire-jack').allowed()
7
   manpages += 'pw-jack.1.rst.in'
8
 endif
9
 
10
pipewire-0.3.45.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.47.tar.gz/man/pipewire.conf.5.rst.in Changed
54
 
1
@@ -19,13 +19,19 @@
2
 
3
 *@PIPEWIRE_CONFDATADIR@/pipewire.conf*
4
 
5
+*@PIPEWIRE_CONFDATADIR@/pipewire.conf.d/*
6
+
7
+*@PIPEWIRE_CONFIG_DIR@/pipewire.conf.d/*
8
+
9
+*$XDG_CONFIG_HOME/pipewire/pipewire.conf.d/*
10
+
11
 DESCRIPTION
12
 ===========
13
 
14
 PipeWire is a service that facilitates sharing of multimedia content
15
 between devices and applications.
16
 
17
-On startup, the daemon reads a configuration file to configure
18
+On startup, the daemon reads a main configuration file to configure
19
 itself. It executes a series of commands listed in the config
20
 file.
21
 
22
@@ -34,6 +40,13 @@
23
 and ``PIPEWIRE_CONFIG_NAME`` can be used to specify an alternative config
24
 directory, subdirectory and file respectively.
25
 
26
+Next to the configuration file can be a directory with the same name as
27
+the file with a ``.d/`` suffix. All directories in the SYNOPSIS_ directory
28
+search paths are traversed in the listed order and the contents of the
29
+``*.conf`` files inside them are appended to the main configuration file
30
+as overrides. Object sections are merged and array sections are appended.
31
+
32
+
33
 CONFIGURATION FILE FORMAT
34
 =========================
35
 
36
@@ -51,6 +64,17 @@
37
 
38
 name = [ { k = v1 } { k = v2 } ] # an array of dictionaries
39
 
40
+
41
+The configuration files can be expressed in full JSON syntax but for ease
42
+of use, a relaxed format may be used where:
43
+
44
+ * ``:`` to delimit keys and values can be substuted by ``=`` or a space.
45
+ * ``"`` around keys and string can be omited as long as no special characters
46
+         are used in the strings.
47
+ * ``,`` to separate objects can be replaced with a whitespace character.
48
+ * ``#`` can be used to start a comment until the line end
49
+
50
+
51
 CONFIGURATION FILE SECTIONS
52
 ===========================
53
 
54
pipewire-0.3.45.tar.gz/meson.build -> pipewire-0.3.47.tar.gz/meson.build Changed
201
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', ['c' ],
3
-  version : '0.3.45',
4
+  version : '0.3.47',
5
   license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
6
   meson_version : '>= 0.59.0',
7
   default_options : [ 'warning_level=3',
8
@@ -202,8 +202,6 @@
9
 cdata.set_quoted('PIPEWIRE_CONFIG_DIR', pipewire_configdir)
10
 cdata.set_quoted('PLUGINDIR', spa_plugindir)
11
 cdata.set_quoted('SPADATADIR', spa_datadir)
12
-# FIXME: --with-memory-alignment],[8,N,malloc,pagesize (default is 32)]) option
13
-cdata.set('MEMORY_ALIGNMENT_MALLOC', 1)
14
 cdata.set_quoted('PA_ALSA_PATHS_DIR', alsadatadir / 'paths')
15
 cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', alsadatadir / 'profile-sets')
16
 
17
@@ -211,95 +209,38 @@
18
   cdata.set('WORDS_BIGENDIAN', 1)
19
 endif
20
 
21
-check_headers = [['dlfcn.h','HAVE_DLFCN_H'],
22
-  ['inttypes.h', 'HAVE_INTTYPES_H'],
23
-  ['memory.h', 'HAVE_MEMORY_H'],
24
-  ['poll.h', 'HAVE_POLL_H'],
25
-  ['stddef.h', 'HAVE_STDDEF_H'],
26
-  ['stdint.h', 'HAVE_STDINT_H'],
27
-  ['stdio_ext.h', 'HAVE_STDIO_EXT_H'],
28
-  ['strings.h', 'HAVE_STRINGS_H'],
29
-  ['string.h', 'HAVE_STRING_H'],
30
+check_headers = [
31
   ['sys/mount.h', 'HAVE_SYS_MOUNT_H'],
32
   ['sys/param.h', 'HAVE_SYS_PARAM_H'],
33
-  ['sys/poll.h', 'HAVE_SYS_POLL_H'],
34
-  ['sys/prctl.h', 'HAVE_SYS_PRCTL_H'],
35
   ['sys/random.h', 'HAVE_SYS_RANDOM_H'],
36
-  ['sys/socket.h', 'HAVE_SYS_SOCKET_H'],
37
-  ['sys/stat.h', 'HAVE_SYS_STAT_H'],
38
-  ['sys/times.h', 'HAVE_SYS_TIMES_H'],
39
-  ['sys/time.h', 'HAVE_SYS_TIME_H'],
40
-  ['sys/types.h', 'HAVE_SYS_TYPES_H'],
41
-  ['sys/utsname.h', 'HAVE_SYS_UTSNAME_H'],
42
   ['sys/vfs.h', 'HAVE_SYS_VFS_H'],
43
-  ['sys/wait.h', 'HAVE_SYS_WAIT_H'],
44
   ['pwd.h', 'HAVE_PWD_H'],
45
-  ['ucontext.h', 'HAVE_UCONTEXT_H'],
46
-  ['unistd.h', 'HAVE_UNISTD_H'],
47
 ]
48
 
49
 foreach h : check_headers
50
-  if cc.has_header(h.get(0))
51
-    cdata.set(h.get(1), 1)
52
-  endif
53
+  cdata.set(h.get(1), cc.has_header(h.get(0)))
54
 endforeach
55
 
56
-if cc.has_function('poll', prefix : '#include<poll.h>')
57
-  cdata.set('HAVE_POLL', 1)
58
-endif
59
-if cc.has_function('pselect', prefix : '#include<sys/select.h>')
60
-  cdata.set('HAVE_PSELECT', 1)
61
-endif
62
-cdata.set('HAVE_MMAP', 1)
63
-
64
-if cc.has_function('posix_memalign', prefix : '#include<stdlib.h>')
65
-  cdata.set('HAVE_POSIX_MEMALIGN', 1)
66
-endif
67
-if cc.has_function('getpagesize', prefix : '#include<unistd.h>')
68
-  cdata.set('HAVE_GETPAGESIZE', 1)
69
-endif
70
-if cc.has_function('gettid', prefix : '#include<unistd.h>', args: [ '-D_GNU_SOURCE' ])
71
-  cdata.set('HAVE_GETTID', 1)
72
-endif
73
-if cc.has_function('clock_gettime', prefix : '#include <time.h>')
74
-  cdata.set('HAVE_CLOCK_GETTIME', 1)
75
-endif
76
-
77
-if cc.has_type('ptrdiff_t', prefix : '#include <stddef.h>')
78
-  cdata.set('HAVE_PTRDIFF_T', 1)
79
-endif
80
-
81
-if cc.has_header_symbol('string.h', 'strndupa', args : [ '-D_GNU_SOURCE' ])
82
-  cdata.set('HAVE_STRNDUPA', 1)
83
-endif
84
-
85
-if cc.has_function('mkstemp', prefix : '#include <stdlib.h>')
86
-  cdata.set('HAVE_MKSTEMP', 1)
87
-endif
88
-
89
-if cc.has_function('memfd_create', prefix : '#include <sys/mman.h>', args : [ '-D_GNU_SOURCE' ])
90
-  cdata.set('HAVE_MEMFD_CREATE', 1)
91
-endif
92
-
93
-if cc.has_function('getrandom', prefix : '#include <stddef.h>\n#include <sys/random.h>', args : [ '-D_GNU_SOURCE' ])
94
-  cdata.set('HAVE_GETRANDOM', 1)
95
-endif
96
+check_functions = [
97
+  ['gettid', '#include <unistd.h>', ['-D_GNU_SOURCE']],
98
+  ['memfd_create', '#include <sys/mman.h>', ['-D_GNU_SOURCE']],
99
+  ['getrandom', '#include <stddef.h>\n#include <sys/random.h>', ['-D_GNU_SOURCE']],
100
+  ['sigabbrev_np', '#include <string.h>', ['-D_GNU_SOURCE']],
101
+]
102
 
103
-if cc.has_function('sigabbrev_np', prefix : '#include <string.h>', args : [ '-D_GNU_SOURCE' ])
104
-  cdata.set('HAVE_SIGABBREV_NP', 1)
105
-endif
106
+foreach f : check_functions
107
+  cdata.set('HAVE_' + f.get(0).to_upper(),
108
+            cc.has_function(f.get(0), prefix: f.get(1), args: f.get(2)))
109
+endforeach
110
 
111
-if cc.get_define('SYS_pidfd_open', prefix : '#include <sys/syscall.h>') != ''
112
-  cdata.set('HAVE_PIDFD_OPEN', 1)
113
-endif
114
+cdata.set('HAVE_PIDFD_OPEN',
115
+          cc.get_define('SYS_pidfd_open', prefix: '#include <sys/syscall.h>') != '')
116
 
117
 systemd = dependency('systemd', required: get_option('systemd'))
118
 systemd_dep = dependency('libsystemd',required: get_option('systemd'))
119
 summary({'systemd conf data': systemd.found()}, bool_yn: true)
120
 summary({'libsystemd': systemd_dep.found()}, bool_yn: true)
121
-if systemd.found() and systemd_dep.found()
122
-  cdata.set('HAVE_SYSTEMD', 1)
123
-endif
124
+cdata.set('HAVE_SYSTEMD', systemd.found() and systemd_dep.found())
125
 
126
 configinc = include_directories('.')
127
 includes_inc = include_directories('include')
128
@@ -326,9 +267,7 @@
129
 pthread_lib = dependency('threads')
130
 dbus_dep = dependency('dbus-1', required : get_option('dbus'))
131
 summary({'dbus (Bluetooth, rt, portal, pw-reserve)': dbus_dep.found()}, bool_yn: true, section: 'Misc dependencies')
132
-if dbus_dep.found()
133
-  cdata.set('HAVE_DBUS', 1)
134
-endif
135
+cdata.set('HAVE_DBUS', dbus_dep.found())
136
 sdl_dep = dependency('sdl2', required : get_option('sdl2'))
137
 summary({'SDL2 (video examples)': sdl_dep.found()}, bool_yn: true, section: 'Misc dependencies')
138
 drm_dep = dependency('libdrm', required : false)
139
@@ -342,9 +281,7 @@
140
 ncurses_dep = dependency('ncursesw', required : false)
141
 sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option('sndfile'))
142
 summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump/filter-chain')
143
-if sndfile_dep.found()
144
-  cdata.set('HAVE_SNDFILE', 1)
145
-endif
146
+cdata.set('HAVE_SNDFILE', sndfile_dep.found())
147
 pulseaudio_dep = dependency('libpulse', required : get_option('libpulse'))
148
 summary({'libpulse': pulseaudio_dep.found()}, bool_yn: true, section: 'Streaming between daemons')
149
 avahi_dep = dependency('avahi-client', required : get_option('avahi'))
150
@@ -361,14 +298,10 @@
151
 
152
 libusb_dep = dependency('libusb-1.0', required : get_option('libusb'))
153
 summary({'libusb (Bluetooth quirks)': libusb_dep.found()}, bool_yn: true, section: 'Backend')
154
-if libusb_dep.found()
155
-  cdata.set('HAVE_LIBUSB', 1)
156
-endif
157
+cdata.set('HAVE_LIBUSB', libusb_dep.found())
158
 
159
 cap_lib = dependency('libcap', required : false)
160
-if cap_lib.found()
161
-  cdata.set('HAVE_LIBCAP', 1)
162
-endif
163
+cdata.set('HAVE_LIBCAP', cap_lib.found())
164
 
165
 gst_option = get_option('gstreamer')
166
 gst_deps_def = {
167
@@ -403,18 +336,13 @@
168
 gst_dp_found = gst_dep.length() > 0
169
 summary({'gstreamer-device-provider': gst_dp_found}, bool_yn: true, section: 'Backend')
170
 
171
-if not get_option('gstreamer-device-provider').disabled()
172
-  cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', 1)
173
-endif
174
+cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', get_option('gstreamer-device-provider').allowed())
175
 
176
 webrtc_dep = dependency('webrtc-audio-processing',
177
   version : ['>= 0.2', '< 1.0'],
178
   required : get_option('echo-cancel-webrtc'))
179
 summary({'WebRTC Echo Canceling': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies')
180
-
181
-if webrtc_dep.found()
182
-  cdata.set('HAVE_WEBRTC', 1)
183
-endif
184
+cdata.set('HAVE_WEBRTC', webrtc_dep.found())
185
 
186
 # On FreeBSD, epoll-shim library is required for eventfd() and timerfd()
187
 epoll_shim_dep = (build_machine.system() == 'freebsd'
188
@@ -450,35 +378,33 @@
189
 
190
 lilv_lib = dependency('lilv-0', required: get_option('lv2'))
191
 summary({'lilv (for lv2 plugins)': lilv_lib.found()}, bool_yn: true)
192
-if lilv_lib.found()
193
-  cdata.set('HAVE_LILV', 1)
194
-endif
195
+cdata.set('HAVE_LILV', lilv_lib.found())
196
 
197
 installed_tests_metadir = pipewire_datadir / 'installed-tests' / pipewire_name
198
 installed_tests_execdir = pipewire_libexecdir / 'installed-tests' / pipewire_name
199
-installed_tests_enabled = not get_option('installed_tests').disabled()
200
+installed_tests_enabled = get_option('installed_tests').allowed()
201
pipewire-0.3.45.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.47.tar.gz/pipewire-jack/src/meson.build Changed
9
 
1
@@ -1,7 +1,6 @@
2
 pipewire_jack_sources = [
3
   'export.c',
4
   'pipewire-jack.c',
5
-  'match-rules.c',
6
   'ringbuffer.c',
7
   'uuid.c',
8
 ]
9
pipewire-0.3.45.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.47.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
201
 
1
@@ -64,15 +64,13 @@
2
 
3
 #define JACK_CLIENT_NAME_SIZE      128
4
 #define JACK_PORT_NAME_SIZE        256
5
-#define JACK_PORT_MAX          4096
6
 #define JACK_PORT_TYPE_SIZE             32
7
-#define CONNECTION_NUM_FOR_PORT        1024
8
 #define MONITOR_EXT            " Monitor"
9
 
10
+#define MAX_MIDI_MIX           1024
11
 #define MAX_BUFFER_FRAMES      8192
12
 
13
 #define MAX_ALIGN          16
14
-#define MAX_PORTS          1024
15
 #define MAX_BUFFERS            2
16
 #define MAX_BUFFER_DATAS       1u
17
 
18
@@ -380,6 +378,7 @@
19
    } rt;
20
 
21
    pthread_mutex_t rt_lock;
22
+   unsigned int rt_locked:1;
23
 
24
    unsigned int started:1;
25
    unsigned int active:1;
26
@@ -396,6 +395,7 @@
27
    unsigned int filter_name:1;
28
    unsigned int freewheeling:1;
29
    unsigned int locked_process:1;
30
+   unsigned int default_as_system:1;
31
    int self_connect_mode;
32
    int rt_max;
33
 
34
@@ -808,7 +808,9 @@
35
    int res = 0;                        \
36
    if (c->callback) {                  \
37
        if (pthread_mutex_trylock(&c->rt_lock) == 0) {  \
38
+           c->rt_locked = true;            \
39
            res = c->callback(__VA_ARGS__);     \
40
+           c->rt_locked = false;           \
41
            pthread_mutex_unlock(&c->rt_lock);  \
42
        }                       \
43
    }                           \
44
@@ -859,6 +861,8 @@
45
 
46
 static int do_sync(struct client *client)
47
 {
48
+   bool in_data_thread = pw_data_loop_in_thread(client->loop);
49
+
50
    if (pw_thread_loop_in_thread(client->context.loop)) {
51
        pw_log_warn("sync requested from callback");
52
        return 0;
53
@@ -869,8 +873,14 @@
54
    client->pending_sync = pw_proxy_sync((struct pw_proxy*)client->core, client->pending_sync);
55
 
56
    while (true) {
57
+       if (in_data_thread && client->rt_locked)
58
+           pthread_mutex_unlock(&client->rt_lock);
59
+
60
            pw_thread_loop_wait(client->context.loop);
61
 
62
+       if (in_data_thread && client->rt_locked)
63
+           pthread_mutex_lock(&client->rt_lock);
64
+
65
        if (client->error)
66
            return client->last_res;
67
 
68
@@ -891,6 +901,7 @@
69
    struct client *client = data;
70
    client->node = NULL;
71
    spa_hook_remove(&client->proxy_listener);
72
+   spa_hook_remove(&client->node_listener);
73
 }
74
 
75
 static void on_node_bound(void *data, uint32_t global_id)
76
@@ -3087,7 +3098,8 @@
77
 }
78
 
79
 
80
-static int execute_match(void *data, const char *action, const char *val, int len)
81
+static int execute_match(void *data, const char *location, const char *action,
82
+       const char *val, size_t len)
83
 {
84
    struct client *client = data;
85
    if (spa_streq(action, "update-props"))
86
@@ -3095,19 +3107,6 @@
87
    return 1;
88
 }
89
 
90
-static int apply_jack_rules(void *data, const char *location, const char *section,
91
-       const char *str, size_t len)
92
-{
93
-   struct client *client = data;
94
-   const struct pw_properties *p =
95
-       pw_context_get_properties(client->context.context);
96
-
97
-   if (p != NULL)
98
-       pw_jack_match_rules(str, len, &p->dict, execute_match, client);
99
-
100
-   return 0;
101
-}
102
-
103
 SPA_EXPORT
104
 jack_client_t * jack_client_open (const char *client_name,
105
                                   jack_options_t options,
106
@@ -3171,15 +3170,15 @@
107
         if ((str = getenv("PIPEWIRE_PROPS")) != NULL)
108
        pw_properties_update_string(client->props, str, strlen(str));
109
 
110
-
111
-   pw_context_conf_section_for_each(client->context.context, "jack.rules",
112
-           apply_jack_rules, client);
113
+   pw_context_conf_section_match_rules(client->context.context, "jack.rules",
114
+           &client->props->dict, execute_match, client);
115
 
116
    client->show_monitor = pw_properties_get_bool(client->props, "jack.show-monitor", true);
117
    client->merge_monitor = pw_properties_get_bool(client->props, "jack.merge-monitor", false);
118
    client->short_name = pw_properties_get_bool(client->props, "jack.short-name", false);
119
    client->filter_name = pw_properties_get_bool(client->props, "jack.filter-name", false);
120
    client->locked_process = pw_properties_get_bool(client->props, "jack.locked-process", true);
121
+   client->default_as_system = pw_properties_get_bool(client->props, "jack.default-as-system", false);
122
 
123
    client->self_connect_mode = SELF_CONNECT_ALLOW;
124
    if ((str = pw_properties_get(client->props, "jack.self-connect-mode")) != NULL) {
125
@@ -3221,8 +3220,8 @@
126
         spa_list_init(&client->mix);
127
         spa_list_init(&client->free_mix);
128
 
129
-   pw_map_init(&client->ports[SPA_DIRECTION_INPUT], MAX_PORTS, 32);
130
-   pw_map_init(&client->ports[SPA_DIRECTION_OUTPUT], MAX_PORTS, 32);
131
+   pw_map_init(&client->ports[SPA_DIRECTION_INPUT], 32, 32);
132
+   pw_map_init(&client->ports[SPA_DIRECTION_OUTPUT], 32, 32);
133
    spa_list_init(&client->free_ports);
134
 
135
    pw_thread_loop_start(client->context.loop);
136
@@ -3278,6 +3277,8 @@
137
        pw_properties_set(client->props, PW_KEY_MEDIA_ROLE, "DSP");
138
    if (pw_properties_get(client->props, PW_KEY_NODE_ALWAYS_PROCESS) == NULL)
139
        pw_properties_set(client->props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
140
+   if (pw_properties_get(client->props, PW_KEY_NODE_LOCK_QUANTUM) == NULL)
141
+       pw_properties_set(client->props, PW_KEY_NODE_LOCK_QUANTUM, "true");
142
    pw_properties_set(client->props, PW_KEY_NODE_TRANSPORT_SYNC, "true");
143
 
144
    client->node = pw_core_create_object(client->core,
145
@@ -3295,8 +3296,8 @@
146
            &client->proxy_listener, &node_proxy_events, client);
147
 
148
    client->info = SPA_NODE_INFO_INIT();
149
-   client->info.max_input_ports = MAX_PORTS;
150
-   client->info.max_output_ports = MAX_PORTS;
151
+   client->info.max_input_ports = UINT32_MAX;
152
+   client->info.max_output_ports = UINT32_MAX;
153
    client->info.change_mask = SPA_NODE_CHANGE_MASK_FLAGS |
154
        SPA_NODE_CHANGE_MASK_PROPS;
155
    client->info.flags = SPA_NODE_FLAG_RT;
156
@@ -3383,11 +3384,14 @@
157
 
158
    pw_thread_loop_stop(c->context.loop);
159
 
160
-   if (c->registry)
161
+   if (c->registry) {
162
+       spa_hook_remove(&c->registry_listener);
163
        pw_proxy_destroy((struct pw_proxy*)c->registry);
164
+   }
165
    if (c->metadata && c->metadata->proxy) {
166
        pw_proxy_destroy((struct pw_proxy*)c->metadata->proxy);
167
    }
168
+   spa_hook_remove(&c->core_listener);
169
    pw_core_disconnect(c->core);
170
    pw_context_destroy(c->context.context);
171
 
172
@@ -3996,15 +4000,12 @@
173
 int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes)
174
 {
175
    struct client *c = (struct client *) client;
176
-   char latency[128];
177
 
178
    spa_return_val_if_fail(c != NULL, -EINVAL);
179
 
180
-   snprintf(latency, sizeof(latency), "%d/%d", nframes, jack_get_sample_rate(client));
181
-   pw_log_info("%p: buffer-size %s", client, latency);
182
+   pw_log_info("%p: buffer-size %u", client, nframes);
183
 
184
    pw_thread_loop_lock(c->context.loop);
185
-   pw_properties_set(c->props, PW_KEY_NODE_LATENCY, latency);
186
    pw_properties_setf(c->props, PW_KEY_NODE_FORCE_QUANTUM, "%u", nframes);
187
 
188
    c->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS;
189
@@ -4334,7 +4335,7 @@
190
 {
191
    struct mix *mix;
192
    void *ptr = p->emptyptr;
193
-   struct spa_pod_sequence *seq[CONNECTION_NUM_FOR_PORT];
194
+   struct spa_pod_sequence *seq[MAX_MIDI_MIX];
195
    uint32_t n_seq = 0;
196
 
197
    jack_midi_clear_buffer(ptr);
198
@@ -4358,6 +4359,8 @@
199
            continue;
200
 
201
pipewire-0.3.45.tar.gz/po/LINGUAS -> pipewire-0.3.47.tar.gz/po/LINGUAS Changed
9
 
1
@@ -36,6 +36,7 @@
2
 pl
3
 pt_BR
4
 pt
5
+ro
6
 ru
7
 sk
8
 sr@latin
9
pipewire-0.3.45.tar.gz/po/POTFILES.in -> pipewire-0.3.47.tar.gz/po/POTFILES.in Changed
9
 
1
@@ -2,6 +2,7 @@
2
 src/daemon/pipewire.desktop.in
3
 src/modules/module-protocol-pulse/modules/module-tunnel-sink.c
4
 src/modules/module-protocol-pulse/modules/module-tunnel-source.c
5
+src/modules/module-fallback-sink.c
6
 src/modules/module-pulse-tunnel.c
7
 src/modules/module-zeroconf-discover.c
8
 src/tools/pw-cat.c
9
pipewire-0.3.47.tar.gz/po/ro.po Added
201
 
1
@@ -0,0 +1,679 @@
2
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+# This file is distributed under the same license as the pipewire package.
4
+#
5
+# Sergiu Bivol <sergiu@cip.md>, 2022.
6
+msgid ""
7
+msgstr ""
8
+"Project-Id-Version: pipewire\n"
9
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/issues/"
10
+"new\n"
11
+"POT-Creation-Date: 2021-11-17 15:06+0100\n"
12
+"PO-Revision-Date: 2022-02-05 12:06+0000\n"
13
+"Last-Translator: Sergiu Bivol <sergiu@cip.md>\n"
14
+"Language-Team: Romanian\n"
15
+"Language: ro\n"
16
+"MIME-Version: 1.0\n"
17
+"Content-Type: text/plain; charset=UTF-8\n"
18
+"Content-Transfer-Encoding: 8bit\n"
19
+"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 <"
20
+" 20)) ? 1 : 2;\n"
21
+"X-Generator: Lokalize 21.12.2\n"
22
+
23
+#: src/daemon/pipewire.c:45
24
+#, c-format
25
+msgid ""
26
+"%s [options]\n"
27
+"  -h, --help                            Show this help\n"
28
+"      --version                         Show version\n"
29
+"  -c, --config                          Load config (Default %s)\n"
30
+msgstr ""
31
+"%s [opțiuni]\n"
32
+"  -h, --help                            Arată acest ajutor\n"
33
+"      --version                         Arată versiunea\n"
34
+"  -c, --config                          Încarcă configurare (implicit %s)\n"
35
+
36
+#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:185
37
+#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:185
38
+#, c-format
39
+msgid "Tunnel to %s/%s"
40
+msgstr "Tunelează spre %s/%s"
41
+
42
+#: src/modules/module-pulse-tunnel.c:536
43
+#, c-format
44
+msgid "Tunnel for %s@%s"
45
+msgstr "Tunelează pentru %s@%s"
46
+
47
+#: src/modules/module-zeroconf-discover.c:332
48
+msgid "Unknown device"
49
+msgstr "Dispozitiv necunoscut"
50
+
51
+#: src/modules/module-zeroconf-discover.c:344
52
+#, c-format
53
+msgid "%s on %s@%s"
54
+msgstr "%s pe %s@%s"
55
+
56
+#: src/modules/module-zeroconf-discover.c:348
57
+#, c-format
58
+msgid "%s on %s"
59
+msgstr "%s pe %s"
60
+
61
+#: src/tools/pw-cat.c:1058
62
+#, c-format
63
+msgid ""
64
+"%s [options] <file>\n"
65
+"  -h, --help                            Show this help\n"
66
+"      --version                         Show version\n"
67
+"  -v, --verbose                         Enable verbose operations\n"
68
+"\n"
69
+msgstr ""
70
+"%s [opțiuni] <fișier>\n"
71
+"  -h, --help                            Arată acest ajutor\n"
72
+"      --version                         Arată versiunea\n"
73
+"  -v, --verbose                         Activează operații verboase\n"
74
+"\n"
75
+
76
+#: src/tools/pw-cat.c:1065
77
+#, c-format
78
+msgid ""
79
+"  -R, --remote                          Remote daemon name\n"
80
+"      --media-type                      Set media type (default %s)\n"
81
+"      --media-category                  Set media category (default %s)\n"
82
+"      --media-role                      Set media role (default %s)\n"
83
+"      --target                          Set node target (default %s)\n"
84
+"                                          0 means don't link\n"
85
+"      --latency                         Set node latency (default %s)\n"
86
+"                                          Xunit (unit = s, ms, us, ns)\n"
87
+"                                          or direct samples (256)\n"
88
+"                                          the rate is the one of the source "
89
+"file\n"
90
+"      --list-targets                    List available targets for --target\n"
91
+"\n"
92
+msgstr ""
93
+"  -R, --remote                          Denumirea demonului distant\n"
94
+"      --media-type                      Stabilește tipul mediului (implicit "
95
+"%s)\n"
96
+"      --media-category                  Stabilește categoria mediului"
97
+" (implicit %s)\n"
98
+"      --media-role                      Stabilește rolul mediului (implicit "
99
+"%s)\n"
100
+"      --target                          Stabilește ținta nodului (implicit "
101
+"%s)\n"
102
+"                                          0 înseamnă „nu lega”\n"
103
+"      --latency                         Stabilește latența nodului (implicit "
104
+"%s)\n"
105
+"                                          Xunit (unitate = s, ms, us, ns)\n"
106
+"                                          sau mostre directe (256)\n"
107
+"                                          rata este cea a fișierului sursă\n"
108
+"      --list-targets                    Enumeră țintele disponibile pentru"
109
+" --target\n"
110
+"\n"
111
+
112
+#: src/tools/pw-cat.c:1083
113
+#, c-format
114
+msgid ""
115
+"      --rate                            Sample rate (req. for rec) (default "
116
+"%u)\n"
117
+"      --channels                        Number of channels (req. for rec) "
118
+"(default %u)\n"
119
+"      --channel-map                     Channel map\n"
120
+"                                            one of: \"stereo\", "
121
+"\"surround-51\",... or\n"
122
+"                                            comma separated list of channel "
123
+"names: eg. \"FL,FR\"\n"
124
+"      --format                          Sample format %s (req. for rec) "
125
+"(default %s)\n"
126
+"      --volume                          Stream volume 0-1.0 (default %.3f)\n"
127
+"  -q  --quality                         Resampler quality (0 - 15) (default "
128
+"%d)\n"
129
+"\n"
130
+msgstr ""
131
+"      --rate                            Rată de eșantionare (nec. pt."
132
+" înregistrare) (implicit %u)\n"
133
+"      --channels                        Număr de canale (nec. pt."
134
+" înregistrare) (implicit %u)\n"
135
+"      --channel-map                     Hartă canale\n"
136
+"                                            una dintre: \"stereo\","
137
+" \"surround-51\",... sau listă\n"
138
+"                                            separată prin virgulă cu denumiri"
139
+" de canale: de ex. \"FL,FR\"\n"
140
+"      --format                          Format de eșantionare %s (nec. pt."
141
+" înregistrare) (implicit %s)\n"
142
+"      --volume                          Volum flux 0-1.0 (implicit %.3f)\n"
143
+"  -q  --quality                         Calitate de re-eșantionare (0 - 15)"
144
+" (implicit %d)\n"
145
+"\n"
146
+
147
+#: src/tools/pw-cat.c:1100
148
+msgid ""
149
+"  -p, --playback                        Playback mode\n"
150
+"  -r, --record                          Recording mode\n"
151
+"  -m, --midi                            Midi mode\n"
152
+"  -d, --dsd                             DSD mode\n"
153
+"\n"
154
+msgstr ""
155
+"  -p, --playback                        Regim de redare\n"
156
+"  -r, --record                          Regim de înregistrare\n"
157
+"  -m, --midi                            Regim MIDI\n"
158
+"  -d, --dsd                             regim DSD\n"
159
+"\n"
160
+
161
+#: src/tools/pw-cli.c:3018
162
+#, c-format
163
+msgid ""
164
+"%s [options] [command]\n"
165
+"  -h, --help                            Show this help\n"
166
+"      --version                         Show version\n"
167
+"  -d, --daemon                          Start as daemon (Default false)\n"
168
+"  -r, --remote                          Remote daemon name\n"
169
+"\n"
170
+msgstr ""
171
+"%s [opțiuni] [comandă]\n"
172
+"  -h, --help                            Arată acest ajutor\n"
173
+"      --version                         Arată versiunea\n"
174
+"  -d, --daemon                          Pornește ca demon (implicit fals)\n"
175
+"  -r, --remote                          Denumire demon distant\n"
176
+"\n"
177
+
178
+#: spa/plugins/alsa/acp/acp.c:321
179
+msgid "Pro Audio"
180
+msgstr "Pro Audio"
181
+
182
+#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648
183
+#: spa/plugins/bluez5/bluez5-device.c:1145
184
+msgid "Off"
185
+msgstr "Oprit"
186
+
187
+#: spa/plugins/alsa/acp/alsa-mixer.c:2652
188
+msgid "Input"
189
+msgstr "Intrare"
190
+
191
+#: spa/plugins/alsa/acp/alsa-mixer.c:2653
192
+msgid "Docking Station Input"
193
+msgstr "Intrare stație de andocare"
194
+
195
+#: spa/plugins/alsa/acp/alsa-mixer.c:2654
196
+msgid "Docking Station Microphone"
197
+msgstr "Microfon stație de andocare"
198
+
199
+#: spa/plugins/alsa/acp/alsa-mixer.c:2655
200
+msgid "Docking Station Line In"
201
pipewire-0.3.45.tar.gz/po/sv.po -> pipewire-0.3.47.tar.gz/po/sv.po Changed
201
 
1
@@ -1,9 +1,9 @@
2
 # Swedish translation for pipewire.
3
-# Copyright © 2008-2021 Free Software Foundation, Inc.
4
+# Copyright © 2008-2022 Free Software Foundation, Inc.
5
 # This file is distributed under the same license as the pipewire package.
6
 # Daniel Nylander <po@danielnylander.se>, 2008, 2012.
7
 # Josef Andersson <josef.andersson@fripost.org>, 2014, 2017.
8
-# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2021.
9
+# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2021, 2022.
10
 #
11
 # Termer:
12
 # input/output: ingång/utgång (det handlar om ljud)
13
@@ -19,8 +19,8 @@
14
 "Project-Id-Version: pipewire\n"
15
 "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
16
 "issues\n"
17
-"POT-Creation-Date: 2021-09-21 15:31+0000\n"
18
-"PO-Revision-Date: 2021-09-21 21:51+0200\n"
19
+"POT-Creation-Date: 2022-02-13 15:33+0000\n"
20
+"PO-Revision-Date: 2022-02-14 22:57+0100\n"
21
 "Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\n"
22
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
23
 "Language: sv\n"
24
@@ -28,7 +28,7 @@
25
 "Content-Type: text/plain; charset=UTF-8\n"
26
 "Content-Transfer-Encoding: 8bit\n"
27
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
28
-"X-Generator: Poedit 3.0\n"
29
+"X-Generator: Poedit 3.0.1\n"
30
 
31
 #: src/daemon/pipewire.c:45
32
 #, c-format
33
@@ -51,43 +51,36 @@
34
 msgid "Start the PipeWire Media System"
35
 msgstr "Starta mediasystemet PipeWire"
36
 
37
-#: src/examples/media-session/alsa-monitor.c:656
38
-#: spa/plugins/alsa/acp/compat.c:189
39
-msgid "Built-in Audio"
40
-msgstr "Inbyggt ljud"
41
-
42
-#: src/examples/media-session/alsa-monitor.c:660
43
-#: spa/plugins/alsa/acp/compat.c:194
44
-msgid "Modem"
45
-msgstr "Modem"
46
-
47
-#: src/examples/media-session/alsa-monitor.c:669
48
-#: src/modules/module-zeroconf-discover.c:296
49
-msgid "Unknown device"
50
-msgstr "Okänd enhet"
51
-
52
-#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:173
53
-#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:173
54
+#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:188
55
+#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:188
56
 #, c-format
57
 msgid "Tunnel to %s/%s"
58
 msgstr "Tunnel till %s/%s"
59
 
60
-#: src/modules/module-pulse-tunnel.c:534
61
+#: src/modules/module-fallback-sink.c:51
62
+msgid "Dummy Output"
63
+msgstr "Attrapputgång"
64
+
65
+#: src/modules/module-pulse-tunnel.c:536
66
 #, c-format
67
 msgid "Tunnel for %s@%s"
68
 msgstr "Tunnel för %s@%s"
69
 
70
-#: src/modules/module-zeroconf-discover.c:308
71
+#: src/modules/module-zeroconf-discover.c:332
72
+msgid "Unknown device"
73
+msgstr "Okänd enhet"
74
+
75
+#: src/modules/module-zeroconf-discover.c:344
76
 #, c-format
77
 msgid "%s on %s@%s"
78
 msgstr "%s på %s@%s"
79
 
80
-#: src/modules/module-zeroconf-discover.c:312
81
+#: src/modules/module-zeroconf-discover.c:348
82
 #, c-format
83
 msgid "%s on %s"
84
 msgstr "%s på %s"
85
 
86
-#: src/tools/pw-cat.c:1055
87
+#: src/tools/pw-cat.c:1075
88
 #, c-format
89
 msgid ""
90
 "%s [options] <file>\n"
91
@@ -102,7 +95,7 @@
92
 "  -v, --verbose                         Aktivera utförliga operationer\n"
93
 "\n"
94
 
95
-#: src/tools/pw-cat.c:1062
96
+#: src/tools/pw-cat.c:1082
97
 #, c-format
98
 msgid ""
99
 "  -R, --remote                          Remote daemon name\n"
100
@@ -132,7 +125,7 @@
101
 "      --list-targets                    Lista tillgängliga mål för --target\n"
102
 "\n"
103
 
104
-#: src/tools/pw-cat.c:1080
105
+#: src/tools/pw-cat.c:1100
106
 #, c-format
107
 msgid ""
108
 "      --rate                            Sample rate (req. for rec) (default "
109
@@ -167,7 +160,7 @@
110
 "%d)\n"
111
 "\n"
112
 
113
-#: src/tools/pw-cat.c:1097
114
+#: src/tools/pw-cat.c:1117
115
 msgid ""
116
 "  -p, --playback                        Playback mode\n"
117
 "  -r, --record                          Recording mode\n"
118
@@ -181,7 +174,7 @@
119
 "  -d, --dsd                             DSD-läge\n"
120
 "\n"
121
 
122
-#: src/tools/pw-cli.c:2954
123
+#: src/tools/pw-cli.c:3050
124
 #, c-format
125
 msgid ""
126
 "%s [options] [command]\n"
127
@@ -198,12 +191,12 @@
128
 "  -r, --remote                          Fjärrdemonnamn\n"
129
 "\n"
130
 
131
-#: spa/plugins/alsa/acp/acp.c:310
132
+#: spa/plugins/alsa/acp/acp.c:321
133
 msgid "Pro Audio"
134
 msgstr "Professionellt ljud"
135
 
136
-#: spa/plugins/alsa/acp/acp.c:433 spa/plugins/alsa/acp/alsa-mixer.c:4648
137
-#: spa/plugins/bluez5/bluez5-device.c:1135
138
+#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648
139
+#: spa/plugins/bluez5/bluez5-device.c:1159
140
 msgid "Off"
141
 msgstr "Av"
142
 
143
@@ -230,7 +223,7 @@
144
 
145
 #: spa/plugins/alsa/acp/alsa-mixer.c:2657
146
 #: spa/plugins/alsa/acp/alsa-mixer.c:2741
147
-#: spa/plugins/bluez5/bluez5-device.c:1292
148
+#: spa/plugins/bluez5/bluez5-device.c:1328
149
 msgid "Microphone"
150
 msgstr "Mikrofon"
151
 
152
@@ -296,7 +289,7 @@
153
 msgstr "Ingen basökning"
154
 
155
 #: spa/plugins/alsa/acp/alsa-mixer.c:2672
156
-#: spa/plugins/bluez5/bluez5-device.c:1297
157
+#: spa/plugins/bluez5/bluez5-device.c:1333
158
 msgid "Speaker"
159
 msgstr "Högtalare"
160
 
161
@@ -411,7 +404,7 @@
162
 
163
 #: spa/plugins/alsa/acp/alsa-mixer.c:4484
164
 #: spa/plugins/alsa/acp/alsa-mixer.c:4642
165
-#: spa/plugins/bluez5/bluez5-device.c:1282
166
+#: spa/plugins/bluez5/bluez5-device.c:1318
167
 msgid "Headset"
168
 msgstr "Headset"
169
 
170
@@ -561,13 +554,13 @@
171
 #: spa/plugins/alsa/acp/alsa-util.c:1239
172
 #, c-format
173
 msgid ""
174
-"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s"
175
-"%lu ms).\n"
176
+"snd_pcm_delay() returned a value that is exceptionally large: %li byte "
177
+"(%s%lu ms).\n"
178
 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
179
 "to the ALSA developers."
180
 msgid_plural ""
181
-"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s"
182
-"%lu ms).\n"
183
+"snd_pcm_delay() returned a value that is exceptionally large: %li bytes "
184
+"(%s%lu ms).\n"
185
 "Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
186
 "to the ALSA developers."
187
 msgstr[0] ""
188
@@ -617,65 +610,73 @@
189
 "Förmodligen är detta ett fel i ALSA-drivrutinen ”%s”. Vänligen rapportera "
190
 "problemet till ALSA-utvecklarna."
191
 
192
-#: spa/plugins/alsa/acp/channelmap.h:466
193
+#: spa/plugins/alsa/acp/channelmap.h:464
194
 msgid "(invalid)"
195
 msgstr "(ogiltig)"
196
 
197
-#: spa/plugins/bluez5/bluez5-device.c:1145
198
+#: spa/plugins/alsa/acp/compat.c:189
199
+msgid "Built-in Audio"
200
+msgstr "Inbyggt ljud"
201
pipewire-0.3.45.tar.gz/spa/include/meson.build -> pipewire-0.3.47.tar.gz/spa/include/meson.build Changed
9
 
1
@@ -3,6 +3,7 @@
2
   'control',
3
   'debug',
4
   'graph',
5
+  'interfaces',
6
   'monitor',
7
   'node',
8
   'param',
9
pipewire-0.3.45.tar.gz/spa/include/spa/debug/buffer.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/buffer.h Changed
17
 
1
@@ -38,14 +38,11 @@
2
  * \{
3
  */
4
 
5
+#include <spa/debug/log.h>
6
 #include <spa/debug/mem.h>
7
 #include <spa/debug/types.h>
8
 #include <spa/buffer/type-info.h>
9
 
10
-#ifndef spa_debug
11
-#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
12
-#endif
13
-
14
 static inline int spa_debug_buffer(int indent, const struct spa_buffer *buffer)
15
 {
16
    uint32_t i;
17
pipewire-0.3.45.tar.gz/spa/include/spa/debug/dict.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/dict.h Changed
15
 
1
@@ -34,12 +34,9 @@
2
  * \{
3
  */
4
 
5
+#include <spa/debug/log.h>
6
 #include <spa/utils/dict.h>
7
 
8
-#ifndef spa_debug
9
-#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
10
-#endif
11
-
12
 static inline int spa_debug_dict(int indent, const struct spa_dict *dict)
13
 {
14
    const struct spa_dict_item *item;
15
pipewire-0.3.45.tar.gz/spa/include/spa/debug/format.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/format.h Changed
132
 
1
@@ -35,6 +35,7 @@
2
  */
3
 
4
 #include <spa/pod/parser.h>
5
+#include <spa/debug/log.h>
6
 #include <spa/debug/types.h>
7
 #include <spa/param/type-info.h>
8
 #include <spa/param/format-utils.h>
9
@@ -45,7 +46,7 @@
10
 {
11
    switch (type) {
12
    case SPA_TYPE_Bool:
13
-       fprintf(stderr, "%s", *(int32_t *) body ? "true" : "false");
14
+       spa_debugn("%s", *(int32_t *) body ? "true" : "false");
15
        break;
16
    case SPA_TYPE_Id:
17
    {
18
@@ -55,41 +56,41 @@
19
            snprintf(tmp, sizeof(tmp), "%d", *(int32_t*)body);
20
            str = tmp;
21
        }
22
-       fprintf(stderr, "%s", str);
23
+       spa_debugn("%s", str);
24
        break;
25
    }
26
    case SPA_TYPE_Int:
27
-       fprintf(stderr, "%d", *(int32_t *) body);
28
+       spa_debugn("%d", *(int32_t *) body);
29
        break;
30
    case SPA_TYPE_Long:
31
-       fprintf(stderr, "%" PRIi64, *(int64_t *) body);
32
+       spa_debugn("%" PRIi64, *(int64_t *) body);
33
        break;
34
    case SPA_TYPE_Float:
35
-       fprintf(stderr, "%f", *(float *) body);
36
+       spa_debugn("%f", *(float *) body);
37
        break;
38
    case SPA_TYPE_Double:
39
-       fprintf(stderr, "%g", *(double *) body);
40
+       spa_debugn("%g", *(double *) body);
41
        break;
42
    case SPA_TYPE_String:
43
-       fprintf(stderr, "%s", (char *) body);
44
+       spa_debugn("%s", (char *) body);
45
        break;
46
    case SPA_TYPE_Rectangle:
47
    {
48
        struct spa_rectangle *r = (struct spa_rectangle *)body;
49
-       fprintf(stderr, "%" PRIu32 "x%" PRIu32, r->width, r->height);
50
+       spa_debugn("%" PRIu32 "x%" PRIu32, r->width, r->height);
51
        break;
52
    }
53
    case SPA_TYPE_Fraction:
54
    {
55
        struct spa_fraction *f = (struct spa_fraction *)body;
56
-       fprintf(stderr, "%" PRIu32 "/%" PRIu32, f->num, f->denom);
57
+       spa_debugn("%" PRIu32 "/%" PRIu32, f->num, f->denom);
58
        break;
59
    }
60
    case SPA_TYPE_Bitmap:
61
-       fprintf(stderr, "Bitmap");
62
+       spa_debugn("Bitmap");
63
        break;
64
    case SPA_TYPE_Bytes:
65
-       fprintf(stderr, "Bytes");
66
+       spa_debugn("Bytes");
67
        break;
68
    case SPA_TYPE_Array:
69
    {
70
@@ -97,17 +98,17 @@
71
        struct spa_pod_array_body *b = (struct spa_pod_array_body *)body;
72
        int i = 0;
73
        info = info && info->values ? info->values : info;
74
-       fprintf(stderr, "< ");
75
+       spa_debugn("< ");
76
        SPA_POD_ARRAY_BODY_FOREACH(b, size, p) {
77
            if (i++ > 0)
78
-               fprintf(stderr, ", ");
79
+               spa_debugn(", ");
80
            spa_debug_format_value(info, b->child.type, p, b->child.size);
81
        }
82
-       fprintf(stderr, " >");
83
+       spa_debugn(" >");
84
        break;
85
    }
86
    default:
87
-       fprintf(stderr, "INVALID type %d", type);
88
+       spa_debugn("INVALID type %d", type);
89
        break;
90
    }
91
    return 0;
92
@@ -133,7 +134,7 @@
93
    media_type = spa_debug_type_find_name(spa_type_media_type, mtype);
94
    media_subtype = spa_debug_type_find_name(spa_type_media_subtype, mstype);
95
 
96
-   fprintf(stderr, "%*s %s/%s\n", indent, "",
97
+   spa_debug("%*s %s/%s", indent, "",
98
        media_type ? spa_debug_type_short_name(media_type) : "unknown",
99
        media_subtype ? spa_debug_type_short_name(media_subtype) : "unknown");
100
 
101
@@ -160,7 +161,7 @@
102
        ti = spa_debug_type_find(info, prop->key);
103
        key = ti ? ti->name : NULL;
104
 
105
-       fprintf(stderr, "%*s %16s : (%s) ", indent, "",
106
+       spa_debugn("%*s %16s : (%s) ", indent, "",
107
            key ? spa_debug_type_short_name(key) : "unknown",
108
            spa_debug_type_short_name(spa_types[type].name));
109
 
110
@@ -185,17 +186,17 @@
111
                break;
112
            }
113
 
114
-           fprintf(stderr, "%s", ssep);
115
+           spa_debugn("%s", ssep);
116
 
117
            for (i = 1; i < n_vals; i++) {
118
                vals = SPA_PTROFF(vals, size, void);
119
                if (i > 1)
120
-                   fprintf(stderr, "%s", sep);
121
+                   spa_debugn("%s", sep);
122
                spa_debug_format_value(ti ? ti->values : NULL, type, vals, size);
123
            }
124
-           fprintf(stderr, "%s", esep);
125
+           spa_debugn("%s", esep);
126
        }
127
-       fprintf(stderr, "\n");
128
+       spa_debugn("\n");
129
    }
130
    return 0;
131
 }
132
pipewire-0.3.47.tar.gz/spa/include/spa/debug/log.h Added
55
 
1
@@ -0,0 +1,53 @@
2
+/* Simple Plugin API
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef SPA_DEBUG_LOG_H
27
+#define SPA_DEBUG_LOG_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+#include <stdio.h>
34
+/**
35
+ * \addtogroup spa_debug
36
+ * \{
37
+ */
38
+
39
+#ifndef spa_debug
40
+#define spa_debug(fmt,...) ({ printf(fmt"\n", ## __VA_ARGS__); })
41
+#endif
42
+#ifndef spa_debugn
43
+#define spa_debugn(fmt,...)    ({ printf(fmt, ## __VA_ARGS__); })
44
+#endif
45
+
46
+/**
47
+ * \}
48
+ */
49
+
50
+#ifdef __cplusplus
51
+}  /* extern "C" */
52
+#endif
53
+
54
+#endif /* SPA_DEBUG_LOGH */
55
pipewire-0.3.45.tar.gz/spa/include/spa/debug/mem.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/mem.h Changed
21
 
1
@@ -29,16 +29,14 @@
2
 extern "C" {
3
 #endif
4
 
5
+#include <inttypes.h>
6
+
7
 /**
8
  * \addtogroup spa_debug
9
  * \{
10
  */
11
 
12
-#include <spa/utils/dict.h>
13
-
14
-#ifndef spa_debug
15
-#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
16
-#endif
17
+#include <spa/debug/log.h>
18
 
19
 static inline int spa_debug_mem(int indent, const void *data, size_t size)
20
 {
21
pipewire-0.3.45.tar.gz/spa/include/spa/debug/node.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/node.h Changed
15
 
1
@@ -35,12 +35,9 @@
2
  */
3
 
4
 #include <spa/node/node.h>
5
+#include <spa/debug/log.h>
6
 #include <spa/debug/dict.h>
7
 
8
-#ifndef spa_debug
9
-#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
10
-#endif
11
-
12
 static inline int spa_debug_port_info(int indent, const struct spa_port_info *info)
13
 {
14
         spa_debug("%*s" "struct spa_port_info %p:", indent, "", info);
15
pipewire-0.3.45.tar.gz/spa/include/spa/debug/pod.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/pod.h Changed
18
 
1
@@ -34,15 +34,12 @@
2
  * \{
3
  */
4
 
5
+#include <spa/debug/log.h>
6
 #include <spa/debug/mem.h>
7
 #include <spa/debug/types.h>
8
 #include <spa/pod/pod.h>
9
 #include <spa/pod/iter.h>
10
 
11
-#ifndef spa_debug
12
-#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
13
-#endif
14
-
15
 static inline int
16
 spa_debug_pod_value(int indent, const struct spa_type_info *info,
17
        uint32_t type, void *body, uint32_t size)
18
pipewire-0.3.47.tar.gz/spa/include/spa/interfaces Added
2
 
1
+(directory)
2
pipewire-0.3.47.tar.gz/spa/include/spa/interfaces/audio Added
2
 
1
+(directory)
2
pipewire-0.3.47.tar.gz/spa/include/spa/interfaces/audio/aec.h Added
97
 
1
@@ -0,0 +1,95 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+
27
+#include <spa/utils/dict.h>
28
+#include <spa/utils/hook.h>
29
+#include <spa/param/audio/raw.h>
30
+
31
+#ifndef SPA_AUDIO_AEC_H
32
+#define SPA_AUDIO_AEC_H
33
+
34
+#ifdef __cplusplus
35
+extern "C" {
36
+#endif
37
+
38
+#define SPA_TYPE_INTERFACE_AUDIO_AEC SPA_TYPE_INFO_INTERFACE_BASE "Audio:AEC"
39
+
40
+#define SPA_VERSION_AUDIO_AEC   0
41
+struct spa_audio_aec {
42
+   struct spa_interface iface;
43
+   const char *name;
44
+   const struct spa_dict *info;
45
+   const char *latency;
46
+};
47
+
48
+struct spa_audio_aec_info {
49
+#define SPA_AUDIO_AEC_CHANGE_MASK_PROPS    (1u<<0)
50
+        uint64_t change_mask;
51
+
52
+   const struct spa_dict *props;
53
+};
54
+
55
+struct spa_audio_aec_events {
56
+#define SPA_VERSION_AUDIO_AEC_EVENTS   0
57
+        uint32_t version;       /**< version of this structure */
58
+
59
+   /** Emitted when info changes */
60
+   void (*info) (void *data, const struct spa_audio_aec_info *info);
61
+};
62
+
63
+struct spa_audio_aec_methods {
64
+#define SPA_VERSION_AUDIO_AEC_METHODS  0
65
+        uint32_t version;
66
+
67
+   int (*add_listener) (void *object,
68
+           struct spa_hook *listener,
69
+           const struct spa_audio_aec_events *events,
70
+           void *data);
71
+
72
+   int (*init) (void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info);
73
+   int (*run) (void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples);
74
+   int (*set_props) (void *data, const struct spa_dict *args);
75
+};
76
+
77
+#define spa_audio_aec_method(o,method,version,...)         \
78
+({                                 \
79
+   int _res = -ENOTSUP;                        \
80
+   struct spa_audio_aec *_o = o;                   \
81
+   spa_interface_call_res(&_o->iface,              \
82
+           struct spa_audio_aec_methods, _res,     \
83
+           method, version, ##__VA_ARGS__);        \
84
+   _res;                               \
85
+})
86
+
87
+#define spa_audio_aec_add_listener(o,...)  spa_audio_aec_method(o, add_listener, 0, __VA_ARGS__)
88
+#define spa_audio_aec_init(o,...)      spa_audio_aec_method(o, init, 0, __VA_ARGS__)
89
+#define spa_audio_aec_run(o,...)       spa_audio_aec_method(o, run, 0, __VA_ARGS__)
90
+#define spa_audio_aec_set_props(o,...)     spa_audio_aec_method(o, set_props, 0, __VA_ARGS__)
91
+
92
+#ifdef __cplusplus
93
+}  /* extern "C" */
94
+#endif
95
+
96
+#endif /* SPA_AUDIO_AEC_H */
97
pipewire-0.3.45.tar.gz/spa/include/spa/support/loop.h -> pipewire-0.3.47.tar.gz/spa/include/spa/support/loop.h Changed
10
 
1
@@ -66,6 +66,8 @@
2
    int fd;
3
    uint32_t mask;
4
    uint32_t rmask;
5
+   /* private data for the loop implementer */
6
+   void *priv;
7
 };
8
 
9
 typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
10
pipewire-0.3.45.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.47.tar.gz/spa/include/spa/utils/defs.h Changed
11
 
1
@@ -228,6 +228,9 @@
2
 #define SPA_RESTRICT
3
 #endif
4
 
5
+#define SPA_ROUND_DOWN(num,value)  ((num) - ((num) % (value)))
6
+#define SPA_ROUND_UP(num,value)        ((((num) + (value) - 1) / (value)) * (value))
7
+
8
 #define SPA_ROUND_DOWN_N(num,align)    ((num) & ~((align) - 1))
9
 #define SPA_ROUND_UP_N(num,align)  SPA_ROUND_DOWN_N((num) + ((align) - 1),align)
10
 
11
pipewire-0.3.45.tar.gz/spa/include/spa/utils/names.h -> pipewire-0.3.47.tar.gz/spa/include/spa/utils/names.h Changed
10
 
1
@@ -82,6 +82,8 @@
2
 #define SPA_NAME_AUDIO_ADAPT       "audio.adapt"           /**< combination of a node and an
3
                                      *  audio.convert. Does clock slaving */
4
 
5
+#define SPA_NAME_AEC               "audio.aec"             /**< Echo canceling */
6
+
7
 /** video processing */
8
 #define SPA_NAME_VIDEO_PROCESS_FORMAT  "video.process.format"      /**< processes raw video from one format
9
                                      *  to another */
10
pipewire-0.3.45.tar.gz/spa/meson.build -> pipewire-0.3.47.tar.gz/spa/meson.build Changed
18
 
1
@@ -31,7 +31,7 @@
2
 
3
 subdir('include')
4
 
5
-if not get_option('spa-plugins').disabled()
6
+if get_option('spa-plugins').allowed()
7
   udevrulesdir = get_option('udevrulesdir')
8
   if udevrulesdir == ''
9
     # absolute path, otherwise meson prepends the prefix
10
@@ -74,6 +74,6 @@
11
 
12
 subdir('tools')
13
 subdir('tests')
14
-if not get_option('examples').disabled()
15
+if get_option('examples').allowed()
16
   subdir('examples')
17
 endif
18
pipewire-0.3.47.tar.gz/spa/plugins/aec Added
2
 
1
+(directory)
2
pipewire-0.3.47.tar.gz/spa/plugins/aec/aec-null.c Added
181
 
1
@@ -0,0 +1,179 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <spa/interfaces/audio/aec.h>
27
+#include <spa/support/log.h>
28
+#include <spa/utils/string.h>
29
+#include <spa/utils/names.h>
30
+#include <spa/support/plugin.h>
31
+
32
+struct impl {
33
+   struct spa_handle handle;
34
+   struct spa_audio_aec aec;
35
+   struct spa_log *log;
36
+
37
+   struct spa_hook_list hooks_list;
38
+
39
+   uint32_t channels;
40
+};
41
+
42
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.aec.null");
43
+#undef SPA_LOG_TOPIC_DEFAULT
44
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
45
+
46
+static int null_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info)
47
+{
48
+   struct impl *impl = data;
49
+   impl->channels = info->channels;
50
+   return 0;
51
+}
52
+
53
+static int null_run(void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
54
+{
55
+   struct impl *impl = data;
56
+   uint32_t i;
57
+   for (i = 0; i < impl->channels; i++)
58
+       memcpy(out[i], rec[i], n_samples * sizeof(float));
59
+   return 0;
60
+}
61
+
62
+static struct spa_audio_aec_methods impl_aec = {
63
+   .init = null_init,
64
+   .run = null_run,
65
+};
66
+
67
+static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
68
+{
69
+   struct impl *impl;
70
+
71
+   spa_return_val_if_fail(handle != NULL, -EINVAL);
72
+   spa_return_val_if_fail(interface != NULL, -EINVAL);
73
+
74
+   impl = (struct impl *) handle;
75
+
76
+   if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC))
77
+       *interface = &impl->aec;
78
+   else
79
+       return -ENOENT;
80
+
81
+   return 0;
82
+}
83
+
84
+static int impl_clear(struct spa_handle *handle)
85
+{
86
+   spa_return_val_if_fail(handle != NULL, -EINVAL);
87
+
88
+   return 0;
89
+}
90
+
91
+static size_t
92
+impl_get_size(const struct spa_handle_factory *factory,
93
+         const struct spa_dict *params)
94
+{
95
+   return sizeof(struct impl);
96
+}
97
+
98
+static int
99
+impl_init(const struct spa_handle_factory *factory,
100
+     struct spa_handle *handle,
101
+     const struct spa_dict *info,
102
+     const struct spa_support *support,
103
+     uint32_t n_support)
104
+{
105
+   struct impl *impl;
106
+
107
+   spa_return_val_if_fail(factory != NULL, -EINVAL);
108
+   spa_return_val_if_fail(handle != NULL, -EINVAL);
109
+
110
+   handle->get_interface = impl_get_interface;
111
+   handle->clear = impl_clear;
112
+
113
+   impl = (struct impl *) handle;
114
+
115
+   impl->aec.iface = SPA_INTERFACE_INIT(
116
+       SPA_TYPE_INTERFACE_AUDIO_AEC,
117
+       SPA_VERSION_AUDIO_AEC,
118
+       &impl_aec, impl);
119
+   impl->aec.name = "null";
120
+   impl->aec.info = NULL;
121
+   impl->aec.latency = NULL;
122
+
123
+   impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
124
+   spa_log_topic_init(impl->log, &log_topic);
125
+
126
+   spa_hook_list_init(&impl->hooks_list);
127
+
128
+   return 0;
129
+}
130
+
131
+static const struct spa_interface_info impl_interfaces[] = {
132
+   {SPA_TYPE_INTERFACE_AUDIO_AEC,},
133
+};
134
+
135
+static int
136
+impl_enum_interface_info(const struct spa_handle_factory *factory,
137
+            const struct spa_interface_info **info,
138
+            uint32_t *index)
139
+{
140
+   spa_return_val_if_fail(factory != NULL, -EINVAL);
141
+   spa_return_val_if_fail(info != NULL, -EINVAL);
142
+   spa_return_val_if_fail(index != NULL, -EINVAL);
143
+
144
+   switch (*index) {
145
+   case 0:
146
+       *info = &impl_interfaces[*index];
147
+       break;
148
+   default:
149
+       return 0;
150
+   }
151
+   (*index)++;
152
+   return 1;
153
+}
154
+
155
+const struct spa_handle_factory spa_aec_exaudio_factory = {
156
+   SPA_VERSION_HANDLE_FACTORY,
157
+   SPA_NAME_AEC,
158
+   NULL,
159
+   impl_get_size,
160
+   impl_init,
161
+   impl_enum_interface_info,
162
+};
163
+
164
+
165
+SPA_EXPORT
166
+int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index)
167
+{
168
+   spa_return_val_if_fail(factory != NULL, -EINVAL);
169
+   spa_return_val_if_fail(index != NULL, -EINVAL);
170
+
171
+   switch (*index) {
172
+   case 0:
173
+       *factory = &spa_aec_exaudio_factory;
174
+       break;
175
+   default:
176
+       return 0;
177
+   }
178
+   (*index)++;
179
+   return 1;
180
+}
181
pipewire-0.3.47.tar.gz/spa/plugins/aec/aec-webrtc.cpp Added
201
 
1
@@ -0,0 +1,278 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
5
+ *           © 2021 Arun Raghavan <arun@asymptotic.io>
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a
8
+ * copy of this software and associated documentation files (the "Software"),
9
+ * to deal in the Software without restriction, including without limitation
10
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
+ * and/or sell copies of the Software, and to permit persons to whom the
12
+ * Software is furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice (including the next
15
+ * paragraph) shall be included in all copies or substantial portions of the
16
+ * Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
+ * DEALINGS IN THE SOFTWARE.
25
+ */
26
+
27
+#include <memory>
28
+#include <utility>
29
+
30
+#include <spa/interfaces/audio/aec.h>
31
+#include <spa/support/log.h>
32
+#include <spa/utils/string.h>
33
+#include <spa/utils/names.h>
34
+#include <spa/support/plugin.h>
35
+
36
+#include <webrtc/modules/audio_processing/include/audio_processing.h>
37
+#include <webrtc/modules/interface/module_common_types.h>
38
+#include <webrtc/system_wrappers/include/trace.h>
39
+
40
+struct impl_data {
41
+   struct spa_handle handle;
42
+   struct spa_audio_aec aec;
43
+
44
+   struct spa_log *log;
45
+   std::unique_ptr<webrtc::AudioProcessing> apm;
46
+   spa_audio_info_raw info;
47
+   std::unique_ptr<float *[]> play_buffer, rec_buffer, out_buffer;
48
+};
49
+
50
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.eac.webrtc");
51
+#undef SPA_LOG_TOPIC_DEFAULT
52
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
53
+
54
+static bool webrtc_get_spa_bool(const struct spa_dict *args, const char *key, bool default_value) {
55
+   const char *str_val;
56
+   bool value = default_value;
57
+   str_val = spa_dict_lookup(args, key);
58
+   if (str_val != NULL)
59
+       value =spa_atob(str_val);
60
+
61
+   return value;
62
+}
63
+
64
+static int webrtc_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info)
65
+{
66
+   auto impl = reinterpret_cast<struct impl_data*>(data);
67
+
68
+   bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true);
69
+   bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true);
70
+   bool high_pass_filter = webrtc_get_spa_bool(args, "webrtc.high_pass_filter", true);
71
+   bool noise_suppression = webrtc_get_spa_bool(args, "webrtc.noise_suppression", true);
72
+   bool voice_detection = webrtc_get_spa_bool(args, "webrtc.voice_detection", true);
73
+
74
+   // Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech,
75
+   // result in very poor performance, disable by default
76
+   bool gain_control = webrtc_get_spa_bool(args, "webrtc.gain_control", false);
77
+
78
+   // Disable experimental flags by default
79
+   bool experimental_agc = webrtc_get_spa_bool(args, "webrtc.experimental_agc", false);
80
+   bool experimental_ns = webrtc_get_spa_bool(args, "webrtc.experimental_ns", false);
81
+
82
+   // FIXME: Intelligibility enhancer is not currently supported
83
+   // This filter will modify playback buffer (when calling ProcessReverseStream), but now
84
+   // playback buffer modifications are discarded.
85
+
86
+   webrtc::Config config;
87
+   config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter));
88
+   config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic));
89
+   config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc));
90
+   config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns));
91
+
92
+   webrtc::ProcessingConfig pconfig = {{
93
+       webrtc::StreamConfig(info->rate, info->channels, false), /* input stream */
94
+       webrtc::StreamConfig(info->rate, info->channels, false), /* output stream */
95
+       webrtc::StreamConfig(info->rate, info->channels, false), /* reverse input stream */
96
+       webrtc::StreamConfig(info->rate, info->channels, false), /* reverse output stream */
97
+   }};
98
+
99
+   auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config));
100
+   if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) {
101
+       spa_log_error(impl->log, "Error initialising webrtc audio processing module");
102
+       return -1;
103
+   }
104
+
105
+   apm->high_pass_filter()->Enable(high_pass_filter);
106
+   // Always disable drift compensation since it requires drift sampling
107
+   apm->echo_cancellation()->enable_drift_compensation(false);
108
+   apm->echo_cancellation()->Enable(true);
109
+   // TODO: wire up supression levels to args
110
+   apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression);
111
+   apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh);
112
+   apm->noise_suppression()->Enable(noise_suppression);
113
+   apm->voice_detection()->Enable(voice_detection);
114
+   // TODO: wire up AGC parameters to args
115
+   apm->gain_control()->set_analog_level_limits(0, 255);
116
+   apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
117
+   apm->gain_control()->Enable(gain_control);
118
+   impl->apm = std::move(apm);
119
+   impl->info = *info;
120
+   impl->play_buffer = std::make_unique<float *[]>(info->channels);
121
+   impl->rec_buffer = std::make_unique<float *[]>(info->channels);
122
+   impl->out_buffer = std::make_unique<float *[]>(info->channels);
123
+   return 0;
124
+}
125
+
126
+static int webrtc_run(void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
127
+{
128
+   auto impl = reinterpret_cast<struct impl_data*>(data);
129
+   webrtc::StreamConfig config =
130
+       webrtc::StreamConfig(impl->info.rate, impl->info.channels, false);
131
+   unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10;
132
+
133
+   if (n_samples * 1000 / impl->info.rate % 10 != 0) {
134
+       spa_log_error(impl->log, "Buffers must be multiples of 10ms in length (currently %u samples)", n_samples);
135
+       return -1;
136
+   }
137
+
138
+   for (size_t i = 0; i < num_blocks; i ++) {
139
+       for (size_t j = 0; j < impl->info.channels; j++) {
140
+           impl->play_buffer[j] = const_cast<float *>(play[j]) + config.num_frames() * i;
141
+           impl->rec_buffer[j] = const_cast<float *>(rec[j]) + config.num_frames() * i;
142
+           impl->out_buffer[j] = out[j] + config.num_frames() * i;
143
+       }
144
+       /* FIXME: ProcessReverseStream may change the playback buffer, in which
145
+       * case we should use that, if we ever expose the intelligibility
146
+       * enhancer */
147
+       if (impl->apm->ProcessReverseStream(impl->play_buffer.get(), config, config, impl->play_buffer.get()) !=
148
+               webrtc::AudioProcessing::kNoError) {
149
+           spa_log_error(impl->log, "Processing reverse stream failed");
150
+       }
151
+
152
+       // Extra delay introduced by multiple frames
153
+       impl->apm->set_stream_delay_ms((num_blocks - 1) * 10);
154
+
155
+       if (impl->apm->ProcessStream(impl->rec_buffer.get(), config, config, impl->out_buffer.get()) !=
156
+               webrtc::AudioProcessing::kNoError) {
157
+           spa_log_error(impl->log, "Processing stream failed");
158
+       }
159
+   }
160
+
161
+   return 0;
162
+}
163
+
164
+static struct spa_audio_aec_methods impl_aec = {
165
+   SPA_VERSION_AUDIO_AEC_METHODS,
166
+   .add_listener = NULL,
167
+   .init = webrtc_init,
168
+   .run = webrtc_run,
169
+};
170
+
171
+static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
172
+{
173
+   auto impl = reinterpret_cast<struct impl_data*>(handle);
174
+
175
+   spa_return_val_if_fail(handle != NULL, -EINVAL);
176
+   spa_return_val_if_fail(interface != NULL, -EINVAL);
177
+
178
+   if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC))
179
+       *interface = &impl->aec;
180
+   else
181
+       return -ENOENT;
182
+
183
+   return 0;
184
+}
185
+
186
+static int impl_clear(struct spa_handle *handle)
187
+{
188
+   spa_return_val_if_fail(handle != NULL, -EINVAL);
189
+   auto impl = reinterpret_cast<struct impl_data*>(handle);
190
+   impl->~impl_data();
191
+   return 0;
192
+}
193
+
194
+static size_t
195
+impl_get_size(const struct spa_handle_factory *factory,
196
+         const struct spa_dict *params)
197
+{
198
+   return sizeof(struct impl_data);
199
+}
200
+
201
pipewire-0.3.47.tar.gz/spa/plugins/aec/meson.build Added
18
 
1
@@ -0,0 +1,16 @@
2
+aec_null = shared_library('spa-aec-null',
3
+  [ 'aec-null.c' ],
4
+  include_directories : [ configinc ],
5
+  dependencies : [ spa_dep ],
6
+  install : true,
7
+  install_dir : spa_plugindir / 'aec')
8
+
9
+if webrtc_dep.found()
10
+  aec_webrtc = shared_library('spa-aec-webrtc',
11
+    [ 'aec-webrtc.cpp' ],
12
+    include_directories : [ configinc ],
13
+    dependencies : [ spa_dep, webrtc_dep ],
14
+    install : true,
15
+    install_dir : spa_plugindir / 'aec')
16
+endif
17
+
18
pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/alsa-pcm.c Changed
201
 
1
@@ -1516,8 +1516,10 @@
2
    /* get the current params */
3
    CHECK(snd_pcm_sw_params_current(hndl, params), "sw_params_current");
4
 
5
-   CHECK(snd_pcm_sw_params_set_tstamp_mode(hndl, params, SND_PCM_TSTAMP_ENABLE), "sw_params_set_tstamp_mode");
6
-
7
+   CHECK(snd_pcm_sw_params_set_tstamp_mode(hndl, params, SND_PCM_TSTAMP_ENABLE),
8
+           "sw_params_set_tstamp_mode");
9
+   CHECK(snd_pcm_sw_params_set_tstamp_type(hndl, params, SND_PCM_TSTAMP_TYPE_MONOTONIC),
10
+           "sw_params_set_tstamp_type");
11
 #if 0
12
    snd_pcm_uframes_t boundary;
13
    CHECK(snd_pcm_sw_params_get_boundary(params, &boundary), "get_boundary");
14
@@ -1644,6 +1646,9 @@
15
    case SND_PCM_STATE_SUSPENDED:
16
        spa_log_info(state->log, "%s: recover from state %s",
17
                state->props.device, snd_pcm_state_name(st));
18
+       res = snd_pcm_resume(state->hndl);
19
+       if (res >= 0)
20
+               return res;
21
        err = -ESTRPIPE;
22
        break;
23
    default:
24
@@ -1668,10 +1673,10 @@
25
    return do_start(state);
26
 }
27
 
28
-static int get_status(struct state *state, snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target)
29
+static int get_avail(struct state *state, uint64_t current_time)
30
 {
31
-   snd_pcm_sframes_t avail;
32
    int res;
33
+   snd_pcm_sframes_t avail;
34
 
35
    if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) {
36
        if ((res = alsa_recover(state, avail)) < 0)
37
@@ -1684,6 +1689,48 @@
38
    } else {
39
        state->alsa_recovering = false;
40
    }
41
+   return avail;
42
+}
43
+
44
+#if 0
45
+static int get_avail_htimestamp(struct state *state, uint64_t current_time)
46
+{
47
+   int res;
48
+   snd_pcm_uframes_t avail;
49
+   snd_htimestamp_t tstamp;
50
+   uint64_t then;
51
+
52
+   if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) {
53
+       if ((res = alsa_recover(state, avail)) < 0)
54
+           return res;
55
+       if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) {
56
+           spa_log_warn(state->log, "%s: snd_pcm_htimestamp error: %s",
57
+               state->props.device, snd_strerror(res));
58
+           avail = state->threshold * 2;
59
+       }
60
+   } else {
61
+       state->alsa_recovering = false;
62
+   }
63
+
64
+   if ((then = SPA_TIMESPEC_TO_NSEC(&tstamp)) != 0) {
65
+       if (then < current_time)
66
+           avail += (current_time - then) * state->rate / SPA_NSEC_PER_SEC;
67
+       else
68
+           avail -= (then - current_time) * state->rate / SPA_NSEC_PER_SEC;
69
+   }
70
+   return SPA_MIN(avail, state->buffer_frames);
71
+}
72
+#endif
73
+
74
+static int get_status(struct state *state, uint64_t current_time,
75
+       snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target)
76
+{
77
+   int avail;
78
+
79
+   if ((avail = get_avail(state, current_time)) < 0)
80
+       return avail;
81
+
82
+   avail = SPA_MIN(avail, (int)state->buffer_frames);
83
 
84
    *target = state->threshold + state->headroom;
85
 
86
@@ -1704,7 +1751,7 @@
87
    return 0;
88
 }
89
 
90
-static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t delay,
91
+static int update_time(struct state *state, uint64_t current_time, snd_pcm_sframes_t delay,
92
        snd_pcm_sframes_t target, bool follower)
93
 {
94
    double err, corr;
95
@@ -1717,8 +1764,8 @@
96
 
97
    if (SPA_UNLIKELY(state->dll.bw == 0.0)) {
98
        spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate);
99
-       state->next_time = nsec;
100
-       state->base_time = nsec;
101
+       state->next_time = current_time;
102
+       state->base_time = current_time;
103
    }
104
    diff = (int32_t) (state->last_threshold - state->threshold);
105
 
106
@@ -1727,9 +1774,20 @@
107
        spa_log_trace(state->log, "%p: follower:%d quantum change %d -> %d (%d) %f",
108
                state, follower, state->last_threshold, state->threshold, diff, err);
109
        state->last_threshold = state->threshold;
110
+       state->alsa_sync = true;
111
    }
112
-   err = SPA_CLAMP(err, -state->max_error, state->max_error);
113
-   corr = spa_dll_update(&state->dll, err);
114
+   if (err > state->max_error) {
115
+       err = state->max_error;
116
+       state->alsa_sync = true;
117
+   } else if (err < -state->max_error) {
118
+       err = -state->max_error;
119
+       state->alsa_sync = true;
120
+   }
121
+
122
+   if (!follower || state->matching)
123
+       corr = spa_dll_update(&state->dll, err);
124
+   else
125
+       corr = 1.0;
126
 
127
    if (diff < 0)
128
        state->next_time += diff / corr * 1e9 / state->rate;
129
@@ -1737,11 +1795,11 @@
130
    if (SPA_UNLIKELY((state->next_time - state->base_time) > BW_PERIOD)) {
131
        state->base_time = state->next_time;
132
 
133
-       spa_log_debug(state->log, "%p: follower:%d match:%d rate:%f "
134
-               "bw:%f thr:%u del:%ld target:%ld err:%f",
135
-               state, follower, state->matching, corr, state->dll.bw,
136
-               state->threshold, delay, target,
137
-               err);
138
+       spa_log_debug(state->log, "%s: follower:%d match:%d rate:%f "
139
+               "bw:%f thr:%u del:%ld target:%ld err:%f max:%f",
140
+               state->props.device, follower, state->matching,
141
+               corr, state->dll.bw, state->threshold, delay, target,
142
+               err, state->max_error);
143
    }
144
 
145
    if (state->rate_match) {
146
@@ -1756,7 +1814,7 @@
147
    state->next_time += state->threshold / corr * 1e9 / state->rate;
148
 
149
    if (SPA_LIKELY(!follower && state->clock)) {
150
-       state->clock->nsec = nsec;
151
+       state->clock->nsec = current_time;
152
        state->clock->position += state->duration;
153
        state->clock->duration = state->duration;
154
        state->clock->delay = delay + state->delay;
155
@@ -1765,7 +1823,7 @@
156
    }
157
 
158
    spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %f %f %u",
159
-           state, follower, nsec, corr, delay, err, state->threshold * corr,
160
+           state, follower, current_time, corr, delay, err, state->threshold * corr,
161
            state->threshold);
162
 
163
    return 0;
164
@@ -1804,6 +1862,7 @@
165
        state->rate_denom = state->position->clock.rate.denom;
166
        state->threshold = (state->duration * state->rate + state->rate_denom-1) / state->rate_denom;
167
        state->resample = ((uint32_t)state->rate != state->rate_denom) || state->matching;
168
+       state->alsa_sync = true;
169
    }
170
 }
171
 
172
@@ -1811,45 +1870,42 @@
173
 {
174
    snd_pcm_t *hndl = state->hndl;
175
    const snd_pcm_channel_area_t *my_areas;
176
-   snd_pcm_uframes_t written, frames, offset, off, to_write, total_written;
177
+   snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write;
178
    snd_pcm_sframes_t commitres;
179
    int res = 0;
180
 
181
    check_position_config(state);
182
 
183
+   max_write = state->buffer_frames;
184
+
185
    if (state->following && state->alsa_started) {
186
-       uint64_t nsec;
187
+       uint64_t current_time;
188
        snd_pcm_uframes_t delay, target;
189
 
190
-       if (SPA_UNLIKELY((res = get_status(state, &delay, &target)) < 0))
191
+       current_time = state->position->clock.nsec;
192
+
193
+       if (SPA_UNLIKELY((res = get_status(state, current_time, &delay, &target)) < 0))
194
            return res;
195
 
196
-       if (SPA_UNLIKELY(!state->alsa_recovering && delay > target + state->threshold)) {
197
+       if (SPA_UNLIKELY(state->alsa_sync)) {
198
            spa_log_warn(state->log, "%s: follower delay:%ld target:%ld thr:%u, resync",
199
                    state->props.device, delay, target, state->threshold);
200
-           spa_dll_init(&state->dll);
201
pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/alsa-pcm.h Changed
18
 
1
@@ -189,8 +189,6 @@
2
    uint32_t start_delay;
3
 
4
    uint32_t duration;
5
-   uint32_t last_duration;
6
-   uint64_t last_position;
7
    unsigned int alsa_started:1;
8
    unsigned int alsa_sync:1;
9
    unsigned int alsa_recovering:1;
10
@@ -210,7 +208,6 @@
11
    int64_t sample_count;
12
 
13
    int64_t sample_time;
14
-   uint64_t current_time;
15
    uint64_t next_time;
16
    uint64_t base_time;
17
 
18
pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/alsa-udev.c Changed
159
 
1
@@ -246,6 +246,60 @@
2
    *d = 0;
3
 }
4
 
5
+static int check_device_pcm_class(const char *devname)
6
+{
7
+   FILE *f;
8
+   char path[PATH_MAX];
9
+   char buf[16];
10
+   size_t sz;
11
+
12
+   /* Check device class */
13
+   spa_scnprintf(path, sizeof(path), "/sys/class/sound/%s/pcm_class",
14
+           devname);
15
+   f = fopen(path, "r");
16
+   if (f == NULL)
17
+       return -errno;
18
+   sz = fread(buf, 1, sizeof(buf) - 1, f);
19
+   buf[sz] = '\0';
20
+   fclose(f);
21
+   return spa_strstartswith(buf, "modem") ? -ENXIO : 0;
22
+}
23
+
24
+static int get_num_pcm_devices(unsigned int card_id)
25
+{
26
+   char prefix[32];
27
+   DIR *snd = NULL;
28
+   struct dirent *entry;
29
+   int num_dev = 0;
30
+   int res;
31
+
32
+   /* Check if card has PCM devices, without opening them */
33
+
34
+   spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_id);
35
+
36
+   if ((snd = opendir("/dev/snd")) == NULL)
37
+       return -errno;
38
+
39
+   while ((errno = 0, entry = readdir(snd)) != NULL) {
40
+       if (!(entry->d_type == DT_CHR &&
41
+               spa_strstartswith(entry->d_name, prefix)))
42
+           continue;
43
+
44
+       res = check_device_pcm_class(entry->d_name);
45
+       if (res != -ENXIO) {
46
+           /* count device also if sysfs status file not accessible */
47
+           ++num_dev;
48
+       }
49
+   }
50
+   if (errno != 0)
51
+       res = -errno;
52
+   else
53
+       res = num_dev;
54
+
55
+   closedir(snd);
56
+   return res;
57
+}
58
+
59
 static int check_device_available(struct impl *this, struct device *device, int *num_pcm)
60
 {
61
    char path[PATH_MAX];
62
@@ -256,13 +310,27 @@
63
    struct dirent *entry, *entry_pcm;
64
    int res;
65
 
66
+   res = get_num_pcm_devices(device->id);
67
+   if (res < 0) {
68
+       spa_log_error(this->log, "Error finding PCM devices for ALSA card %u: %s",
69
+           (unsigned int)device->id, spa_strerror(res));
70
+       return res;
71
+   }
72
+   *num_pcm = res;
73
+
74
+   spa_log_debug(this->log, "card %u has %d pcm device(s)", (unsigned int)device->id, *num_pcm);
75
+
76
    /*
77
     * Check if some pcm devices of the card are busy.  Check it via /proc, as we
78
     * don't want to actually open any devices using alsa-lib (generates uncontrolled
79
     * number of inotify events), or replicate its subdevice logic.
80
+    *
81
+    * The /proc/asound directory might not exist if kernel is compiled with
82
+    * CONFIG_SND_PROCFS=n, and the pcmXX directories may be missing if compiled
83
+    * with CONFIG_SND_VERBOSE_PROCFS=n. In those cases, the busy check always succeeds.
84
     */
85
 
86
-   *num_pcm = 0;
87
+   res = 0;
88
 
89
    spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", (unsigned int)device->id);
90
 
91
@@ -274,16 +342,9 @@
92
                spa_strstartswith(entry->d_name, "pcm")))
93
            continue;
94
 
95
-       /* Check device class */
96
-       spa_scnprintf(path, sizeof(path), "/sys/class/sound/pcmC%uD%s/pcm_class",
97
+       spa_scnprintf(path, sizeof(path), "pcmC%uD%s",
98
                (unsigned int)device->id, entry->d_name+3);
99
-       f = fopen(path, "r");
100
-       if (f == NULL)
101
-           goto done;
102
-       sz = fread(buf, 1, sizeof(buf) - 1, f);
103
-       buf[sz] = '\0';
104
-       fclose(f);
105
-       if (spa_strstartswith(buf, "modem"))
106
+       if (check_device_pcm_class(path) < 0)
107
            continue;
108
 
109
        /* Check busy status */
110
@@ -310,7 +371,7 @@
111
            if (!spa_strstartswith(buf, "closed")) {
112
                spa_log_debug(this->log, "card %u pcm device %s busy",
113
                        (unsigned int)device->id, entry->d_name);
114
-               errno = EBUSY;
115
+               res = -EBUSY;
116
                goto done;
117
            }
118
            spa_log_debug(this->log, "card %u pcm device %s free",
119
@@ -319,8 +380,6 @@
120
        if (errno != 0)
121
            goto done;
122
 
123
-       ++*num_pcm;
124
-
125
        closedir(pcm);
126
        pcm = NULL;
127
    }
128
@@ -328,7 +387,10 @@
129
        goto done;
130
 
131
 done:
132
-   res = -errno;
133
+   if (errno != 0) {
134
+       spa_log_info(this->log, "card %u: failed to find busy status (%s)",
135
+               (unsigned int)device->id, spa_strerror(-errno));
136
+   }
137
    if (card)
138
        closedir(card);
139
    if (pcm)
140
@@ -352,15 +414,16 @@
141
     * device->emitted to true. alsalib functions can be used after that.
142
     */
143
 
144
+   snprintf(path, sizeof(path), "hw:%u", id);
145
+
146
    if ((res = check_device_available(this, device, &pcm)) < 0)
147
        return res;
148
    if (pcm == 0) {
149
        spa_log_debug(this->log, "no pcm devices for %s", path);
150
        device->ignored = true;
151
-       return 0;
152
+       return -ENODEV;
153
    }
154
 
155
-   snprintf(path, sizeof(path), "hw:%u", id);
156
    spa_log_debug(this->log, "emitting card %s", path);
157
    device->emitted = true;
158
 
159
pipewire-0.3.45.tar.gz/spa/plugins/alsa/mixer/profile-sets/texas-instruments-pcm2902.conf -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/mixer/profile-sets/texas-instruments-pcm2902.conf Changed
18
 
1
@@ -16,12 +16,14 @@
2
 ; Texas Instruments PCM2902
3
 ;
4
 ; This is a generic chip used in multiple products, including at least
5
-; Behringer U-Phoria UMC22, Behringer Xenyx 302USB, Intopic Jazz-UB700 and
6
-; some unbranded "usb mini microphone".
7
+; Behringer U-Phoria UMC22, Behringer U-Phoria UM2, Behringer Xenyx 302USB, 
8
+; Intopic Jazz-UB700 and some unbranded "usb mini microphone".
9
 ;
10
 ; Behringer UMC22 has stereo input (representing two physical mono inputs),
11
 ; others have mono input.
12
 ;
13
+; (Behringer UMC22 and UM2 are "the same device" with different controls)
14
+;
15
 ; Some devices have a mic input path, but at least Behringer Xenyx 302USB
16
 ; doesn't have any input mixer controls.
17
 ;
18
pipewire-0.3.45.tar.gz/spa/plugins/alsa/test-timer.c -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/test-timer.c Changed
102
 
1
@@ -45,10 +45,12 @@
2
    unsigned int rate;
3
    unsigned int channels;
4
    snd_pcm_uframes_t period;
5
+   snd_pcm_uframes_t buffer_frames;
6
 
7
    snd_pcm_t *hndl;
8
    int timerfd;
9
 
10
+   double max_error;
11
    float accumulator;
12
 
13
    uint64_t next_time;
14
@@ -103,15 +105,36 @@
15
 
16
 static int on_timer_wakeup(struct state *state)
17
 {
18
-   snd_pcm_sframes_t avail, delay;
19
+   snd_pcm_sframes_t delay;
20
    double error, corr;
21
-
22
-   /* check the delay in the device */
23
-   CHECK(snd_pcm_avail_delay(state->hndl, &avail, &delay), "delay");
24
+#if 1
25
+   snd_pcm_sframes_t avail;
26
+        CHECK(snd_pcm_avail_delay(state->hndl, &avail, &delay), "delay");
27
+#else
28
+   snd_pcm_uframes_t avail;
29
+   snd_htimestamp_t tstamp;
30
+   uint64_t then;
31
+
32
+   CHECK(snd_pcm_htimestamp(state->hndl, &avail, &tstamp), "htimestamp");
33
+   delay = state->buffer_frames - avail;
34
+
35
+   then = TIMESPEC_TO_NSEC(&tstamp);
36
+   if (then != 0) {
37
+       if (then < state->next_time) {
38
+           delay -= (state->next_time - then) * state->rate / NSEC_PER_SEC;
39
+       } else {
40
+           delay += (then - state->next_time) * state->rate / NSEC_PER_SEC;
41
+       }
42
+   }
43
+#endif
44
 
45
    /* calculate the error, we want to have exactly 1 period of
46
     * samples remaining in the device when we wakeup. */
47
    error = (double)delay - (double)state->period;
48
+   if (error > state->max_error)
49
+       error = state->max_error;
50
+   else if (error < -state->max_error)
51
+       error = -state->max_error;
52
 
53
    /* update the dll with the error, this gives a rate correction */
54
    corr = spa_dll_update(&state->dll, error);
55
@@ -124,12 +147,6 @@
56
 
57
    if (state->next_time - state->prev_time > BW_PERIOD) {
58
        state->prev_time = state->next_time;
59
-
60
-       /* reduce bandwidth and show some stats */
61
-       if (state->dll.bw > SPA_DLL_BW_MIN)
62
-           spa_dll_set_bw(&state->dll, state->dll.bw / 2.0,
63
-                   state->period, state->rate);
64
-
65
        fprintf(stdout, "corr:%f error:%f bw:%f\n",
66
                corr, error, state->dll.bw);
67
    }
68
@@ -144,6 +161,7 @@
69
    struct state state = { 0, };
70
    const char *device = DEFAULT_DEVICE;
71
    snd_pcm_hw_params_t *hparams;
72
+   snd_pcm_sw_params_t *sparams;
73
    struct timespec now;
74
 
75
    CHECK(snd_pcm_open(&state.hndl, device, SND_PCM_STREAM_PLAYBACK, 0), "open %s failed", device);
76
@@ -165,12 +183,25 @@
77
                &state.rate, 0), "set rate");
78
    CHECK(snd_pcm_hw_params(state.hndl, hparams), "hw_params");
79
 
80
+   CHECK(snd_pcm_hw_params_get_buffer_size(hparams, &state.buffer_frames), "get_buffer_size_max");
81
+
82
    fprintf(stdout, "opened format:%s rate:%u channels:%u\n",
83
            snd_pcm_format_name(SND_PCM_FORMAT_S32_LE),
84
            state.rate, state.channels);
85
 
86
+   snd_pcm_sw_params_alloca(&sparams);
87
+#if 0
88
+   CHECK(snd_pcm_sw_params_current(state.hndl, sparams), "sw_params_current");
89
+   CHECK(snd_pcm_sw_params_set_tstamp_mode(state.hndl, sparams, SND_PCM_TSTAMP_ENABLE),
90
+           "sw_params_set_tstamp_type");
91
+   CHECK(snd_pcm_sw_params_set_tstamp_type(state.hndl, sparams, SND_PCM_TSTAMP_TYPE_MONOTONIC),
92
+           "sw_params_set_tstamp_type");
93
+   CHECK(snd_pcm_sw_params(state.hndl, sparams), "sw_params");
94
+#endif
95
+
96
    spa_dll_init(&state.dll);
97
    spa_dll_set_bw(&state.dll, SPA_DLL_BW_MAX, state.period, state.rate);
98
+   state.max_error = 256.0;
99
 
100
    if ((state.timerfd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0)
101
        perror("timerfd");
102
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.47.tar.gz/spa/plugins/bluez5/backend-native.c Changed
10
 
1
@@ -594,7 +594,7 @@
2
 
3
    /* Check if USB ALT6 is really available on the device */
4
    if (device->adapter->bus_type == BUS_TYPE_USB && !msbc_alt1_ok && msbc_ok) {
5
-#if HAVE_LIBUSB
6
+#ifdef HAVE_LIBUSB
7
        if (device->adapter->source_id == SOURCE_ID_USB) {
8
            msbc_ok = check_usb_altsetting_6(backend, device->adapter->vendor_id,
9
                    device->adapter->product_id);
10
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.47.tar.gz/spa/plugins/bluez5/bluez5-dbus.c Changed
14
 
1
@@ -425,12 +425,6 @@
2
    }
3
 }
4
 
5
-static inline void add_dict(struct spa_pod_builder *builder, const char *key, const char *val)
6
-{
7
-   spa_pod_builder_string(builder, key);
8
-   spa_pod_builder_string(builder, val);
9
-}
10
-
11
 static int a2dp_codec_to_endpoint(const struct a2dp_codec *codec,
12
                   const char * endpoint,
13
                   char** object_path)
14
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.47.tar.gz/spa/plugins/bluez5/meson.build Changed
56
 
1
@@ -5,24 +5,14 @@
2
   endif
3
 endforeach
4
 
5
-if not get_option('bluez5-backend-hsp-native').disabled()
6
-  cdata.set('HAVE_BLUEZ_5_BACKEND_HSP_NATIVE', 1)
7
-  cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE', 1)
8
-endif
9
-if not get_option('bluez5-backend-hfp-native').disabled()
10
-  cdata.set('HAVE_BLUEZ_5_BACKEND_HFP_NATIVE', 1)
11
-  cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE', 1)
12
-endif
13
-if not get_option('bluez5-backend-ofono').disabled()
14
-  cdata.set('HAVE_BLUEZ_5_BACKEND_OFONO', 1)
15
-endif
16
-if not get_option('bluez5-backend-hsphfpd').disabled()
17
-  cdata.set('HAVE_BLUEZ_5_BACKEND_HSPHFPD', 1)
18
-endif
19
-
20
-if dependency('bluez', version: '< 6', required: false).found()
21
-  cdata.set('HAVE_BLUEZ_5_HCI', 1)
22
-endif
23
+cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE',
24
+          get_option('bluez5-backend-hsp-native').allowed() or
25
+          get_option('bluez5-backend-hfp-native').allowed())
26
+cdata.set('HAVE_BLUEZ_5_BACKEND_HSP_NATIVE', get_option('bluez5-backend-hsp-native').allowed())
27
+cdata.set('HAVE_BLUEZ_5_BACKEND_HFP_NATIVE', get_option('bluez5-backend-hfp-native').allowed())
28
+cdata.set('HAVE_BLUEZ_5_BACKEND_OFONO', get_option('bluez5-backend-ofono').allowed())
29
+cdata.set('HAVE_BLUEZ_5_BACKEND_HSPHFPD', get_option('bluez5-backend-hsphfpd').allowed())
30
+cdata.set('HAVE_BLUEZ_5_HCI', dependency('bluez', version: '< 6', required: false).found())
31
 
32
 bluez5_sources = [
33
   'plugin.c',
34
@@ -44,18 +34,18 @@
35
 
36
 install_data(bluez5_data, install_dir : spa_datadir / 'bluez5')
37
 
38
-if not get_option('bluez5-backend-hsp-native').disabled() or not get_option('bluez5-backend-hfp-native').disabled()
39
+if get_option('bluez5-backend-hsp-native').allowed() or get_option('bluez5-backend-hfp-native').allowed()
40
   if libusb_dep.found()
41
     bluez5_deps += libusb_dep
42
   endif
43
   bluez5_sources += ['backend-native.c']
44
 endif
45
 
46
-if not get_option('bluez5-backend-ofono').disabled()
47
+if get_option('bluez5-backend-ofono').allowed()
48
   bluez5_sources += ['backend-ofono.c']
49
 endif
50
 
51
-if not get_option('bluez5-backend-hsphfpd').disabled()
52
+if get_option('bluez5-backend-hsphfpd').allowed()
53
   bluez5_sources += ['backend-hsphfpd.c']
54
 endif
55
 
56
pipewire-0.3.45.tar.gz/spa/plugins/meson.build -> pipewire-0.3.47.tar.gz/spa/plugins/meson.build Changed
54
 
1
@@ -1,16 +1,16 @@
2
 if alsa_dep.found()
3
   subdir('alsa')
4
 endif
5
-if not get_option('audioconvert').disabled()
6
+if get_option('audioconvert').allowed()
7
   subdir('audioconvert')
8
 endif
9
-if not get_option('audiomixer').disabled()
10
+if get_option('audiomixer').allowed()
11
   subdir('audiomixer')
12
 endif
13
-if not get_option('control').disabled()
14
+if get_option('control').allowed()
15
   subdir('control')
16
 endif
17
-if not get_option('audiotestsrc').disabled()
18
+if get_option('audiotestsrc').allowed()
19
   subdir('audiotestsrc')
20
 endif
21
 if bluez_dep.found()
22
@@ -22,19 +22,19 @@
23
 if jack_dep.found()
24
   subdir('jack')
25
 endif
26
-if not get_option('support').disabled()
27
+if get_option('support').allowed()
28
   subdir('support')
29
 endif
30
-if not get_option('test').disabled()
31
+if get_option('test').allowed()
32
   subdir('test')
33
 endif
34
-if not get_option('videoconvert').disabled()
35
+if get_option('videoconvert').allowed()
36
   subdir('videoconvert')
37
 endif
38
-if not get_option('videotestsrc').disabled()
39
+if get_option('videotestsrc').allowed()
40
   subdir('videotestsrc')
41
 endif
42
-if not get_option('volume').disabled()
43
+if get_option('volume').allowed()
44
   subdir('volume')
45
 endif
46
 if vulkan_headers
47
@@ -51,3 +51,5 @@
48
 if libcamera_dep.found()
49
   subdir('libcamera')
50
 endif
51
+
52
+subdir('aec')
53
\ No newline at end of file
54
pipewire-0.3.45.tar.gz/spa/plugins/support/logger.c -> pipewire-0.3.47.tar.gz/spa/plugins/support/logger.c Changed
28
 
1
@@ -57,6 +57,7 @@
2
    struct spa_log log;
3
 
4
    FILE *file;
5
+   bool close_file;
6
 
7
    struct spa_system *system;
8
    struct spa_source source;
9
@@ -285,6 +286,9 @@
10
 
11
    support_log_free_patterns(&this->patterns);
12
 
13
+   if (this->close_file && this->file != NULL)
14
+       fclose(this->file);
15
+
16
    if (this->have_source) {
17
        spa_loop_remove_source(this->source.loop, &this->source);
18
        spa_system_close(this->system, this->source.fd);
19
@@ -356,6 +360,8 @@
20
            this->file = fopen(str, "w");
21
            if (this->file == NULL)
22
                fprintf(stderr, "Warning: failed to open file %s: (%m)", str);
23
+           else
24
+               this->close_file = true;
25
        }
26
        if ((str = spa_dict_lookup(info, SPA_KEY_LOG_PATTERNS)) != NULL)
27
            support_log_parse_patterns(&this->patterns, str);
28
pipewire-0.3.45.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.47.tar.gz/spa/plugins/support/loop.c Changed
156
 
1
@@ -48,6 +48,7 @@
2
 #define MAX_ALIGN  8
3
 #define ITEM_ALIGN 8
4
 #define DATAS_SIZE (4096*8)
5
+#define MAX_EP     32
6
 
7
 /** \cond */
8
 
9
@@ -74,11 +75,11 @@
10
         struct spa_system *system;
11
 
12
    struct spa_list source_list;
13
-   struct spa_list destroy_list;
14
    struct spa_hook_list hooks_list;
15
 
16
    int poll_fd;
17
    pthread_t thread;
18
+   int enter_count;
19
 
20
    struct spa_source *wakeup;
21
    int ack_fd;
22
@@ -113,6 +114,7 @@
23
 {
24
    struct impl *impl = object;
25
    source->loop = &impl->loop;
26
+   source->priv = NULL;
27
    return spa_system_pollfd_add(impl->system, impl->poll_fd, source->fd, source->mask, source);
28
 }
29
 
30
@@ -125,6 +127,12 @@
31
 static int loop_remove_source(void *object, struct spa_source *source)
32
 {
33
    struct impl *impl = object;
34
+   struct spa_poll_event *e;
35
+   if ((e = source->priv)) {
36
+       /* active in an iteration of the loop, remove it from there */
37
+       e->data = NULL;
38
+       source->priv = NULL;
39
+   }
40
    source->loop = NULL;
41
    return spa_system_pollfd_del(impl->system, impl->poll_fd, source->fd);
42
 }
43
@@ -289,35 +297,43 @@
44
 static void loop_enter(void *object)
45
 {
46
    struct impl *impl = object;
47
-   impl->thread = pthread_self();
48
+   pthread_t thread_id = pthread_self();
49
+
50
+   if (impl->enter_count == 0) {
51
+       spa_return_if_fail(impl->thread == 0);
52
+       impl->thread = thread_id;
53
+       impl->enter_count = 1;
54
+   } else {
55
+       spa_return_if_fail(impl->enter_count > 0);
56
+       spa_return_if_fail(impl->thread == thread_id);
57
+       impl->enter_count++;
58
+   }
59
    spa_log_trace(impl->log, "%p: enter %lu", impl, impl->thread);
60
 }
61
 
62
 static void loop_leave(void *object)
63
 {
64
    struct impl *impl = object;
65
+   pthread_t thread_id = pthread_self();
66
+
67
+   spa_return_if_fail(impl->enter_count > 0);
68
+   spa_return_if_fail(impl->thread == thread_id);
69
+
70
    spa_log_trace(impl->log, "%p: leave %lu", impl, impl->thread);
71
-   impl->thread = 0;
72
-}
73
 
74
-static inline void process_destroy(struct impl *impl)
75
-{
76
-   struct source_impl *source, *tmp;
77
-   spa_list_for_each_safe(source, tmp, &impl->destroy_list, link)
78
-       free(source);
79
-   spa_list_init(&impl->destroy_list);
80
+   if (--impl->enter_count == 0)
81
+       impl->thread = 0;
82
 }
83
 
84
 static int loop_iterate(void *object, int timeout)
85
 {
86
    struct impl *impl = object;
87
-   struct spa_loop *loop = &impl->loop;
88
-   struct spa_poll_event ep[32];
89
+   struct spa_poll_event ep[MAX_EP], *e;
90
    int i, nfds;
91
 
92
    spa_loop_control_hook_before(&impl->hooks_list);
93
 
94
-   nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
95
+   nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, MAX_EP, timeout);
96
 
97
    spa_loop_control_hook_after(&impl->hooks_list);
98
 
99
@@ -330,15 +346,19 @@
100
    for (i = 0; i < nfds; i++) {
101
        struct spa_source *s = ep[i].data;
102
        s->rmask = ep[i].events;
103
+       /* already active in another iteration of the loop,
104
+        * remove it from that iteration */
105
+       if (SPA_UNLIKELY(e = s->priv))
106
+           e->data = NULL;
107
+       s->priv = &ep[i];
108
    }
109
    for (i = 0; i < nfds; i++) {
110
        struct spa_source *s = ep[i].data;
111
-       if (SPA_LIKELY(s->rmask && s->fd != -1 && s->loop == loop))
112
+       if (SPA_LIKELY(s && s->rmask)) {
113
+           s->priv = NULL;
114
            s->func(s);
115
+       }
116
    }
117
-   if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list)))
118
-       process_destroy(impl);
119
-
120
    return nfds;
121
 }
122
 
123
@@ -692,7 +712,7 @@
124
        spa_system_close(impl->impl->system, source->fd);
125
        source->fd = -1;
126
    }
127
-   spa_list_insert(&impl->impl->destroy_list, &impl->link);
128
+   free(source);
129
 }
130
 
131
 static const struct spa_loop_methods impl_loop = {
132
@@ -756,11 +776,13 @@
133
 
134
    impl = (struct impl *) handle;
135
 
136
+   if (impl->enter_count != 0)
137
+       spa_log_warn(impl->log, "%p: loop is entered %d times",
138
+               impl, impl->enter_count);
139
+
140
    spa_list_consume(source, &impl->source_list, link)
141
        loop_destroy_source(impl, &source->source);
142
 
143
-   process_destroy(impl);
144
-
145
    spa_system_close(impl->system, impl->ack_fd);
146
    spa_system_close(impl->system, impl->poll_fd);
147
 
148
@@ -822,7 +844,6 @@
149
    impl->poll_fd = res;
150
 
151
    spa_list_init(&impl->source_list);
152
-   spa_list_init(&impl->destroy_list);
153
    spa_hook_list_init(&impl->hooks_list);
154
 
155
    impl->buffer_data = SPA_PTR_ALIGN(impl->buffer_mem, MAX_ALIGN, uint8_t);
156
pipewire-0.3.45.tar.gz/spa/plugins/support/meson.build -> pipewire-0.3.47.tar.gz/spa/plugins/support/meson.build Changed
10
 
1
@@ -23,7 +23,7 @@
2
   install_dir : spa_plugindir / 'support')
3
 spa_support_dep = declare_dependency(link_with: spa_support_lib)
4
 
5
-if not get_option('evl').disabled()
6
+if get_option('evl').allowed()
7
   evl_inc = include_directories('/usr/evl/include')
8
   evl_lib = cc.find_library('evl',
9
                             dirs: ['/usr/evl/lib/'],
10
pipewire-0.3.45.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/client-rt.conf.in Changed
13
 
1
@@ -2,6 +2,11 @@
2
 #
3
 # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
4
 # or in ~/.config/pipewire for local changes.
5
+#
6
+# It is also possible to place a file with an updated section in
7
+# @PIPEWIRE_CONFIG_DIR@/client-rt.conf.d/ for system-wide changes or in
8
+# ~/.config/pipewire/client-rt.conf.d/ for local changes.
9
+#
10
 
11
 context.properties = {
12
     ## Configure properties in the system.
13
pipewire-0.3.45.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/client.conf.in Changed
14
 
1
@@ -2,7 +2,11 @@
2
 #
3
 # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
4
 # or in ~/.config/pipewire for local changes.
5
-
6
+#
7
+# It is also possible to place a file with an updated section in
8
+# @PIPEWIRE_CONFIG_DIR@/client.conf.d/ for system-wide changes or in
9
+# ~/.config/pipewire/client.conf.d/ for local changes.
10
+#
11
 context.properties = {
12
     ## Configure properties in the system.
13
     #mem.warn-mlock  = false
14
pipewire-0.3.45.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/jack.conf.in Changed
33
 
1
@@ -2,6 +2,11 @@
2
 #
3
 # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
4
 # or in ~/.config/pipewire for local changes.
5
+#
6
+# It is also possible to place a file with an updated section in
7
+# @PIPEWIRE_CONFIG_DIR@/jack.conf.d/ for system-wide changes or in
8
+# ~/.config/pipewire/jack.conf.d/ for local changes.
9
+#
10
 
11
 context.properties = {
12
     ## Configure properties in the system.
13
@@ -60,7 +65,10 @@
14
 # global properties for all jack clients
15
 jack.properties = {
16
      #node.latency       = 1024/48000
17
-     #node.lock-quantum  = false
18
+     #node.rate          = 1/48000
19
+     #node.quantum       = 1024/48000
20
+     #node.lock-quantum  = true
21
+     #node.force-quantum = 0
22
      #jack.show-monitor  = true
23
      #jack.merge-monitor = false
24
      #jack.short-name    = false
25
@@ -73,6 +81,7 @@
26
      # ignore-all:      Ignore all self connect requests
27
      #jack.self-connect-mode = allow
28
      #jack.locked-process    = true
29
+     #jack.default-as-system    = false
30
 }
31
 
32
 # client specific properties
33
pipewire-0.3.45.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/minimal.conf.in Changed
13
 
1
@@ -2,6 +2,11 @@
2
 #
3
 # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
4
 # or in ~/.config/pipewire for local changes.
5
+#
6
+# It is also possible to place a file with an updated section in
7
+# @PIPEWIRE_CONFIG_DIR@/minimal.conf.d/ for system-wide changes or in
8
+# ~/.config/pipewire/minimal.conf.d/ for local changes.
9
+#
10
 
11
 context.properties = {
12
     ## Configure properties in the system.
13
pipewire-0.3.45.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/pipewire-pulse.conf.in Changed
21
 
1
@@ -2,6 +2,11 @@
2
 #
3
 # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
4
 # or in ~/.config/pipewire for local changes.
5
+#
6
+# It is also possible to place a file with an updated section in
7
+# @PIPEWIRE_CONFIG_DIR@/pipewire-pulse.conf.d/ for system-wide changes or in
8
+# ~/.config/pipewire/pipewire-pulse.conf.d/ for local changes.
9
+#
10
 
11
 context.properties = {
12
     ## Configure properties in the system.
13
@@ -67,6 +72,7 @@
14
 
15
 # Extra modules can be loaded here. Setup in default.pa can be moved here
16
 context.exec = [
17
+    { path = "pactl"        args = "load-module module-always-sink" }
18
     #{ path = "pactl"        args = "load-module module-switch-on-connect" }
19
     #{ path = "/usr/bin/sh"  args = "~/.config/pipewire/default.pw" }
20
 ]
21
pipewire-0.3.45.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/pipewire.conf.in Changed
22
 
1
@@ -2,6 +2,11 @@
2
 #
3
 # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
4
 # or in ~/.config/pipewire for local changes.
5
+#
6
+# It is also possible to place a file with an updated section in
7
+# @PIPEWIRE_CONFIG_DIR@/pipewire.conf.d/ for system-wide changes or in
8
+# ~/.config/pipewire/pipewire.conf.d/ for local changes.
9
+#
10
 
11
 context.properties = {
12
     ## Configure properties in the system.
13
@@ -24,7 +29,7 @@
14
     #default.clock.rate          = 48000
15
     #default.clock.allowed-rates = [ 48000 ]
16
     #default.clock.quantum       = 1024
17
-    #default.clock.min-quantum   = 32
18
+    default.clock.min-quantum   = 16
19
     #default.clock.max-quantum   = 2048
20
     #default.clock.quantum-limit = 8192
21
     #default.video.width         = 640
22
pipewire-0.3.45.tar.gz/src/daemon/systemd/meson.build -> pipewire-0.3.47.tar.gz/src/daemon/systemd/meson.build Changed
10
 
1
@@ -1,6 +1,6 @@
2
-if not get_option('systemd-system-service').disabled()
3
+if get_option('systemd-system-service').allowed()
4
   subdir('system')
5
 endif
6
-if not get_option('systemd-user-service').disabled()
7
+if get_option('systemd-user-service').allowed()
8
   subdir('user')
9
 endif
10
pipewire-0.3.45.tar.gz/src/gst/gstpipewire.c -> pipewire-0.3.47.tar.gz/src/gst/gstpipewire.c Changed
10
 
1
@@ -51,7 +51,7 @@
2
   gst_element_register (plugin, "pipewiresink", GST_RANK_NONE,
3
       GST_TYPE_PIPEWIRE_SINK);
4
 
5
-#if HAVE_GSTREAMER_DEVICE_PROVIDER
6
+#ifdef HAVE_GSTREAMER_DEVICE_PROVIDER
7
   if (!gst_device_provider_register (plugin, "pipewiredeviceprovider",
8
        GST_RANK_PRIMARY + 1, GST_TYPE_PIPEWIRE_DEVICE_PROVIDER))
9
     return FALSE;
10
pipewire-0.3.45.tar.gz/src/gst/gstpipewireformat.c -> pipewire-0.3.47.tar.gz/src/gst/gstpipewireformat.c Changed
58
 
1
@@ -445,6 +445,44 @@
2
   return TRUE;
3
 }
4
 
5
+static void
6
+set_default_channels (struct spa_pod_builder *b, uint32_t channels)
7
+{
8
+  uint32_t position[SPA_AUDIO_MAX_CHANNELS] = {0};
9
+  gboolean ok = TRUE;
10
+
11
+  switch (channels) {
12
+  case 8:
13
+    position[6] = SPA_AUDIO_CHANNEL_SL;
14
+    position[7] = SPA_AUDIO_CHANNEL_SR;
15
+    SPA_FALLTHROUGH
16
+  case 6:
17
+    position[5] = SPA_AUDIO_CHANNEL_LFE;
18
+    SPA_FALLTHROUGH
19
+  case 5:
20
+    position[4] = SPA_AUDIO_CHANNEL_FC;
21
+    SPA_FALLTHROUGH
22
+  case 4:
23
+    position[2] = SPA_AUDIO_CHANNEL_RL;
24
+    position[3] = SPA_AUDIO_CHANNEL_RR;
25
+    SPA_FALLTHROUGH
26
+  case 2:
27
+    position[0] = SPA_AUDIO_CHANNEL_FL;
28
+    position[1] = SPA_AUDIO_CHANNEL_FR;
29
+    break;
30
+  case 1:
31
+    position[0] = SPA_AUDIO_CHANNEL_MONO;
32
+    break;
33
+  default:
34
+    ok = FALSE;
35
+    break;
36
+  }
37
+
38
+  if (ok)
39
+    spa_pod_builder_add (b, SPA_FORMAT_AUDIO_position,
40
+        SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, channels, position), 0);
41
+}
42
+
43
 static gboolean
44
 handle_audio_fields (ConvertData *d)
45
 {
46
@@ -538,8 +576,10 @@
47
     }
48
     if (i > 0) {
49
       choice = spa_pod_builder_pop(&d->b, &f);
50
-      if (i == 1)
51
+      if (i == 1) {
52
         choice->body.type = SPA_CHOICE_None;
53
+        set_default_channels (&d->b, v);
54
+      }
55
     }
56
   }
57
   return TRUE;
58
pipewire-0.3.45.tar.gz/src/gst/meson.build -> pipewire-0.3.47.tar.gz/src/gst/meson.build Changed
10
 
1
@@ -8,7 +8,7 @@
2
   'gstpipewiresrc.c',
3
 ]
4
 
5
-if not get_option('gstreamer-device-provider').disabled()
6
+if get_option('gstreamer-device-provider').allowed()
7
   pipewire_gst_sources += [ 'gstpipewiredeviceprovider.c' ]
8
 endif
9
 
10
pipewire-0.3.45.tar.gz/src/meson.build -> pipewire-0.3.47.tar.gz/src/meson.build Changed
14
 
1
@@ -3,10 +3,10 @@
2
 subdir('daemon')
3
 subdir('tools')
4
 subdir('modules')
5
-if not get_option('examples').disabled()
6
+if get_option('examples').allowed()
7
   subdir('examples')
8
 endif
9
-if not get_option('tests').disabled()
10
+if get_option('tests').allowed()
11
   subdir('tests')
12
 endif
13
 
14
pipewire-0.3.45.tar.gz/src/modules/meson.build -> pipewire-0.3.47.tar.gz/src/modules/meson.build Changed
87
 
1
@@ -10,6 +10,7 @@
2
   'module-echo-cancel.c',
3
   'module-example-sink.c',
4
   'module-example-source.c',
5
+  'module-fallback-sink.c',
6
   'module-filter-chain.c',
7
   'module-link-factory.c',
8
   'module-loopback.c',
9
@@ -109,22 +110,15 @@
10
 
11
 pipewire_module_echo_cancel_sources = [
12
   'module-echo-cancel.c',
13
-  'module-echo-cancel/aec-null.c',
14
 ]
15
 
16
-if webrtc_dep.found()
17
-  pipewire_module_echo_cancel_sources += [
18
-    'module-echo-cancel/aec-webrtc.cpp'
19
-  ]
20
-endif
21
-
22
 pipewire_module_echo_cancel = shared_library('pipewire-module-echo-cancel',
23
   pipewire_module_echo_cancel_sources,
24
   include_directories : [configinc],
25
   install : true,
26
   install_dir : modules_install_dir,
27
   install_rpath: modules_install_dir,
28
-  dependencies : [mathlib, dl_lib, pipewire_dep, webrtc_dep],
29
+  dependencies : [mathlib, dl_lib, pipewire_dep],
30
 )
31
 
32
 pipewire_module_profiler = shared_library('pipewire-module-profiler',
33
@@ -223,7 +217,6 @@
34
   'module-protocol-pulse/extensions/ext-stream-restore.c',
35
   'module-protocol-pulse/format.c',
36
   'module-protocol-pulse/manager.c',
37
-  'module-protocol-pulse/media-roles.c',
38
   'module-protocol-pulse/message.c',
39
   'module-protocol-pulse/message-handler.c',
40
   'module-protocol-pulse/module.c',
41
@@ -231,6 +224,7 @@
42
   'module-protocol-pulse/pending-sample.c',
43
   'module-protocol-pulse/pulse-server.c',
44
   'module-protocol-pulse/quirks.c',
45
+  'module-protocol-pulse/remap.c',
46
   'module-protocol-pulse/reply.c',
47
   'module-protocol-pulse/sample.c',
48
   'module-protocol-pulse/sample-play.c',
49
@@ -238,6 +232,7 @@
50
   'module-protocol-pulse/stream.c',
51
   'module-protocol-pulse/utils.c',
52
   'module-protocol-pulse/volume.c',
53
+  'module-protocol-pulse/modules/module-always-sink.c',
54
   'module-protocol-pulse/modules/module-combine-sink.c',
55
   'module-protocol-pulse/modules/module-echo-cancel.c',
56
   'module-protocol-pulse/modules/module-ladspa-sink.c',
57
@@ -265,7 +260,6 @@
58
     'module-protocol-pulse/dbus-name.c',
59
   ]
60
   pipewire_module_protocol_pulse_deps += dbus_dep
61
-  cdata.set('HAVE_DBUS', 1)
62
 endif
63
 
64
 if avahi_dep.found()
65
@@ -274,7 +268,7 @@
66
     'module-zeroconf-discover/avahi-poll.c',
67
   ]
68
   pipewire_module_protocol_pulse_deps += avahi_dep
69
-  cdata.set('HAVE_AVAHI', 1)
70
+  cdata.set('HAVE_AVAHI', true)
71
 endif
72
 
73
 pipewire_module_protocol_pulse = shared_library('pipewire-module-protocol-pulse',
74
@@ -499,3 +493,12 @@
75
 )
76
 endif
77
 summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules')
78
+
79
+pipewire_module_fallback_sink = shared_library('pipewire-module-fallback-sink',
80
+  [ 'module-fallback-sink.c' ],
81
+  include_directories : [configinc],
82
+  install : true,
83
+  install_dir : modules_install_dir,
84
+  install_rpath: modules_install_dir,
85
+  dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep],
86
+)
87
pipewire-0.3.45.tar.gz/src/modules/module-access.c -> pipewire-0.3.47.tar.gz/src/modules/module-access.c Changed
14
 
1
@@ -32,10 +32,10 @@
2
 
3
 #include "config.h"
4
 
5
-#if HAVE_SYS_VFS_H
6
+#ifdef HAVE_SYS_VFS_H
7
 #include <sys/vfs.h>
8
 #endif
9
-#if HAVE_SYS_MOUNT_H
10
+#ifdef HAVE_SYS_MOUNT_H
11
 #include <sys/mount.h>
12
 #endif
13
 
14
pipewire-0.3.45.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.47.tar.gz/src/modules/module-client-node/client-node.c Changed
201
 
1
@@ -47,28 +47,14 @@
2
 
3
 /** \cond */
4
 
5
-#define MAX_INPUTS 1024
6
-#define MAX_OUTPUTS    1024
7
-
8
 #define MAX_BUFFERS    64
9
 #define MAX_METAS  16u
10
 #define MAX_DATAS  64u
11
 #define MAX_AREAS  2048
12
-#define MAX_MIX        128
13
-
14
-#define CHECK_IN_PORT_ID(this,d,p)       ((d) == SPA_DIRECTION_INPUT && (p) < MAX_INPUTS)
15
-#define CHECK_OUT_PORT_ID(this,d,p)      ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_OUTPUTS)
16
-#define CHECK_PORT_ID(this,d,p)          (CHECK_IN_PORT_ID(this,d,p) || CHECK_OUT_PORT_ID(this,d,p))
17
-#define CHECK_FREE_IN_PORT(this,d,p)     (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p] == NULL)
18
-#define CHECK_FREE_OUT_PORT(this,d,p)    (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p] == NULL)
19
-#define CHECK_FREE_PORT(this,d,p)        (CHECK_FREE_IN_PORT (this,d,p) || CHECK_FREE_OUT_PORT (this,d,p))
20
-#define CHECK_IN_PORT(this,d,p)          (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p])
21
-#define CHECK_OUT_PORT(this,d,p)         (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p])
22
-#define CHECK_PORT(this,d,p)             (CHECK_IN_PORT (this,d,p) || CHECK_OUT_PORT (this,d,p))
23
-
24
-#define GET_IN_PORT(this,p)    (this->in_ports[p])
25
-#define GET_OUT_PORT(this,p)   (this->out_ports[p])
26
-#define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p))
27
+
28
+#define CHECK_FREE_PORT(this,d,p)  (p <= pw_map_get_size(&this->ports[d]) && !CHECK_PORT(this,d,p))
29
+#define CHECK_PORT(this,d,p)       (pw_map_lookup(&this->ports[d], p) != NULL)
30
+#define GET_PORT(this,d,p)     (pw_map_lookup(&this->ports[d], p))
31
 
32
 #define CHECK_PORT_BUFFER(this,b,p)      (b < p->n_buffers)
33
 
34
@@ -129,10 +115,7 @@
35
    struct spa_source data_source;
36
    int writefd;
37
 
38
-   uint32_t n_inputs;
39
-   uint32_t n_outputs;
40
-   struct port *in_ports[MAX_INPUTS];
41
-   struct port *out_ports[MAX_OUTPUTS];
42
+   struct pw_map ports[2];
43
 
44
    struct port dummy;
45
 
46
@@ -213,8 +196,7 @@
47
        mix_id = 0;
48
    else
49
        mix_id++;
50
-   if (mix_id >= MAX_MIX)
51
-       return NULL;
52
+
53
    len = pw_array_get_len(&p->mix, struct mix);
54
    if (mix_id >= len) {
55
        size_t need = sizeof(struct mix) * (mix_id + 1 - len);
56
@@ -432,19 +414,19 @@
57
 {
58
    struct node *this = object;
59
    struct spa_hook_list save;
60
-   uint32_t i;
61
+   union pw_map_item *item;
62
 
63
    spa_return_val_if_fail(this != NULL, -EINVAL);
64
 
65
    spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
66
 
67
-   for (i = 0; i < MAX_INPUTS; i++) {
68
-       if (this->in_ports[i])
69
-           emit_port_info(this, this->in_ports[i]);
70
+   pw_array_for_each(item, &this->ports[SPA_DIRECTION_INPUT].items) {
71
+       if (item->data)
72
+           emit_port_info(this, item->data);
73
    }
74
-   for (i = 0; i < MAX_OUTPUTS; i++) {
75
-       if (this->out_ports[i])
76
-           emit_port_info(this, this->out_ports[i]);
77
+   pw_array_for_each(item, &this->ports[SPA_DIRECTION_OUTPUT].items) {
78
+       if (item->data)
79
+           emit_port_info(this, item->data);
80
    }
81
    spa_hook_list_join(&this->hooks, &save);
82
 
83
@@ -537,18 +519,8 @@
84
    pw_array_clear(&port->mix);
85
    pw_array_init(&port->mix, sizeof(struct mix) * 2);
86
 
87
-   if (port->direction == SPA_DIRECTION_INPUT) {
88
-       if (this->in_ports[port->id] == port) {
89
-           this->in_ports[port->id] = NULL;
90
-           this->n_inputs--;
91
-       }
92
-   }
93
-   else {
94
-       if (this->out_ports[port->id] == port) {
95
-           this->out_ports[port->id] = NULL;
96
-           this->n_outputs--;
97
-       }
98
-   }
99
+   pw_map_insert_at(&this->ports[port->direction], port->id, NULL);
100
+
101
    if (!port->removed)
102
        spa_node_emit_port_info(&this->hooks, port->direction, port->id, NULL);
103
 }
104
@@ -598,9 +570,9 @@
105
 
106
    spa_return_val_if_fail(this != NULL, -EINVAL);
107
    spa_return_val_if_fail(num != 0, -EINVAL);
108
-   spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
109
 
110
    port = GET_PORT(this, direction, port_id);
111
+   spa_return_val_if_fail(port != NULL, -EINVAL);
112
 
113
    pw_log_debug("%p: seq:%d port %d.%d id:%u start:%u num:%u n_params:%d",
114
            this, seq, direction, port_id, id, start, num, port->n_params);
115
@@ -649,15 +621,15 @@
116
    struct mix *mix;
117
 
118
    spa_return_val_if_fail(this != NULL, -EINVAL);
119
-   if(!CHECK_PORT(this, direction, port_id))
120
+
121
+   port = GET_PORT(this, direction, port_id);
122
+   if(port == NULL)
123
        return param == NULL ? 0 : -EINVAL;
124
 
125
    pw_log_debug("%p: port %d.%d set param %s %d", this,
126
            direction, port_id,
127
            spa_debug_type_find_name(spa_type_param, id), id);
128
 
129
-   port = GET_PORT(this, direction, port_id);
130
-
131
    if (id == SPA_PARAM_Format) {
132
        pw_array_for_each(mix, &port->mix)
133
            clear_buffers(this, mix);
134
@@ -687,10 +659,9 @@
135
            direction == SPA_DIRECTION_INPUT ? "input" : "output",
136
            port_id, mix_id, data, size);
137
 
138
-   if (!CHECK_PORT(this, direction, port_id))
139
-       return data == NULL ? 0 : -EINVAL;
140
-
141
    port = GET_PORT(this, direction, port_id);
142
+   if (port == NULL)
143
+       return data == NULL ? 0 : -EINVAL;
144
 
145
    if ((mix = find_mix(port, mix_id)) == NULL || !mix->valid)
146
        return -EINVAL;
147
@@ -752,13 +723,13 @@
148
    uint32_t i, j, peer_id;
149
    struct pw_client_node_buffer *mb;
150
 
151
-   if (!CHECK_PORT(this, direction, port_id))
152
+   p = GET_PORT(this, direction, port_id);
153
+   if (p == NULL)
154
        return n_buffers == 0 ? 0 : -EINVAL;
155
 
156
    if (n_buffers > MAX_BUFFERS)
157
        return -ENOSPC;
158
 
159
-   p = GET_PORT(this, direction, port_id);
160
 
161
    spa_log_debug(this->log, "%p: %s port %d.%d use buffers %p %u flags:%08x", this,
162
            direction == SPA_DIRECTION_INPUT ? "input" : "output",
163
@@ -920,7 +891,7 @@
164
    struct node *this = object;
165
 
166
    spa_return_val_if_fail(this != NULL, -EINVAL);
167
-   spa_return_val_if_fail(CHECK_OUT_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL);
168
+   spa_return_val_if_fail(CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL);
169
 
170
    spa_log_trace_fp(this->log, "reuse buffer %d", buffer_id);
171
 
172
@@ -1011,8 +982,6 @@
173
 
174
    spa_log_debug(this->log, "%p: got port update change:%08x params:%d",
175
            this, change_mask, n_params);
176
-   if (!CHECK_PORT_ID(this, direction, port_id))
177
-       return -EINVAL;
178
 
179
    remove = (change_mask == 0);
180
 
181
@@ -1027,6 +996,9 @@
182
        struct port *target;
183
 
184
        if (port == NULL) {
185
+           if (!CHECK_FREE_PORT(this, direction, port_id))
186
+               return -EINVAL;
187
+
188
            target = &this->dummy;
189
            spa_zero(this->dummy);
190
            target->direction = direction;
191
@@ -1076,9 +1048,8 @@
192
            direction == SPA_DIRECTION_INPUT ? "input" : "output",
193
            port_id, mix_id, buffers, n_buffers);
194
 
195
-   spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
196
-
197
    p = GET_PORT(this, direction, port_id);
198
+   spa_return_val_if_fail(p != NULL, -EINVAL);
199
 
200
    if (direction == SPA_DIRECTION_OUTPUT)
201
pipewire-0.3.45.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.47.tar.gz/src/modules/module-client-node/remote-node.c Changed
94
 
1
@@ -42,7 +42,6 @@
2
 #include "pipewire/extensions/client-node.h"
3
 
4
 #define MAX_BUFFERS    64
5
-#define MAX_MIX        4096
6
 
7
 PW_LOG_TOPIC_EXTERN(mod_topic);
8
 #define PW_LOG_TOPIC_DEFAULT mod_topic
9
@@ -74,7 +73,6 @@
10
    int rtwritefd;
11
    struct pw_memmap *activation;
12
 
13
-   struct mix mix_pool[MAX_MIX];
14
    struct spa_list mix[2];
15
    struct spa_list free_mix;
16
 
17
@@ -241,15 +239,17 @@
18
    if ((mix = find_mix(data, direction, port_id, mix_id)))
19
        return mix;
20
 
21
-   if (spa_list_is_empty(&data->free_mix))
22
-       return NULL;
23
-
24
    port = pw_impl_node_find_port(data->node, direction, port_id);
25
    if (port == NULL)
26
        return NULL;
27
 
28
-   mix = spa_list_first(&data->free_mix, struct mix, link);
29
-   spa_list_remove(&mix->link);
30
+   if (spa_list_is_empty(&data->free_mix)) {
31
+       if ((mix = calloc(1, sizeof(*mix))) == NULL)
32
+           return NULL;
33
+   } else {
34
+       mix = spa_list_first(&data->free_mix, struct mix, link);
35
+       spa_list_remove(&mix->link);
36
+   }
37
 
38
    mix_init(mix, port, mix_id);
39
    spa_list_append(&data->mix[direction], &mix->link);
40
@@ -986,21 +986,24 @@
41
    clear_buffers(data, mix);
42
    pw_array_clear(&mix->buffers);
43
 
44
-   spa_list_remove(&mix->mix.link);
45
    spa_list_append(&data->free_mix, &mix->link);
46
    pw_impl_port_release_mix(mix->port, &mix->mix);
47
 }
48
 
49
 static void clean_node(struct node_data *d)
50
 {
51
-   struct mix *mix, *tmp;
52
+   struct mix *mix;
53
 
54
    if (d->have_transport) {
55
-       spa_list_for_each_safe(mix, tmp, &d->mix[SPA_DIRECTION_INPUT], link)
56
+       spa_list_consume(mix, &d->mix[SPA_DIRECTION_INPUT], link)
57
            clear_mix(d, mix);
58
-       spa_list_for_each_safe(mix, tmp, &d->mix[SPA_DIRECTION_OUTPUT], link)
59
+       spa_list_consume(mix, &d->mix[SPA_DIRECTION_OUTPUT], link)
60
            clear_mix(d, mix);
61
    }
62
+   spa_list_consume(mix, &d->free_mix, link) {
63
+       spa_list_remove(&mix->link);
64
+       free(mix);
65
+   }
66
    clean_transport(d);
67
 }
68
 
69
@@ -1121,6 +1124,7 @@
70
    pw_log_debug("%p: removed", data);
71
 
72
    spa_hook_remove(&data->proxy_client_node_listener);
73
+   spa_hook_remove(&data->client_node_listener);
74
 
75
    if (data->node) {
76
        spa_hook_remove(&data->node_listener);
77
@@ -1220,7 +1224,6 @@
78
    struct pw_impl_node *node = object;
79
    struct pw_proxy *client_node;
80
    struct node_data *data;
81
-   int i;
82
 
83
    user_data_size = SPA_ROUND_UP_N(user_data_size, __alignof__(struct node_data));
84
 
85
@@ -1254,8 +1257,6 @@
86
    spa_list_init(&data->free_mix);
87
    spa_list_init(&data->mix[0]);
88
    spa_list_init(&data->mix[1]);
89
-   for (i = 0; i < MAX_MIX; i++)
90
-       spa_list_append(&data->free_mix, &data->mix_pool[i].link);
91
 
92
    spa_list_init(&data->links);
93
 
94
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.47.tar.gz/src/modules/module-echo-cancel.c Changed
201
 
1
@@ -43,10 +43,14 @@
2
 #include <spa/param/audio/raw.h>
3
 #include <spa/param/profiler.h>
4
 #include <spa/pod/builder.h>
5
+#include <spa/support/plugin.h>
6
 #include <spa/utils/json.h>
7
+#include <spa/utils/names.h>
8
 #include <spa/utils/result.h>
9
 #include <spa/utils/ringbuffer.h>
10
 #include <spa/utils/string.h>
11
+#include <spa/support/plugin-loader.h>
12
+#include <spa/interfaces/audio/aec.h>
13
 
14
 #include <pipewire/private.h>
15
 #include <pipewire/impl.h>
16
@@ -54,8 +58,6 @@
17
 
18
 #include <pipewire/extensions/profiler.h>
19
 
20
-#include "module-echo-cancel/echo-cancel.h"
21
-
22
 /** \page page_module_echo_cancel PipeWire Module: Echo Cancel
23
  *
24
  * The `echo-cancel` module performs echo cancellation. The module creates
25
@@ -68,8 +70,8 @@
26
  *
27
  * - `source.props = {}`: properties to be passed to the source stream
28
  * - `sink.props = {}`: properties to be passed to the sink stream
29
- * - `aec.method = <str>`: the echo cancellation method. Currently supported:
30
- * `webrtc`. Leave unset to use the default method (`webrtc`).
31
+ * - `library.name = <str>`: the echo cancellation library  Currently supported:
32
+ * `aec/libspa-aec-exaudio`. Leave unset to use the default method (`aec/libspa-aec-exaudio`).
33
  * - `aec.args = <str>`: arguments to pass to the echo cancellation method
34
  *
35
  * ## General options
36
@@ -94,7 +96,7 @@
37
  * context.modules = [
38
  *  {   name = libpipewire-module-echo-cancel
39
  *      args = {
40
- *          # aec.method = webrtc
41
+ *          # library.name  = aec/libspa-aec-exaudio
42
  *          # node.latency = 1024/48000
43
  *          source.props = {
44
  *             node.name = "Echo Cancellation Source"
45
@@ -138,7 +140,7 @@
46
                "[ audio.position=<channel map> ] "
47
                "[ buffer.max_size=<max buffer size in ms> ] "
48
                "[ buffer.play_delay=<play delay in ms> ] "
49
-               "[ aec.method=<aec method> ] "
50
+               "[ library.name =<library name> ] "
51
                "[ aec.args=<aec arguments> ] "
52
                "[ source.props=<properties> ] "
53
                "[ sink.props=<properties> ] " },
54
@@ -185,8 +187,7 @@
55
    uint32_t out_ringsize;
56
    struct spa_ringbuffer out_ring;
57
 
58
-   const struct echo_cancel_info *aec_info;
59
-   void *aec;
60
+   struct spa_audio_aec *aec;
61
    uint32_t aec_blocksize;
62
 
63
    unsigned int capture_ready:1;
64
@@ -197,6 +198,9 @@
65
 
66
    uint32_t max_buffer_size;
67
    uint32_t buffer_delay;
68
+
69
+   struct spa_handle *spa_handle;
70
+   struct spa_plugin_loader *loader;
71
 };
72
 
73
 static void do_unload_module(void *obj, void *data, int res, uint32_t id)
74
@@ -283,7 +287,7 @@
75
    pw_stream_queue_buffer(impl->playback, pout);
76
 
77
    /* Now run the canceller */
78
-   echo_cancel_run(impl->aec_info, impl->aec, rec, play_delayed, out, size / sizeof(float));
79
+   spa_audio_aec_run(impl->aec, rec, play_delayed, out, size / sizeof(float));
80
 
81
    /* Next, copy over the output to the output ringbuffer */
82
    avail = spa_ringbuffer_get_write_index(&impl->out_ring, &oindex);
83
@@ -647,8 +651,8 @@
84
        pw_properties_set(props, PW_KEY_NODE_LINK_GROUP, str);
85
    if ((str = pw_properties_get(impl->source_props, PW_KEY_NODE_LATENCY)) != NULL)
86
        pw_properties_set(props, PW_KEY_NODE_LATENCY, str);
87
-   else if (impl->aec_info->latency)
88
-       pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency);
89
+   else if (impl->aec->latency)
90
+       pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency);
91
 
92
    impl->capture = pw_stream_new(impl->core,
93
            "Echo-Cancel Capture", props);
94
@@ -680,8 +684,8 @@
95
        pw_properties_set(props, PW_KEY_NODE_LINK_GROUP, str);
96
    if ((str = pw_properties_get(impl->sink_props, PW_KEY_NODE_LATENCY)) != NULL)
97
        pw_properties_set(props, PW_KEY_NODE_LATENCY, str);
98
-   else if (impl->aec_info->latency)
99
-       pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency);
100
+   else if (impl->aec->latency)
101
+       pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency);
102
 
103
    impl->playback = pw_stream_new(impl->core,
104
            "Echo-Cancel Playback", props);
105
@@ -803,8 +807,8 @@
106
        pw_stream_destroy(impl->sink);
107
    if (impl->core && impl->do_disconnect)
108
        pw_core_disconnect(impl->core);
109
-   if (impl->aec)
110
-       echo_cancel_destroy(impl->aec_info, impl->aec);
111
+   if (impl->spa_handle)
112
+       spa_plugin_loader_unload(impl->loader, impl->spa_handle);
113
    pw_properties_free(impl->source_props);
114
    pw_properties_free(impl->sink_props);
115
 
116
@@ -893,7 +897,10 @@
117
    struct impl *impl;
118
    uint32_t id = pw_global_get_id(pw_impl_module_get_global(module));
119
    const char *str;
120
-   int res;
121
+   const char *path;
122
+   int res = 0;
123
+   struct spa_handle *handle = NULL;
124
+   void *iface;
125
 
126
    PW_LOG_TOPIC_INIT(mod_topic);
127
 
128
@@ -967,31 +974,66 @@
129
    if (pw_properties_get(impl->sink_props, PW_KEY_MEDIA_CLASS) == NULL)
130
        pw_properties_set(impl->sink_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
131
 
132
-   if ((str = pw_properties_get(props, "aec.method")) == NULL)
133
-       str = "webrtc";
134
+   if ((str = pw_properties_get(props, "aec.method")) != NULL)
135
+       pw_log_warn("aec.method is not supported anymore use library.name");
136
 
137
-#ifdef HAVE_WEBRTC
138
-   if (spa_streq(str, "webrtc"))
139
-       impl->aec_info = echo_cancel_webrtc;
140
-   else
141
-#endif
142
-       impl->aec_info = echo_cancel_null;
143
+   /* Use webrtc as default */
144
+   if ((path = pw_properties_get(props, "library.name")) == NULL)
145
+       path = "aec/libspa-aec-webrtc";
146
+
147
+   struct spa_dict_item info_items[] = {
148
+       { SPA_KEY_LIBRARY_NAME, path },
149
+   };
150
+   struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items);
151
+
152
+   impl->loader = spa_support_find(context->support, context->n_support, SPA_TYPE_INTERFACE_PluginLoader);
153
+   if (impl->loader == NULL) {
154
+       pw_log_error("a plugin loader is needed");
155
+       return -EINVAL;
156
+   }
157
+
158
+   handle = spa_plugin_loader_load(impl->loader, SPA_NAME_AEC, &info);
159
+   if (handle == NULL) {
160
+       pw_log_error("AEC codec plugin %s not available library.name %s", SPA_NAME_AEC, path);
161
+       return -ENOENT;
162
+   }
163
+
164
+   if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_AUDIO_AEC, &iface)) < 0) {
165
+       pw_log_error("can't get %s interface %d", SPA_TYPE_INTERFACE_AUDIO_AEC, res);
166
+       return res;
167
+   }
168
+   impl->aec = iface;
169
+   impl->spa_handle = handle;
170
+   if (impl->aec->iface.version != SPA_VERSION_AUDIO_AEC) {
171
+       pw_log_error("codec plugin %s has incompatible ABI version (%d != %d)",
172
+           SPA_NAME_AEC, impl->aec->iface.version, SPA_VERSION_AUDIO_AEC);
173
+       res = -ENOENT;
174
+       goto error;
175
+   }
176
+
177
+   (void)SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_AUDIO_AEC, (struct spa_audio_aec *)impl->aec);
178
+
179
+   pw_log_info("Using plugin AEC %s", impl->aec->name);
180
 
181
    if ((str = pw_properties_get(props, "aec.args")) != NULL)
182
        aec_props = pw_properties_new_string(str);
183
    else
184
        aec_props = pw_properties_new(NULL, NULL);
185
 
186
-   impl->aec = echo_cancel_create(impl->aec_info, aec_props, &impl->info);
187
+   if (spa_audio_aec_init(impl->aec, &aec_props->dict, &impl->info)) {
188
+       pw_log_error("codec plugin %s create failed", impl->aec->name);
189
+       res = -ENOENT;
190
+       goto error;
191
+   }
192
 
193
    pw_properties_free(aec_props);
194
 
195
-   if (impl->aec_info->latency) {
196
+   if (impl->aec->latency) {
197
        unsigned int num, denom, req_num, req_denom;
198
        unsigned int factor = 0;
199
        unsigned int new_num = 0;
200
 
201
pipewire-0.3.47.tar.gz/src/modules/module-fallback-sink.c Added
201
 
1
@@ -0,0 +1,473 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2021 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <string.h>
27
+#include <stdio.h>
28
+#include <errno.h>
29
+#include <sys/types.h>
30
+#include <sys/stat.h>
31
+#include <fcntl.h>
32
+#include <unistd.h>
33
+
34
+#include "config.h"
35
+
36
+#include <spa/utils/result.h>
37
+#include <spa/utils/string.h>
38
+#include <spa/param/audio/raw.h>
39
+
40
+#include <pipewire/impl.h>
41
+#include <pipewire/i18n.h>
42
+
43
+/** \page page_module_fallback_sink PipeWire Module: Fallback Sink
44
+ *
45
+ * Fallback sink, which appear dynamically when no other sinks are
46
+ * present. This is only useful for Pulseaudio compatibility.
47
+ */
48
+
49
+#define NAME "fallback-sink"
50
+
51
+#define DEFAULT_SINK_NAME      "auto_null"
52
+#define DEFAULT_SINK_DESCRIPTION   _("Dummy Output")
53
+
54
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
55
+#define PW_LOG_TOPIC_DEFAULT mod_topic
56
+
57
+#define MODULE_USAGE   ("[ sink.name=<str> ] " \
58
+           "[ sink.description=<str> ] ")
59
+
60
+static const struct spa_dict_item module_props[] = {
61
+   { PW_KEY_MODULE_AUTHOR, "Pauli Virtanen <pav@iki.fi>" },
62
+   { PW_KEY_MODULE_DESCRIPTION, "Dynamically appearing fallback sink" },
63
+   { PW_KEY_MODULE_USAGE, MODULE_USAGE },
64
+   { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
65
+};
66
+
67
+struct bitmap {
68
+   uint8_t *data;
69
+   size_t size;
70
+   size_t items;
71
+};
72
+
73
+struct impl {
74
+   struct pw_context *context;
75
+
76
+   struct pw_impl_module *module;
77
+   struct spa_hook module_listener;
78
+
79
+   struct pw_core *core;
80
+   struct pw_registry *registry;
81
+   struct pw_proxy *sink;
82
+
83
+   struct spa_hook core_listener;
84
+   struct spa_hook core_proxy_listener;
85
+   struct spa_hook registry_listener;
86
+   struct spa_hook sink_listener;
87
+
88
+   struct pw_properties *properties;
89
+
90
+   struct bitmap sink_ids;
91
+   struct bitmap fallback_sink_ids;
92
+
93
+   int check_seq;
94
+
95
+   unsigned int do_disconnect:1;
96
+   unsigned int scheduled:1;
97
+};
98
+
99
+static int bitmap_add(struct bitmap *map, uint32_t i)
100
+{
101
+   const uint32_t pos = (i >> 3);
102
+   const uint8_t mask = 1 << (i & 0x7);
103
+
104
+   if (pos >= map->size) {
105
+       size_t new_size = map->size + pos + 16;
106
+       void *p;
107
+
108
+       p = realloc(map->data, new_size);
109
+       if (!p)
110
+           return -errno;
111
+
112
+       memset((uint8_t*)p + map->size, 0, new_size - map->size);
113
+       map->data = p;
114
+       map->size = new_size;
115
+   }
116
+
117
+   if (map->data[pos] & mask)
118
+       return 1;
119
+
120
+   map->data[pos] |= mask;
121
+   ++map->items;
122
+
123
+   return 0;
124
+}
125
+
126
+static bool bitmap_remove(struct bitmap *map, uint32_t i)
127
+{
128
+   const uint32_t pos = (i >> 3);
129
+   const uint8_t mask = 1 << (i & 0x7);
130
+
131
+   if (pos >= map->size)
132
+       return false;
133
+
134
+   if (!(map->data[pos] & mask))
135
+       return false;
136
+
137
+   map->data[pos] &= ~mask;
138
+   --map->items;
139
+
140
+   return true;
141
+}
142
+
143
+static void bitmap_free(struct bitmap *map)
144
+{
145
+   free(map->data);
146
+   spa_zero(*map);
147
+}
148
+
149
+static int add_id(struct bitmap *map, uint32_t id)
150
+{
151
+   int res;
152
+
153
+   if (id == SPA_ID_INVALID)
154
+       return -EINVAL;
155
+
156
+   if ((res = bitmap_add(map, id)) < 0)
157
+          pw_log_error("%s", spa_strerror(res));
158
+
159
+   return res;
160
+}
161
+
162
+static void reschedule_check(struct impl *impl)
163
+{
164
+   if (!impl->scheduled)
165
+       return;
166
+
167
+   impl->check_seq = pw_core_sync(impl->core, 0, impl->check_seq);
168
+}
169
+
170
+static void schedule_check(struct impl *impl)
171
+{
172
+   if (impl->scheduled)
173
+       return;
174
+
175
+   impl->scheduled = true;
176
+   impl->check_seq = pw_core_sync(impl->core, 0, impl->check_seq);
177
+}
178
+
179
+static void sink_proxy_removed(void *data)
180
+{
181
+   struct impl *impl = data;
182
+
183
+   pw_proxy_destroy(impl->sink);
184
+}
185
+
186
+static void sink_proxy_bound(void *data, uint32_t id)
187
+{
188
+   struct impl *impl = data;
189
+
190
+   add_id(&impl->sink_ids, id);
191
+   add_id(&impl->fallback_sink_ids, id);
192
+
193
+   reschedule_check(impl);
194
+   schedule_check(impl);
195
+}
196
+
197
+static void sink_proxy_destroy(void *data)
198
+{
199
+   struct impl *impl = data;
200
+
201
pipewire-0.3.45.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.47.tar.gz/src/modules/module-profiler.c Changed
28
 
1
@@ -214,10 +214,17 @@
2
    spa_list_for_each(t, &node->rt.target_list, link) {
3
        struct pw_impl_node *n = t->node;
4
        struct pw_node_activation *na;
5
+       struct spa_fraction latency;
6
 
7
        if (n == NULL || n == node)
8
            continue;
9
 
10
+       latency = n->latency;
11
+       if (n->force_quantum != 0)
12
+           latency.num = n->force_quantum;
13
+       if (n->force_rate != 0)
14
+           latency.denom = n->force_rate;
15
+
16
        na = n->rt.activation;
17
        spa_pod_builder_prop(&b, SPA_PROFILER_followerBlock, 0);
18
        spa_pod_builder_add_struct(&b,
19
@@ -228,7 +235,7 @@
20
            SPA_POD_Long(na->awake_time),
21
            SPA_POD_Long(na->finish_time),
22
            SPA_POD_Int(na->status),
23
-           SPA_POD_Fraction(&n->latency));
24
+           SPA_POD_Fraction(&latency));
25
    }
26
    spa_pod_builder_pop(&b, &f[0]);
27
 
28
pipewire-0.3.45.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-native.c Changed
10
 
1
@@ -35,7 +35,7 @@
2
 #include <fcntl.h>
3
 #include <sys/file.h>
4
 #include <ctype.h>
5
-#if HAVE_PWD_H
6
+#ifdef HAVE_PWD_H
7
 #include <pwd.h>
8
 #endif
9
 #if defined(__FreeBSD__)
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-native/local-socket.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-native/local-socket.c Changed
10
 
1
@@ -35,7 +35,7 @@
2
 #include <sys/stat.h>
3
 #include <fcntl.h>
4
 #include <sys/file.h>
5
-#if HAVE_PWD_H
6
+#ifdef HAVE_PWD_H
7
 #include <pwd.h>
8
 #endif
9
 
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/client.c Changed
19
 
1
@@ -313,7 +313,7 @@
2
 }
3
 
4
 /* returns true if an event with the (mask, event, index) triplet should be dropped because it is redundant */
5
-static bool client_prune_subscribe_events(struct client *client, uint32_t mask, uint32_t event, uint32_t index)
6
+static bool client_prune_subscribe_events(struct client *client, uint32_t event, uint32_t index)
7
 {
8
    struct message *m, *t;
9
 
10
@@ -376,7 +376,7 @@
11
 
12
    pw_log_debug("client %p: SUBSCRIBE event:%08x index:%u", client, event, index);
13
 
14
-   if (client_prune_subscribe_events(client, mask, event, index))
15
+   if (client_prune_subscribe_events(client, event, index))
16
        return 0;
17
 
18
    struct message *reply = message_alloc(client->impl, -1, 0);
19
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c Changed
9
 
1
@@ -43,7 +43,6 @@
2
 #include "../extension.h"
3
 #include "../format.h"
4
 #include "../manager.h"
5
-#include "../media-roles.h"
6
 #include "../message.h"
7
 #include "../reply.h"
8
 #include "../volume.h"
9
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c Changed
11
 
1
@@ -42,8 +42,8 @@
2
 #include "../extension.h"
3
 #include "../format.h"
4
 #include "../manager.h"
5
-#include "../media-roles.h"
6
 #include "../message.h"
7
+#include "../remap.h"
8
 #include "../reply.h"
9
 #include "../volume.h"
10
 #include "registry.h"
11
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/message.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/message.c Changed
57
 
1
@@ -28,15 +28,14 @@
2
 #include <spa/debug/buffer.h>
3
 #include <spa/utils/defs.h>
4
 #include <spa/utils/string.h>
5
-#include <pipewire/keys.h>
6
 #include <pipewire/log.h>
7
 
8
 #include "defs.h"
9
 #include "format.h"
10
 #include "internal.h"
11
 #include "log.h"
12
-#include "media-roles.h"
13
 #include "message.h"
14
+#include "remap.h"
15
 #include "volume.h"
16
 
17
 #define MAX_SIZE   (256*1024)
18
@@ -65,20 +64,6 @@
19
    return v * v * v;
20
 }
21
 
22
-static const struct str_map key_table[] = {
23
-   { PW_KEY_DEVICE_BUS_PATH, "device.bus_path" },
24
-   { PW_KEY_DEVICE_FORM_FACTOR, "device.form_factor" },
25
-   { PW_KEY_DEVICE_ICON_NAME, "device.icon_name" },
26
-   { PW_KEY_DEVICE_INTENDED_ROLES, "device.intended_roles" },
27
-   { PW_KEY_NODE_DESCRIPTION, "device.description" },
28
-   { PW_KEY_MEDIA_ICON_NAME, "media.icon_name" },
29
-   { PW_KEY_APP_ICON_NAME, "application.icon_name" },
30
-   { PW_KEY_APP_PROCESS_MACHINE_ID, "application.process.machine_id" },
31
-   { PW_KEY_APP_PROCESS_SESSION_ID, "application.process.session_id" },
32
-   { PW_KEY_MEDIA_ROLE, "media.role", media_role_map },
33
-   { NULL, NULL },
34
-};
35
-
36
 static int read_u8(struct message *m, uint8_t *val)
37
 {
38
    if (m->offset + 1 > m->length)
39
@@ -153,7 +138,7 @@
40
                TAG_INVALID)) < 0)
41
            return res;
42
 
43
-       if (remap && (map = str_map_find(key_table, NULL, key)) != NULL) {
44
+       if (remap && (map = str_map_find(props_key_map, NULL, key)) != NULL) {
45
            key = map->pw_str;
46
            if (map->child != NULL &&
47
                (map = str_map_find(map->child, NULL, data)) != NULL)
48
@@ -567,7 +552,7 @@
49
            int l;
50
            const struct str_map *map;
51
 
52
-           if (remap && (map = str_map_find(key_table, key, NULL)) != NULL) {
53
+           if (remap && (map = str_map_find(props_key_map, key, NULL)) != NULL) {
54
                key = map->pa_str;
55
                if (map->child != NULL &&
56
                    (map = str_map_find(map->child, val, NULL)) != NULL)
57
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/module.c Changed
127
 
1
@@ -25,6 +25,7 @@
2
 
3
 #include <stdlib.h>
4
 #include <string.h>
5
+#include <ctype.h>
6
 
7
 #include <spa/utils/defs.h>
8
 #include <spa/utils/list.h>
9
@@ -41,6 +42,7 @@
10
 #include "internal.h"
11
 #include "log.h"
12
 #include "module.h"
13
+#include "remap.h"
14
 
15
 static void on_module_unload(void *obj, void *data, int res, uint32_t index)
16
 {
17
@@ -139,8 +141,11 @@
18
 {
19
    char *s = strdup(str), *p = s, *e, f;
20
    const char *k, *v;
21
+   const struct str_map *map;
22
 
23
    while (*p) {
24
+       while (*p && isspace(*p))
25
+           p++;
26
        e = strchr(p, '=');
27
        if (e == NULL)
28
            break;
29
@@ -168,6 +173,13 @@
30
        if (*e != '\0')
31
            p++;
32
        *e = '\0';
33
+
34
+       if ((map = str_map_find(props_key_map, NULL, k)) != NULL) {
35
+           k = map->pw_str;
36
+           if (map->child != NULL &&
37
+               (map = str_map_find(map->child, NULL, v)) != NULL)
38
+               v = map->pw_str;
39
+       }
40
        pw_properties_set(props, k, v);
41
    }
42
    free(s);
43
@@ -248,29 +260,30 @@
44
 #include "modules/registry.h"
45
 
46
 static const struct module_info module_list[] = {
47
-   { "module-combine-sink", create_module_combine_sink, },
48
-   { "module-echo-cancel", create_module_echo_cancel, },
49
-   { "module-ladspa-sink", create_module_ladspa_sink, },
50
-   { "module-ladspa-source", create_module_ladspa_source, },
51
-   { "module-loopback", create_module_loopback, },
52
-   { "module-null-sink", create_module_null_sink, },
53
-   { "module-native-protocol-tcp", create_module_native_protocol_tcp, },
54
-   { "module-pipe-source", create_module_pipe_source, },
55
-   { "module-pipe-sink", create_module_pipe_sink, },
56
-   { "module-raop-discover", create_module_raop_discover, },
57
-   { "module-remap-sink", create_module_remap_sink, },
58
-   { "module-remap-source", create_module_remap_source, },
59
-   { "module-simple-protocol-tcp", create_module_simple_protocol_tcp, },
60
-   { "module-switch-on-connect", create_module_switch_on_connect, },
61
-   { "module-tunnel-sink", create_module_tunnel_sink, },
62
-   { "module-tunnel-source", create_module_tunnel_source, },
63
-   { "module-zeroconf-discover", create_module_zeroconf_discover, },
64
+   { "module-always-sink", 1, create_module_always_sink, },
65
+   { "module-combine-sink", 0, create_module_combine_sink, },
66
+   { "module-echo-cancel", 0, create_module_echo_cancel, },
67
+   { "module-ladspa-sink", 0, create_module_ladspa_sink, },
68
+   { "module-ladspa-source", 0, create_module_ladspa_source, },
69
+   { "module-loopback", 0, create_module_loopback, },
70
+   { "module-null-sink", 0, create_module_null_sink, },
71
+   { "module-native-protocol-tcp", 0, create_module_native_protocol_tcp, },
72
+   { "module-pipe-source", 0, create_module_pipe_source, },
73
+   { "module-pipe-sink", 0, create_module_pipe_sink, },
74
+   { "module-raop-discover", 1, create_module_raop_discover, },
75
+   { "module-remap-sink", 0, create_module_remap_sink, },
76
+   { "module-remap-source", 0, create_module_remap_source, },
77
+   { "module-simple-protocol-tcp", 0, create_module_simple_protocol_tcp, },
78
+   { "module-switch-on-connect", 1, create_module_switch_on_connect, },
79
+   { "module-tunnel-sink", 0, create_module_tunnel_sink, },
80
+   { "module-tunnel-source", 0, create_module_tunnel_source, },
81
+   { "module-zeroconf-discover", 1, create_module_zeroconf_discover, },
82
 #ifdef HAVE_AVAHI
83
-   { "module-zeroconf-publish", create_module_zeroconf_publish, },
84
+   { "module-zeroconf-publish", 0, create_module_zeroconf_publish, },
85
 #endif
86
-   { "module-roc-sink", create_module_roc_sink, },
87
-   { "module-roc-source", create_module_roc_source, },
88
-   { "module-x11-bell", create_module_x11_bell, },
89
+   { "module-roc-sink", 0, create_module_roc_sink, },
90
+   { "module-roc-source", 0, create_module_roc_source, },
91
+   { "module-x11-bell", 0, create_module_x11_bell, },
92
 };
93
 
94
 static const struct module_info *find_module_info(const char *name)
95
@@ -285,6 +298,13 @@
96
    return NULL;
97
 }
98
 
99
+static int find_module_by_name(void *item_data, void *data)
100
+{
101
+   const char *name = data;
102
+   const struct module *module = item_data;
103
+   return spa_streq(module->name, name) ? 1 : 0;
104
+}
105
+
106
 struct module *module_create(struct client *client, const char *name, const char *args)
107
 {
108
    struct impl *impl = client->impl;
109
@@ -296,6 +316,17 @@
110
        errno = ENOENT;
111
        return NULL;
112
    }
113
+
114
+   if (info->load_once) {
115
+       int exists;
116
+       exists = pw_map_for_each(&impl->modules, find_module_by_name,
117
+               (void *)name);
118
+       if (exists) {
119
+           errno = EEXIST;
120
+           return NULL;
121
+       }
122
+   }
123
+
124
    module = info->create(impl, args);
125
    if (module == NULL)
126
        return NULL;
127
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/module.h Changed
9
 
1
@@ -37,6 +37,7 @@
2
 
3
 struct module_info {
4
    const char *name;
5
+   unsigned int load_once:1;
6
    struct module *(*create) (struct impl *impl, const char *args);
7
 };
8
 
9
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-always-sink.c Added
138
 
1
@@ -0,0 +1,136 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <pipewire/pipewire.h>
27
+
28
+#include "../module.h"
29
+
30
+#define NAME "always-sink"
31
+
32
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
33
+#define PW_LOG_TOPIC_DEFAULT mod_topic
34
+
35
+struct module_always_sink_data {
36
+   struct module *module;
37
+
38
+   struct pw_impl_module *mod;
39
+   struct spa_hook mod_listener;
40
+};
41
+
42
+static void module_destroy(void *data)
43
+{
44
+   struct module_always_sink_data *d = data;
45
+   spa_hook_remove(&d->mod_listener);
46
+   d->mod = NULL;
47
+   module_schedule_unload(d->module);
48
+}
49
+
50
+static const struct pw_impl_module_events module_events = {
51
+   PW_VERSION_IMPL_MODULE_EVENTS,
52
+   .destroy = module_destroy
53
+};
54
+
55
+static int module_always_sink_load(struct client *client, struct module *module)
56
+{
57
+   struct module_always_sink_data *data = module->user_data;
58
+   FILE *f;
59
+   char *args;
60
+   const char *str;
61
+   size_t size;
62
+
63
+   f = open_memstream(&args, &size);
64
+   fprintf(f, "{");
65
+   if ((str = pw_properties_get(module->props, "sink_name")) != NULL)
66
+       fprintf(f, " sink.name = \"%s\"", str);
67
+   fprintf(f, " }");
68
+   fclose(f);
69
+
70
+   data->mod = pw_context_load_module(module->impl->context,
71
+           "libpipewire-module-fallback-sink",
72
+           args, NULL);
73
+   free(args);
74
+
75
+   if (data->mod == NULL)
76
+       return -errno;
77
+
78
+   pw_impl_module_add_listener(data->mod,
79
+           &data->mod_listener,
80
+           &module_events, data);
81
+   return 0;
82
+}
83
+
84
+static int module_always_sink_unload(struct module *module)
85
+{
86
+   struct module_always_sink_data *d = module->user_data;
87
+
88
+   if (d->mod) {
89
+       spa_hook_remove(&d->mod_listener);
90
+       pw_impl_module_destroy(d->mod);
91
+       d->mod = NULL;
92
+   }
93
+   return 0;
94
+}
95
+
96
+static const struct module_methods module_always_sink_methods = {
97
+   VERSION_MODULE_METHODS,
98
+   .load = module_always_sink_load,
99
+   .unload = module_always_sink_unload,
100
+};
101
+
102
+static const struct spa_dict_item module_always_sink_info[] = {
103
+   { PW_KEY_MODULE_AUTHOR, "Pauli Virtanen <pav@iki.fi>" },
104
+   { PW_KEY_MODULE_DESCRIPTION, "Always keeps at least one sink loaded even if it's a null one" },
105
+   { PW_KEY_MODULE_USAGE,  "sink_name=<name of sink>" },
106
+   { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
107
+};
108
+
109
+struct module *create_module_always_sink(struct impl *impl, const char *argument)
110
+{
111
+   struct module *module;
112
+   struct pw_properties *props = NULL;
113
+   int res;
114
+
115
+   PW_LOG_TOPIC_INIT(mod_topic);
116
+
117
+   props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(module_always_sink_info));
118
+   if (props == NULL) {
119
+       res = -EINVAL;
120
+       goto out;
121
+   }
122
+   if (argument)
123
+       module_args_add_props(props, argument);
124
+
125
+   module = module_new(impl, &module_always_sink_methods, sizeof(struct module_always_sink_data));
126
+   if (module == NULL) {
127
+       res = -errno;
128
+       goto out;
129
+   }
130
+   module->props = props;
131
+
132
+   return module;
133
+out:
134
+   pw_properties_free(props);
135
+   errno = -res;
136
+   return NULL;
137
+}
138
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c Changed
201
 
1
@@ -39,6 +39,8 @@
2
 
3
 #define MAX_SINKS 64 /* ... good enough for anyone */
4
 
5
+#define TIMEOUT_SINKS_MSEC 2000
6
+
7
 static const struct spa_dict_item module_combine_sink_info[] = {
8
    { PW_KEY_MODULE_AUTHOR, "Arun Raghavan <arun@asymptotic.io>" },
9
    { PW_KEY_MODULE_DESCRIPTION, "Combine multiple sinks into a single sink" },
10
@@ -61,6 +63,7 @@
11
    struct spa_hook stream_listener;
12
    struct module_combine_sink_data *data;
13
    bool cleanup;
14
+   bool started;
15
 };
16
 
17
 struct module_combine_sink_data {
18
@@ -80,8 +83,14 @@
19
    struct combine_stream streams[MAX_SINKS];
20
 
21
    struct spa_source *cleanup;
22
+   struct spa_source *sinks_timeout;
23
 
24
    struct spa_audio_info_raw info;
25
+
26
+   unsigned int sinks_pending;
27
+   unsigned int source_started:1;
28
+   unsigned int load_emitted:1;
29
+   unsigned int start_error:1;
30
 };
31
 
32
 /* Core connection: mainly to unload the module if the connection errors out */
33
@@ -161,6 +170,24 @@
34
        pw_stream_queue_buffer(data->sink, in);
35
 }
36
 
37
+static void check_initialized(struct module_combine_sink_data *data)
38
+{
39
+   struct module *module = data->module;
40
+
41
+   if (data->load_emitted)
42
+       return;
43
+
44
+   if (data->start_error) {
45
+       pw_log_debug("module load error");
46
+       data->load_emitted = true;
47
+       module_emit_loaded(module, -EIO);
48
+   } else if (data->sinks_pending == 0 && data->source_started) {
49
+       pw_log_debug("module loaded");
50
+       data->load_emitted = true;
51
+       module_emit_loaded(module, 0);
52
+   }
53
+}
54
+
55
 static void on_in_stream_state_changed(void *d, enum pw_stream_state old,
56
        enum pw_stream_state state, const char *error)
57
 {
58
@@ -168,6 +195,14 @@
59
    struct module *module = data->module;
60
    uint32_t i;
61
 
62
+   if (!data->source_started && state != PW_STREAM_STATE_CONNECTING) {
63
+       /* Input stream appears on server */
64
+       data->source_started = true;
65
+       if (state < PW_STREAM_STATE_PAUSED)
66
+           data->start_error = true;
67
+       check_initialized(data);
68
+   }
69
+
70
    switch (state) {
71
    case PW_STREAM_STATE_PAUSED:
72
        pw_stream_flush(data->sink, false);
73
@@ -199,6 +234,16 @@
74
 {
75
    struct combine_stream *s = data;
76
 
77
+   if (!s->started && state != PW_STREAM_STATE_CONNECTING) {
78
+       /* Output stream appears on server */
79
+       s->started = true;
80
+       if (s->data->sinks_pending > 0)
81
+           --s->data->sinks_pending;
82
+       if (state < PW_STREAM_STATE_PAUSED)
83
+           s->data->start_error = true;
84
+       check_initialized(s->data);
85
+   }
86
+
87
    if (state == PW_STREAM_STATE_UNCONNECTED) {
88
        s->cleanup = true;
89
        pw_loop_signal_event(s->data->module->impl->loop, s->data->cleanup);
90
@@ -270,12 +315,13 @@
91
    pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true");
92
    pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
93
    pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true");
94
+   pw_properties_setf(props, "pulse.module.id", "%u", data->module->index);
95
 
96
    cstream->data = data;
97
    cstream->stream = pw_stream_new(data->core, NULL, props);
98
    if (cstream->stream == NULL) {
99
        pw_log_error("Could not create stream");
100
-       return;
101
+       goto error;
102
    }
103
 
104
    pw_stream_add_listener(cstream->stream,
105
@@ -295,8 +341,14 @@
106
            PW_STREAM_FLAG_RT_PROCESS,
107
            params, n_params)) < 0) {
108
        pw_log_error("Could not connect to sink '%s'", sink_name);
109
-       return;
110
+       goto error;
111
    }
112
+
113
+   return;
114
+
115
+error:
116
+   data->start_error = true;
117
+   check_initialized(data);
118
 }
119
 
120
 static const struct pw_manager_events manager_events = {
121
@@ -325,6 +377,17 @@
122
    }
123
 }
124
 
125
+static void on_sinks_timeout(void *d, uint64_t count)
126
+{
127
+   struct module_combine_sink_data *data = d;
128
+
129
+   if (data->load_emitted)
130
+       return;
131
+
132
+   data->start_error = true;
133
+   check_initialized(data);
134
+}
135
+
136
 static int module_combine_sink_load(struct client *client, struct module *module)
137
 {
138
    struct module_combine_sink_data *data = module->user_data;
139
@@ -354,6 +417,7 @@
140
    pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index);
141
    pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index);
142
    pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
143
+   pw_properties_setf(props, "pulse.module.id", "%u", module->index);
144
 
145
    if ((str = pw_properties_get(module->props, "sink_properties")) != NULL)
146
        module_args_add_props(props, str);
147
@@ -379,7 +443,7 @@
148
        return res;
149
 
150
    data->manager = pw_manager_new(data->core);
151
-   if (client->manager == NULL)
152
+   if (data->manager == NULL)
153
        return -errno;
154
 
155
    pw_manager_add_listener(data->manager, &data->manager_listener,
156
@@ -387,7 +451,15 @@
157
 
158
    data->cleanup = pw_loop_add_event(module->impl->loop, on_cleanup, data);
159
 
160
-   return 0;
161
+   data->sinks_timeout = pw_loop_add_timer(module->impl->loop, on_sinks_timeout, data);
162
+   if (data->sinks_timeout) {
163
+       struct timespec timeout = {0}, interval = {0};
164
+       timeout.tv_sec = TIMEOUT_SINKS_MSEC / 1000;
165
+       timeout.tv_nsec = (TIMEOUT_SINKS_MSEC % 1000) * SPA_NSEC_PER_MSEC;
166
+       pw_loop_update_timer(module->impl->loop, data->sinks_timeout, &timeout, &interval, false);
167
+   }
168
+
169
+   return data->load_emitted ? 0 : SPA_RESULT_RETURN_ASYNC(0);
170
 }
171
 
172
 static int module_combine_sink_unload(struct module *module)
173
@@ -398,6 +470,9 @@
174
    if (d->cleanup != NULL)
175
        pw_loop_destroy_source(module->impl->loop, d->cleanup);
176
 
177
+   if (d->sinks_timeout != NULL)
178
+       pw_loop_destroy_source(module->impl->loop, d->sinks_timeout);
179
+
180
    /* Note that we explicitly disconnect the hooks to avoid having the
181
     * cleanup triggered again in those callbacks */
182
    if (d->sink != NULL) {
183
@@ -440,7 +515,8 @@
184
    const char *str;
185
    char *sink_name = NULL, **sink_names = NULL;
186
    struct spa_audio_info_raw info = { 0 };
187
-   int i, n, res;
188
+   int i, res;
189
+   int num_sinks = 0;
190
 
191
    PW_LOG_TOPIC_INIT(mod_topic);
192
 
193
@@ -460,7 +536,7 @@
194
    }
195
 
196
    if ((str = pw_properties_get(props, "slaves")) != NULL) {
197
-       sink_names = pw_split_strv(str, ",", MAX_SINKS, &n);
198
+       sink_names = pw_split_strv(str, ",", MAX_SINKS, &num_sinks);
199
        pw_properties_set(props, "slaves", NULL);
200
    }
201
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c Changed
25
 
1
@@ -75,6 +75,8 @@
2
 
3
    pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index);
4
    pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index);
5
+   pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+   pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
7
 
8
    f = open_memstream(&args, &size);
9
    fprintf(f, "{");
10
@@ -215,6 +217,14 @@
11
    if (pw_properties_get(capture_props, PW_KEY_DEVICE_CLASS) == NULL)
12
        pw_properties_set(capture_props, PW_KEY_DEVICE_CLASS, "filter");
13
 
14
+   if ((str = pw_properties_get(capture_props, PW_KEY_NODE_DESCRIPTION)) == NULL) {
15
+       str = pw_properties_get(capture_props, PW_KEY_NODE_NAME);
16
+       pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
17
+                   "%s Sink", str);
18
+   } else {
19
+       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str);
20
+   }
21
+
22
    if ((str = pw_properties_get(props, "master")) != NULL ||
23
        (str = pw_properties_get(props, "sink_master")) != NULL) {
24
        pw_properties_set(playback_props, PW_KEY_NODE_TARGET, str);
25
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c Changed
53
 
1
@@ -75,6 +75,8 @@
2
 
3
    pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index);
4
    pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index);
5
+   pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+   pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
7
 
8
    f = open_memstream(&args, &size);
9
    fprintf(f, "{");
10
@@ -203,11 +205,11 @@
11
        module_args_add_props(props, argument);
12
 
13
    if ((str = pw_properties_get(props, "source_name")) != NULL) {
14
-       pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
15
+       pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
16
        pw_properties_set(props, "source_name", NULL);
17
    }
18
    if ((str = pw_properties_get(props, "source_properties")) != NULL) {
19
-       module_args_add_props(capture_props, str);
20
+       module_args_add_props(playback_props, str);
21
        pw_properties_set(props, "source_properties", NULL);
22
    }
23
    if (pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS) == NULL)
24
@@ -215,17 +217,25 @@
25
    if (pw_properties_get(playback_props, PW_KEY_DEVICE_CLASS) == NULL)
26
        pw_properties_set(playback_props, PW_KEY_DEVICE_CLASS, "filter");
27
 
28
+   if ((str = pw_properties_get(playback_props, PW_KEY_NODE_DESCRIPTION)) == NULL) {
29
+       str = pw_properties_get(playback_props, PW_KEY_NODE_NAME);
30
+       pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
31
+                   "%s Source", str);
32
+   } else {
33
+       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str);
34
+   }
35
+
36
    if ((str = pw_properties_get(props, "master")) != NULL ||
37
        (str = pw_properties_get(props, "source_master")) != NULL) {
38
-       pw_properties_set(playback_props, PW_KEY_NODE_TARGET, str);
39
+       pw_properties_set(capture_props, PW_KEY_NODE_TARGET, str);
40
        pw_properties_set(props, "master", NULL);
41
    }
42
 
43
-   if (module_args_to_audioinfo(impl, props, &capture_info) < 0) {
44
+   if (module_args_to_audioinfo(impl, props, &playback_info) < 0) {
45
        res = -EINVAL;
46
        goto out;
47
    }
48
-   playback_info = capture_info;
49
+   capture_info = playback_info;
50
 
51
    position_to_props(&capture_info, capture_props);
52
    position_to_props(&playback_info, playback_props);
53
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c Changed
10
 
1
@@ -72,6 +72,8 @@
2
 
3
    pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
4
    pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
5
+   pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+   pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
7
 
8
    f = open_memstream(&args, &size);
9
    fprintf(f, "{");
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c Changed
10
 
1
@@ -115,6 +115,8 @@
2
 
3
    pw_core_add_listener(d->core, &d->core_listener, &core_events, module);
4
 
5
+   pw_properties_setf(module->props, "pulse.module.id", "%u", module->index);
6
+
7
    d->proxy = pw_core_create_object(d->core,
8
                     "adapter", PW_TYPE_INTERFACE_Node, PW_VERSION_NODE,
9
                     module->props ? &module->props->dict : NULL, 0);
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c Changed
10
 
1
@@ -159,6 +159,8 @@
2
            &data->core_listener,
3
            &core_events, data);
4
 
5
+   pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+
7
    data->capture = pw_stream_new(data->core,
8
            "pipesink capture", data->capture_props);
9
    data->capture_props = NULL;
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c Changed
11
 
1
@@ -180,6 +180,9 @@
2
            &data->core_listener,
3
            &core_events, data);
4
 
5
+   pw_properties_setf(data->playback_props, "pulse.module.id",
6
+           "%u", module->index);
7
+
8
    data->playback = pw_stream_new(data->core,
9
            "pipesource playback", data->playback_props);
10
    data->playback_props = NULL;
11
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c Changed
10
 
1
@@ -69,6 +69,8 @@
2
 
3
    pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index);
4
    pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index);
5
+   pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+   pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
7
 
8
    f = open_memstream(&args, &size);
9
    fprintf(f, "{");
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c Changed
10
 
1
@@ -69,6 +69,8 @@
2
 
3
    pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index);
4
    pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index);
5
+   pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
6
+   pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
7
 
8
    f = open_memstream(&args, &size);
9
    fprintf(f, "{");
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c Changed
28
 
1
@@ -67,22 +67,15 @@
2
 {
3
    struct module_roc_sink_data *data = module->user_data;
4
    FILE *f;
5
-   const char *str;
6
    char *args;
7
    size_t size;
8
 
9
+   pw_properties_setf(data->sink_props, "pulse.module.id",
10
+           "%u", module->index);
11
+
12
    f = open_memstream(&args, &size);
13
    fprintf(f, "{");
14
-   /* Can't just serialise this dict because the "null" method gets
15
-    * interpreted as a JSON null */
16
-   if ((str = pw_properties_get(data->roc_props, "local.ip")))
17
-       fprintf(f, " local.ip = \"%s\"", str);
18
-   if ((str = pw_properties_get(data->roc_props, "remote.ip")))
19
-       fprintf(f, " remote.ip = \"%s\"", str);
20
-   if ((str = pw_properties_get(data->roc_props, "remote.source.port")))
21
-       fprintf(f, " remote.source.port = \"%s\"", str);
22
-   if ((str = pw_properties_get(data->roc_props, "remote.repair.port")))
23
-       fprintf(f, " remote.repair.port = \"%s\"", str);
24
+   pw_properties_serialize_dict(f, &data->roc_props->dict, 0);
25
    fprintf(f, " } sink.props = {");
26
    pw_properties_serialize_dict(f, &data->sink_props->dict, 0);
27
    fprintf(f, " } }");
28
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c Changed
30
 
1
@@ -67,24 +67,15 @@
2
 {
3
    struct module_roc_source_data *data = module->user_data;
4
    FILE *f;
5
-   const char *str;
6
    char *args;
7
    size_t size;
8
 
9
+   pw_properties_setf(data->source_props, "pulse.module.id",
10
+           "%u", module->index);
11
+
12
    f = open_memstream(&args, &size);
13
    fprintf(f, "{");
14
-   /* Can't just serialise this dict because the "null" method gets
15
-    * interpreted as a JSON null */
16
-   if ((str = pw_properties_get(data->roc_props, "local.ip")))
17
-       fprintf(f, " local.ip = \"%s\"", str);
18
-   if ((str = pw_properties_get(data->roc_props, "local.source.port")))
19
-       fprintf(f, " local.source.port = \"%s\"", str);
20
-   if ((str = pw_properties_get(data->roc_props, "local.repair.port")))
21
-       fprintf(f, " local.repair.port = \"%s\"", str);
22
-   if ((str = pw_properties_get(data->roc_props, "sess.latency.msec")))
23
-       fprintf(f, " sess.latency.msec = \"%s\"", str);
24
-   if ((str = pw_properties_get(data->roc_props, "resampler.profile")))
25
-       fprintf(f, " resampler.profile = \"%s\"", str);
26
+   pw_properties_serialize_dict(f, &data->roc_props->dict, 0);
27
    fprintf(f, " } source.props = {");
28
    pw_properties_serialize_dict(f, &data->source_props->dict, 0);
29
    fprintf(f, " } }");
30
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c Changed
11
 
1
@@ -73,6 +73,9 @@
2
 
3
    server = pw_properties_get(module->props, "server");
4
 
5
+   pw_properties_setf(data->stream_props, "pulse.module.id",
6
+           "%u", module->index);
7
+
8
    f = open_memstream(&args, &size);
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c Changed
11
 
1
@@ -71,6 +71,9 @@
2
    size_t size;
3
    const char *server;
4
 
5
+   pw_properties_setf(data->stream_props, "pulse.module.id",
6
+           "%u", module->index);
7
+
8
    server = pw_properties_get(module->props, "server");
9
 
10
    f = open_memstream(&args, &size);
11
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c Changed
10
 
1
@@ -591,7 +591,7 @@
2
    }
3
 
4
    data->manager = pw_manager_new(data->core);
5
-   if (client->manager == NULL) {
6
+   if (data->manager == NULL) {
7
        pw_log_error("failed to create pipewire manager: %m");
8
        return -errno;
9
    }
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/registry.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/registry.h Changed
9
 
1
@@ -28,6 +28,7 @@
2
 
3
 struct impl;
4
 
5
+struct module *create_module_always_sink(struct impl *impl, const char *argument);
6
 struct module *create_module_combine_sink(struct impl *impl, const char *argument);
7
 struct module *create_module_echo_cancel(struct impl *impl, const char *argument);
8
 struct module *create_module_ladspa_sink(struct impl *impl, const char *argument);
9
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/operation.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/operation.c Changed
44
 
1
@@ -33,7 +33,9 @@
2
 #include "operation.h"
3
 #include "reply.h"
4
 
5
-int operation_new(struct client *client, uint32_t tag)
6
+int operation_new_cb(struct client *client, uint32_t tag,
7
+       void (*callback)(void *data, struct client *client, uint32_t tag),
8
+       void *data)
9
 {
10
    struct operation *o;
11
 
12
@@ -42,6 +44,8 @@
13
 
14
    o->client = client;
15
    o->tag = tag;
16
+   o->callback = callback;
17
+   o->data = data;
18
 
19
    spa_list_append(&client->operations, &o->link);
20
    pw_manager_sync(client->manager);
21
@@ -51,6 +55,11 @@
22
    return 0;
23
 }
24
 
25
+int operation_new(struct client *client, uint32_t tag)
26
+{
27
+   return operation_new_cb(client, tag, NULL, NULL);
28
+}
29
+
30
 void operation_free(struct operation *o)
31
 {
32
    spa_list_remove(&o->link);
33
@@ -63,6 +72,9 @@
34
 
35
    pw_log_info("[%s]: tag:%u complete", client->name, o->tag);
36
 
37
-   reply_simple_ack(client, o->tag);
38
+   if (o->callback)
39
+       o->callback(o->data, client, o->tag);
40
+   else
41
+       reply_simple_ack(client, o->tag);
42
    operation_free(o);
43
 }
44
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/operation.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/operation.h Changed
16
 
1
@@ -35,9 +35,14 @@
2
    struct spa_list link;
3
    struct client *client;
4
    uint32_t tag;
5
+   void (*callback) (void *data, struct client *client, uint32_t tag);
6
+   void *data;
7
 };
8
 
9
 int operation_new(struct client *client, uint32_t tag);
10
+int operation_new_cb(struct client *client, uint32_t tag,
11
+       void (*callback) (void *data, struct client *client, uint32_t tag),
12
+       void *data);
13
 void operation_free(struct operation *o);
14
 void operation_complete(struct operation *o);
15
 
16
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
201
 
1
@@ -209,14 +209,14 @@
2
 }
3
 
4
 static int send_object_event(struct client *client, struct pw_manager_object *o,
5
-       uint32_t facility)
6
+       uint32_t type)
7
 {
8
    uint32_t event = 0, mask = 0, res_index = o->index;
9
 
10
    if (pw_manager_object_is_sink(o)) {
11
        client_queue_subscribe_event(client,
12
                SUBSCRIPTION_MASK_SINK,
13
-               SUBSCRIPTION_EVENT_SINK | facility,
14
+               SUBSCRIPTION_EVENT_SINK | type,
15
                res_index);
16
    }
17
    if (pw_manager_object_is_source_or_monitor(o)) {
18
@@ -248,7 +248,7 @@
19
    if (event != SPA_ID_INVALID)
20
        client_queue_subscribe_event(client,
21
                mask,
22
-               event | facility,
23
+               event | type,
24
                res_index);
25
    return 0;
26
 }
27
@@ -374,15 +374,14 @@
28
 
29
    if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH)
30
        attr->maxlength = MAXLENGTH;
31
-   attr->maxlength -= attr->maxlength % frame_size;
32
-   attr->maxlength = SPA_MAX(attr->maxlength, frame_size);
33
+   attr->maxlength = SPA_ROUND_UP(attr->maxlength, frame_size);
34
+
35
+   minreq = SPA_MIN(minreq, attr->maxlength);
36
 
37
    if (attr->tlength == (uint32_t) -1)
38
        attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss);
39
-   if (attr->tlength > attr->maxlength)
40
-       attr->tlength = attr->maxlength;
41
-   attr->tlength -= attr->tlength % frame_size;
42
-   attr->tlength = SPA_MAX(attr->tlength, frame_size);
43
+   attr->tlength = SPA_MIN(attr->tlength, attr->maxlength);
44
+   attr->tlength = SPA_ROUND_UP(attr->tlength, frame_size);
45
    attr->tlength = SPA_MAX(attr->tlength, minreq);
46
 
47
    if (attr->minreq == (uint32_t) -1) {
48
@@ -390,13 +389,13 @@
49
        /* With low-latency, tlength/4 gives a decent default in all of traditional,
50
         * adjust latency and early request modes. */
51
        uint32_t m = attr->tlength / 4;
52
-       m -= m % frame_size;
53
+       m = SPA_ROUND_DOWN(m, frame_size);
54
        attr->minreq = SPA_MIN(process, m);
55
    }
56
    attr->minreq = SPA_MAX(attr->minreq, minreq);
57
 
58
    if (attr->tlength < attr->minreq+frame_size)
59
-       attr->tlength = attr->minreq + frame_size;
60
+       attr->tlength = SPA_MIN(attr->minreq + frame_size, attr->maxlength);
61
 
62
    if (s->early_requests) {
63
        latency = attr->minreq;
64
@@ -406,7 +405,7 @@
65
        else
66
            latency = attr->minreq;
67
 
68
-       latency -= latency % frame_size;
69
+       latency = SPA_ROUND_DOWN(latency, frame_size);
70
 
71
        if (attr->tlength >= latency)
72
            attr->tlength -= latency;
73
@@ -418,20 +417,20 @@
74
    }
75
 
76
    if (attr->tlength < latency + 2 * attr->minreq)
77
-       attr->tlength = latency + 2 * attr->minreq;
78
+       attr->tlength = SPA_MIN(latency + 2 * attr->minreq, attr->maxlength);
79
 
80
-   attr->minreq -= attr->minreq % frame_size;
81
+   attr->minreq = SPA_ROUND_DOWN(attr->minreq, frame_size);
82
    if (attr->minreq <= 0) {
83
        attr->minreq = frame_size;
84
        attr->tlength += frame_size*2;
85
    }
86
    if (attr->tlength <= attr->minreq)
87
-       attr->tlength = attr->minreq*2 + frame_size;
88
+       attr->tlength = SPA_MIN(attr->minreq*2 + frame_size, attr->maxlength);
89
 
90
    max_prebuf = attr->tlength + frame_size - attr->minreq;
91
    if (attr->prebuf == (uint32_t) -1 || attr->prebuf > max_prebuf)
92
        attr->prebuf = max_prebuf;
93
-   attr->prebuf -= attr->prebuf % frame_size;
94
+   attr->prebuf = SPA_ROUND_DOWN(attr->prebuf, frame_size);
95
 
96
    attr->fragsize = 0;
97
 
98
@@ -947,6 +946,9 @@
99
    pw_log_info("[%s] SUBSCRIBE tag:%u mask:%08x",
100
            client->name, tag, mask);
101
 
102
+   if (mask & ~SUBSCRIPTION_MASK_ALL)
103
+       return -EINVAL;
104
+
105
    client->subscribed = mask;
106
 
107
    return reply_simple_ack(client, tag);
108
@@ -2322,11 +2324,11 @@
109
    return o;
110
 }
111
 
112
-static void sample_play_ready(void *data, uint32_t index)
113
+static void sample_play_ready_reply(void *data, struct client *client, uint32_t tag)
114
 {
115
    struct pending_sample *ps = data;
116
-   struct client *client = ps->client;
117
    struct message *reply;
118
+   uint32_t index = id_to_index(client->manager, ps->play->id);
119
 
120
    pw_log_info("[%s] PLAY_SAMPLE tag:%u index:%u",
121
            client->name, ps->tag, index);
122
@@ -2340,6 +2342,13 @@
123
    client_queue_message(client, reply);
124
 }
125
 
126
+static void sample_play_ready(void *data, uint32_t id)
127
+{
128
+   struct pending_sample *ps = data;
129
+   struct client *client = ps->client;
130
+   operation_new_cb(client, ps->tag, sample_play_ready_reply, ps);
131
+}
132
+
133
 static void on_sample_done(void *obj, void *data, int res, uint32_t id)
134
 {
135
    struct pending_sample *ps = obj;
136
@@ -3556,6 +3565,9 @@
137
        snprintf(monitor_name, size, "%s.monitor", name);
138
 
139
    if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL)
140
+       module_id = id_to_index(manager, (uint32_t)atoi(str));
141
+   if (module_id == SPA_ID_INVALID &&
142
+       (str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL)
143
        module_id = (uint32_t)atoi(str);
144
    if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
145
        card_id = (uint32_t)atoi(str);
146
@@ -3601,7 +3613,7 @@
147
        TAG_STRING, desc,
148
        TAG_SAMPLE_SPEC, &dev_info.ss,
149
        TAG_CHANNEL_MAP, &dev_info.map,
150
-       TAG_U32, id_to_index(manager, module_id),   /* module index */
151
+       TAG_U32, module_id,         /* module index */
152
        TAG_CVOLUME, &dev_info.volume_info.volume,
153
        TAG_BOOLEAN, dev_info.volume_info.mute,
154
        TAG_U32, o->index,          /* monitor source index */
155
@@ -3760,6 +3772,9 @@
156
    snprintf(monitor_desc, size, "Monitor of %s", desc);
157
 
158
    if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL)
159
+       module_id = id_to_index(manager, (uint32_t)atoi(str));
160
+   if (module_id == SPA_ID_INVALID &&
161
+       (str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL)
162
        module_id = (uint32_t)atoi(str);
163
    if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
164
        card_id = (uint32_t)atoi(str);
165
@@ -3804,7 +3819,7 @@
166
        TAG_STRING, is_monitor ? monitor_desc : desc,
167
        TAG_SAMPLE_SPEC, &dev_info.ss,
168
        TAG_CHANNEL_MAP, &dev_info.map,
169
-       TAG_U32, id_to_index(manager, module_id),   /* module index */
170
+       TAG_U32, module_id,             /* module index */
171
        TAG_CVOLUME, &dev_info.volume_info.volume,
172
        TAG_BOOLEAN, dev_info.volume_info.mute,
173
        TAG_U32, is_monitor ? o->index : SPA_ID_INVALID,/* monitor of sink */
174
@@ -3908,7 +3923,11 @@
175
        return -ENOENT;
176
 
177
    if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL)
178
+       module_id = id_to_index(manager, (uint32_t)atoi(str));
179
+   if (module_id == SPA_ID_INVALID &&
180
+       (str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL)
181
        module_id = (uint32_t)atoi(str);
182
+
183
    if (!pw_manager_object_is_virtual(o) &&
184
        (str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
185
        client_id = (uint32_t)atoi(str);
186
@@ -3929,7 +3948,7 @@
187
    message_put(m,
188
        TAG_U32, o->index,              /* sink_input index */
189
        TAG_STRING, get_media_name(info),
190
-       TAG_U32, id_to_index(manager, module_id),   /* module index */
191
+       TAG_U32, module_id,             /* module index */
192
        TAG_U32, id_to_index(manager, client_id),   /* client index */
193
        TAG_U32, peer_index,                /* sink index */
194
        TAG_SAMPLE_SPEC, &dev_info.ss,
195
@@ -3984,7 +4003,11 @@
196
        return -ENOENT;
197
 
198
    if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL)
199
+       module_id = id_to_index(manager, (uint32_t)atoi(str));
200
+   if (module_id == SPA_ID_INVALID &&
201
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/quirks.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/quirks.c Changed
137
 
1
@@ -46,111 +46,8 @@
2
    return 0;
3
 }
4
 
5
-static bool find_match(struct spa_json *arr, const struct spa_dict *props)
6
-{
7
-   struct spa_json it[1];
8
-
9
-   while (spa_json_enter_object(arr, &it[0]) > 0) {
10
-       char key[256], val[1024];
11
-       const char *str, *value;
12
-       int match = 0, fail = 0;
13
-       int len;
14
-
15
-       while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
16
-           bool success = false;
17
-
18
-           if ((len = spa_json_next(&it[0], &value)) <= 0)
19
-               break;
20
-
21
-           str = spa_dict_lookup(props, key);
22
-
23
-           if (spa_json_is_null(value, len)) {
24
-               success = str == NULL;
25
-           } else {
26
-               if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
27
-                   continue;
28
-               value = val;
29
-               len = strlen(val);
30
-           }
31
-           if (str != NULL) {
32
-               if (value[0] == '~') {
33
-                   regex_t preg;
34
-                   if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
35
-                       if (regexec(&preg, str, 0, NULL, 0) == 0)
36
-                           success = true;
37
-                       regfree(&preg);
38
-                   }
39
-               } else if (strncmp(str, value, len) == 0 &&
40
-                   strlen(str) == (size_t)len) {
41
-                   success = true;
42
-               }
43
-           }
44
-           if (success) {
45
-               match++;
46
-               pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
47
-           }
48
-           else
49
-               fail++;
50
-       }
51
-       if (match > 0 && fail == 0)
52
-           return true;
53
-   }
54
-   return false;
55
-}
56
-
57
-static int pw_conf_match_rules(const char *rules, size_t size, const struct spa_dict *props,
58
-       int (*matched) (void *data, const char *action, const char *val, int len),
59
-       void *data)
60
-{
61
-   const char *val;
62
-   struct spa_json it[4], actions;
63
-   int count = 0;
64
-
65
-   spa_json_init(&it[0], rules, size);
66
-   if (spa_json_enter_array(&it[0], &it[1]) < 0)
67
-       return 0;
68
-
69
-   while (spa_json_enter_object(&it[1], &it[2]) > 0) {
70
-       char key[64];
71
-       bool have_match = false, have_actions = false;
72
-
73
-       while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
74
-           if (spa_streq(key, "matches")) {
75
-               if (spa_json_enter_array(&it[2], &it[3]) < 0)
76
-                   break;
77
-
78
-               have_match = find_match(&it[3], props);
79
-           }
80
-           else if (spa_streq(key, "actions")) {
81
-               if (spa_json_enter_object(&it[2], &actions) > 0)
82
-                   have_actions = true;
83
-           }
84
-           else if (spa_json_next(&it[2], &val) <= 0)
85
-                                break;
86
-       }
87
-       if (!have_match || !have_actions)
88
-           continue;
89
-
90
-       while (spa_json_get_string(&actions, key, sizeof(key)) > 0) {
91
-           int res, len;
92
-           pw_log_debug("action %s", key);
93
-
94
-           if ((len = spa_json_next(&actions, &val)) <= 0)
95
-               break;
96
-
97
-           if (spa_json_is_container(val, len))
98
-               len = spa_json_container_len(&actions, val, len);
99
-
100
-           if ((res = matched(data, key, val, len)) < 0)
101
-               return res;
102
-
103
-           count += res;
104
-       }
105
-   }
106
-   return count;
107
-}
108
-
109
-static int client_rule_matched(void *data, const char *action, const char *val, int len)
110
+static int apply_match(void *data, const char *location, const char *action,
111
+       const char *val, size_t len)
112
 {
113
    struct client *client = data;
114
 
115
@@ -170,19 +67,10 @@
116
    return 0;
117
 }
118
 
119
-static int apply_pulse_rules(void *data, const char *location, const char *section,
120
-       const char *str, size_t len)
121
-{
122
-   struct client *client = data;
123
-   pw_conf_match_rules(str, len, &client->props->dict,
124
-           client_rule_matched, client);
125
-   return 0;
126
-}
127
-
128
 int client_update_quirks(struct client *client)
129
 {
130
    struct impl *impl = client->impl;
131
    struct pw_context *context = impl->context;
132
-   return pw_context_conf_section_for_each(context, "pulse.rules",
133
-           apply_pulse_rules, client);
134
+   return pw_context_conf_section_match_rules(context, "pulse.rules",
135
+           &client->props->dict, apply_match, client);
136
 }
137
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/remap.c Added
58
 
1
@@ -0,0 +1,56 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2020 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <stddef.h>
27
+
28
+#include <pipewire/keys.h>
29
+
30
+#include "remap.h"
31
+
32
+const struct str_map media_role_map[] = {
33
+   { "Movie", "video", },
34
+   { "Music", "music", },
35
+   { "Game", "game", },
36
+   { "Notification", "event", },
37
+   { "Communication", "phone", },
38
+   { "Movie", "animation", },
39
+   { "Production", "production", },
40
+   { "Accessibility", "a11y", },
41
+   { "Test", "test", },
42
+   { NULL, NULL },
43
+};
44
+
45
+const struct str_map props_key_map[] = {
46
+   { PW_KEY_DEVICE_BUS_PATH, "device.bus_path" },
47
+   { PW_KEY_DEVICE_FORM_FACTOR, "device.form_factor" },
48
+   { PW_KEY_DEVICE_ICON_NAME, "device.icon_name" },
49
+   { PW_KEY_DEVICE_INTENDED_ROLES, "device.intended_roles" },
50
+   { PW_KEY_NODE_DESCRIPTION, "device.description" },
51
+   { PW_KEY_MEDIA_ICON_NAME, "media.icon_name" },
52
+   { PW_KEY_APP_ICON_NAME, "application.icon_name" },
53
+   { PW_KEY_APP_PROCESS_MACHINE_ID, "application.process.machine_id" },
54
+   { PW_KEY_APP_PROCESS_SESSION_ID, "application.process.session_id" },
55
+   { PW_KEY_MEDIA_ROLE, "media.role", media_role_map },
56
+   { NULL, NULL },
57
+};
58
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/remap.h Added
54
 
1
@@ -0,0 +1,52 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2020 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef PULSE_SERVER_REMAP_H
27
+#define PULSE_SERVER_REMAP_H
28
+
29
+#include <stddef.h>
30
+
31
+#include <spa/utils/string.h>
32
+
33
+struct str_map {
34
+   const char *pw_str;
35
+   const char *pa_str;
36
+   const struct str_map *child;
37
+};
38
+
39
+extern const struct str_map media_role_map[];
40
+
41
+extern const struct str_map props_key_map[];
42
+
43
+static inline const struct str_map *str_map_find(const struct str_map *map, const char *pw, const char *pa)
44
+{
45
+   size_t i;
46
+   for (i = 0; map[i].pw_str; i++)
47
+       if ((pw && spa_streq(map[i].pw_str, pw)) ||
48
+           (pa && spa_streq(map[i].pa_str, pa)))
49
+           return &map[i];
50
+   return NULL;
51
+}
52
+
53
+#endif /* PULSE_SERVER_REMAP_H */
54
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/sample-play.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/sample-play.c Changed
12
 
1
@@ -53,8 +53,8 @@
2
        sample_play_emit_done(p, -EIO);
3
        break;
4
    case PW_STREAM_STATE_PAUSED:
5
-       p->index = pw_stream_get_node_id(p->stream);
6
-       sample_play_emit_ready(p, p->index);
7
+       p->id = pw_stream_get_node_id(p->stream);
8
+       sample_play_emit_ready(p, p->id);
9
        break;
10
    default:
11
        break;
12
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/sample-play.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/sample-play.h Changed
10
 
1
@@ -56,7 +56,7 @@
2
    struct sample *sample;
3
    struct pw_stream *stream;
4
    struct spa_io_rate_match *rate_match;
5
-   uint32_t index;
6
+   uint32_t id;
7
    struct spa_hook listener;
8
    struct pw_context *context;
9
    struct pw_loop *main_loop;
10
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/server.c Changed
19
 
1
@@ -226,7 +226,8 @@
2
            if (errno == EINTR)
3
                continue;
4
            res = -errno;
5
-           if (res != -EAGAIN && res != -EWOULDBLOCK)
6
+           if (res != -EAGAIN && res != -EWOULDBLOCK &&
7
+               res != -EPIPE && res != -ECONNRESET)
8
                pw_log_warn("recv client:%p res %zd: %m", client, r);
9
            goto exit;
10
        }
11
@@ -327,6 +328,7 @@
12
 error:
13
    switch (res) {
14
    case -EPIPE:
15
+   case -ECONNRESET:
16
        pw_log_info("server %p: client %p [%s] disconnected",
17
                client->server, client, client->name);
18
        SPA_FALLTHROUGH;
19
pipewire-0.3.45.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-raop-sink.c Changed
21
 
1
@@ -93,6 +93,8 @@
2
 #define DEFAULT_CHANNELS "2"
3
 #define DEFAULT_POSITION "[ FL FR ]"
4
 
5
+#define DEFAULT_LATENCY (DEFAULT_RATE*2)
6
+
7
 #define MODULE_USAGE   "[ node.latency=<latency as fraction> ] "               \
8
            "[ node.name=<name of the nodes> ] "                    \
9
            "[ node.description=<description of the nodes> ] "          \
10
@@ -687,7 +689,9 @@
11
 
12
    if ((str = spa_dict_lookup(headers, "Audio-Latency")) != NULL) {
13
        if (!spa_atou32(str, &impl->latency, 0))
14
-           impl->latency = 0;
15
+           impl->latency = DEFAULT_LATENCY;
16
+   } else {
17
+       impl->latency = DEFAULT_LATENCY;
18
    }
19
 
20
    spa_zero(latency);
21
pipewire-0.3.45.tar.gz/src/pipewire/conf.c -> pipewire-0.3.47.tar.gz/src/pipewire/conf.c Changed
201
 
1
@@ -34,7 +34,8 @@
2
 #include <unistd.h>
3
 #include <sys/wait.h>
4
 #include <dirent.h>
5
-#if HAVE_PWD_H
6
+#include <regex.h>
7
+#ifdef HAVE_PWD_H
8
 #include <pwd.h>
9
 #endif
10
 #ifdef __FreeBSD__
11
@@ -733,6 +734,16 @@
12
    if (pid == 0) {
13
        char *cmd, **argv;
14
 
15
+       /* Double fork to avoid zombies; we don't want to set SIGCHLD handler */
16
+       pid = fork();
17
+
18
+       if (pid < 0) {
19
+           pw_log_error("fork error: %m");
20
+           exit(1);
21
+       } else if (pid != 0) {
22
+           exit(0);
23
+       }
24
+
25
        cmd = spa_aprintf("%s %s", key, args ? args : "");
26
        argv = pw_split_strv(cmd, " \t", INT_MAX, &n_args);
27
        free(cmd);
28
@@ -744,13 +755,18 @@
29
        if (res == -1) {
30
            res = -errno;
31
            pw_log_error("execvp error '%s': %m", key);
32
-           return res;
33
        }
34
-   }
35
-   else {
36
+
37
+       exit(1);
38
+   } else if (pid < 0) {
39
+       pw_log_error("fork error: %m");
40
+   } else {
41
        int status = 0;
42
-       res = waitpid(pid, &status, WNOHANG);
43
-       pw_log_info("exec got pid %d res:%d status:%d", pid, res, status);
44
+       do {
45
+           errno = 0;
46
+           res = waitpid(pid, &status, 0);
47
+       } while (res < 0 && errno == EINTR);
48
+       pw_log_debug("exec got pid %d res:%d status:%d", (int)pid, res, status);
49
    }
50
    return 0;
51
 }
52
@@ -810,6 +826,7 @@
53
    return res;
54
 }
55
 
56
+
57
 SPA_EXPORT
58
 int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
59
        int (*callback) (void *data, const char *location, const char *section,
60
@@ -819,7 +836,7 @@
61
    struct pw_properties *conf = context->conf;
62
    const char *path = NULL;
63
    const struct spa_dict_item *it;
64
-   int res;
65
+   int res = 0;
66
 
67
    spa_dict_for_each(it, &conf->dict) {
68
        if (spa_strendswith(it->key, "config.path")) {
69
@@ -882,3 +899,153 @@
70
                update_props, &data);
71
    return data.count;
72
 }
73
+
74
+struct match {
75
+   const struct spa_dict *props;
76
+   int (*matched) (void *data, const char *location, const char *action,
77
+           const char *val, size_t len);
78
+   void *data;
79
+};
80
+
81
+/*
82
+ * {
83
+ *     # all keys must match the value. ~ in value starts regex.
84
+ *     <key> = <value>
85
+ *     ...
86
+ * }
87
+ */
88
+static bool find_match(struct spa_json *arr, const struct spa_dict *props)
89
+{
90
+   struct spa_json it[1];
91
+
92
+   while (spa_json_enter_object(arr, &it[0]) > 0) {
93
+       char key[256], val[1024];
94
+       const char *str, *value;
95
+       int match = 0, fail = 0;
96
+       int len;
97
+
98
+       while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
99
+           bool success = false;
100
+
101
+           if ((len = spa_json_next(&it[0], &value)) <= 0)
102
+               break;
103
+
104
+           str = spa_dict_lookup(props, key);
105
+
106
+           if (spa_json_is_null(value, len)) {
107
+               success = str == NULL;
108
+           } else {
109
+               if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
110
+                   continue;
111
+               value = val;
112
+               len = strlen(val);
113
+           }
114
+           if (str != NULL) {
115
+               if (value[0] == '~') {
116
+                   regex_t preg;
117
+                   if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
118
+                       if (regexec(&preg, str, 0, NULL, 0) == 0)
119
+                           success = true;
120
+                       regfree(&preg);
121
+                   }
122
+               } else if (strncmp(str, value, len) == 0 &&
123
+                   strlen(str) == (size_t)len) {
124
+                   success = true;
125
+               }
126
+           }
127
+           if (success) {
128
+               match++;
129
+               pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
130
+           }
131
+           else
132
+               fail++;
133
+       }
134
+       if (match > 0 && fail == 0)
135
+           return true;
136
+   }
137
+   return false;
138
+}
139
+
140
+/**
141
+ * rules = [
142
+ *     {
143
+ *         matches = [
144
+ *             # any of the items in matches needs to match, it one does,
145
+ *             # actions are emited.
146
+ *             {
147
+ *                 # all keys must match the value. ~ in value starts regex.
148
+ *                 <key> = <value>
149
+ *                 ...
150
+ *             }
151
+ *             ...
152
+ *         ]
153
+ *         actions = {
154
+ *             <action> = <value>
155
+ *             ...
156
+ *         }
157
+ *     }
158
+ * ]
159
+ */
160
+static int match_rules(void *data, const char *location, const char *section,
161
+       const char *str, size_t len)
162
+{
163
+   struct match *match = data;
164
+   const struct spa_dict *props = match->props;
165
+   const char *val;
166
+   struct spa_json it[4], actions;
167
+
168
+   spa_json_init(&it[0], str, len);
169
+   if (spa_json_enter_array(&it[0], &it[1]) < 0)
170
+       return 0;
171
+
172
+   while (spa_json_enter_object(&it[1], &it[2]) > 0) {
173
+       char key[64];
174
+       bool have_match = false, have_actions = false;
175
+
176
+       while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
177
+           if (spa_streq(key, "matches")) {
178
+               if (spa_json_enter_array(&it[2], &it[3]) < 0)
179
+                   break;
180
+
181
+               have_match = find_match(&it[3], props);
182
+           }
183
+           else if (spa_streq(key, "actions")) {
184
+               if (spa_json_enter_object(&it[2], &actions) > 0)
185
+                   have_actions = true;
186
+           }
187
+           else if (spa_json_next(&it[2], &val) <= 0)
188
+                                break;
189
+       }
190
+       if (!have_match || !have_actions)
191
+           continue;
192
+
193
+       while (spa_json_get_string(&actions, key, sizeof(key)) > 0) {
194
+           int res, len;
195
+           pw_log_debug("action %s", key);
196
+
197
+           if ((len = spa_json_next(&actions, &val)) <= 0)
198
+               break;
199
+
200
+           if (spa_json_is_container(val, len))
201
pipewire-0.3.45.tar.gz/src/pipewire/context.c -> pipewire-0.3.47.tar.gz/src/pipewire/context.c Changed
36
 
1
@@ -1068,7 +1068,7 @@
2
    struct pw_impl_node *n, *s, *target, *fallback;
3
    uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum;
4
    uint32_t *rates, n_rates, def_rate;
5
-   bool freewheel = false, global_force_rate, force_rate, global_force_quantum;
6
+   bool freewheel = false, global_force_rate, force_rate, force_quantum, global_force_quantum;
7
 
8
    pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason);
9
 
10
@@ -1083,7 +1083,7 @@
11
    get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum);
12
    rates = get_rates(context, &def_rate, &n_rates, &global_force_rate);
13
 
14
-   global_force_quantum = rate_quantum == 0;
15
+   force_quantum = global_force_quantum = rate_quantum == 0;
16
    force_rate = global_force_rate;
17
 
18
    /* start from all drivers and group all nodes that are linked
19
@@ -1183,6 +1183,7 @@
20
                def_quantum = min_quantum = max_quantum = s->force_quantum;
21
                rate_quantum = 0;
22
                quantum_stamp = s->stamp;
23
+               force_quantum = true;
24
            }
25
            if (!global_force_rate && s->force_rate > 0 &&
26
                s->stamp > rate_stamp) {
27
@@ -1213,6 +1214,8 @@
28
                running = !n->passive;
29
        }
30
 
31
+       if (force_quantum)
32
+           lock_quantum = false;
33
        if (force_rate)
34
            lock_rate = false;
35
 
36
pipewire-0.3.45.tar.gz/src/pipewire/context.h -> pipewire-0.3.47.tar.gz/src/pipewire/context.h Changed
14
 
1
@@ -123,6 +123,12 @@
2
        int (*callback) (void *data, const char *location, const char *section,
3
            const char *str, size_t len),
4
        void *data);
5
+/** emit callback for all matched properties. Since 0.3.46 */
6
+int pw_context_conf_section_match_rules(struct pw_context *context, const char *section,
7
+       struct spa_dict *props,
8
+       int (*callback) (void *data, const char *location, const char *action,
9
+           const char *str, size_t len),
10
+       void *data);
11
 
12
 /** Get the context support objects */
13
 const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support);
14
pipewire-0.3.45.tar.gz/src/pipewire/filter.c -> pipewire-0.3.47.tar.gz/src/pipewire/filter.c Changed
99
 
1
@@ -50,7 +50,6 @@
2
 #define MAX_BUFFERS    64
3
 
4
 #define MASK_BUFFERS   (MAX_BUFFERS-1)
5
-#define MAX_PORTS  1024
6
 
7
 static bool mlock_warned = false;
8
 
9
@@ -142,7 +141,7 @@
10
    } rt;
11
 
12
    struct spa_list port_list;
13
-   struct port *ports[2][MAX_PORTS];
14
+   struct pw_map ports[2];
15
 
16
    uint32_t change_mask_all;
17
    struct spa_node_info info;
18
@@ -306,27 +305,17 @@
19
        enum spa_direction direction, uint32_t user_data_size)
20
 {
21
    struct port *p;
22
-   int i;
23
-
24
-   for (i = 0; i < MAX_PORTS; i++) {
25
-       if ((filter->ports[direction][i]) == NULL)
26
-           break;
27
-   }
28
-   if (i == MAX_PORTS)
29
-       return NULL;
30
 
31
    p = calloc(1, sizeof(struct port) + user_data_size);
32
    p->filter = filter;
33
    p->direction = direction;
34
-   p->id = i;
35
    p->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
36
    p->latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
37
 
38
    spa_list_init(&p->param_list);
39
    spa_ringbuffer_init(&p->dequeued.ring);
40
    spa_ringbuffer_init(&p->queued.ring);
41
-
42
-   filter->ports[direction][i] = p;
43
+   p->id = pw_map_insert_new(&filter->ports[direction], p);
44
    spa_list_append(&filter->port_list, &p->link);
45
 
46
    return p;
47
@@ -334,10 +323,9 @@
48
 
49
 static inline struct port *get_port(struct filter *filter, enum spa_direction direction, uint32_t port_id)
50
 {
51
-   if ((direction != SPA_DIRECTION_INPUT && direction != SPA_DIRECTION_OUTPUT) ||
52
-       port_id >= MAX_PORTS)
53
+   if ((direction != SPA_DIRECTION_INPUT && direction != SPA_DIRECTION_OUTPUT))
54
        return NULL;
55
-   return filter->ports[direction][port_id];
56
+   return pw_map_lookup(&filter->ports[direction], port_id);
57
 }
58
 
59
 static inline int push_queue(struct port *port, struct queue *queue, struct buffer *buffer)
60
@@ -1241,6 +1229,8 @@
61
 
62
    spa_list_init(&impl->param_list);
63
    spa_list_init(&impl->port_list);
64
+   pw_map_init(&impl->ports[SPA_DIRECTION_INPUT], 32, 32);
65
+   pw_map_init(&impl->ports[SPA_DIRECTION_OUTPUT], 32, 32);
66
 
67
    spa_hook_list_init(&this->listener_list);
68
    spa_list_init(&this->controls);
69
@@ -1377,6 +1367,9 @@
70
    spa_hook_list_clean(&impl->hooks);
71
    spa_hook_list_clean(&filter->listener_list);
72
 
73
+   pw_map_clear(&impl->ports[SPA_DIRECTION_INPUT]);
74
+   pw_map_clear(&impl->ports[SPA_DIRECTION_OUTPUT]);
75
+
76
    free(filter->name);
77
 
78
    if (impl->data.context)
79
@@ -1496,8 +1489,8 @@
80
        SPA_NODE_CHANGE_MASK_PARAMS;
81
 
82
    impl->info = SPA_NODE_INFO_INIT();
83
-   impl->info.max_input_ports = MAX_PORTS;
84
-   impl->info.max_output_ports = MAX_PORTS;
85
+   impl->info.max_input_ports = UINT32_MAX;
86
+   impl->info.max_output_ports = UINT32_MAX;
87
    impl->info.flags = impl->process_rt ? SPA_NODE_FLAG_RT : 0;
88
    impl->info.props = &filter->properties->dict;
89
    impl->params[IDX_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE);
90
@@ -1722,7 +1715,7 @@
91
    spa_node_emit_port_info(&impl->hooks, port->direction, port->id, NULL);
92
 
93
    spa_list_remove(&port->link);
94
-   impl->ports[port->direction][port->id] = NULL;
95
+   pw_map_remove(&impl->ports[port->direction], port->id);
96
 
97
    clear_buffers(port);
98
    clear_params(impl, port, SPA_ID_INVALID);
99
pipewire-0.3.45.tar.gz/src/pipewire/map.h -> pipewire-0.3.47.tar.gz/src/pipewire/map.h Changed
10
 
1
@@ -115,7 +115,7 @@
2
  */
3
 static inline void pw_map_init(struct pw_map *map, size_t size, size_t extend)
4
 {
5
-   pw_array_init(&map->items, extend);
6
+   pw_array_init(&map->items, extend * sizeof(union pw_map_item));
7
    pw_array_ensure_size(&map->items, size * sizeof(union pw_map_item));
8
    map->free_list = SPA_ID_INVALID;
9
 }
10
pipewire-0.3.45.tar.gz/src/pipewire/proxy.c -> pipewire-0.3.47.tar.gz/src/pipewire/proxy.c Changed
34
 
1
@@ -256,9 +256,6 @@
2
        pw_proxy_emit_destroy(proxy);
3
    }
4
 
5
-   spa_hook_list_clean(&proxy->listener_list);
6
-   spa_hook_list_clean(&proxy->object_listener_list);
7
-
8
    pw_proxy_unref(proxy);
9
 }
10
 
11
@@ -298,6 +295,22 @@
12
    pw_log_debug("%p: free %u", proxy, proxy->id);
13
    /** client must explicitly destroy all proxies */
14
    assert(proxy->destroyed);
15
+
16
+#if DEBUG_LISTENERS
17
+   {
18
+       struct spa_hook *h;
19
+       spa_list_for_each(h, &proxy->object_listener_list.list, link) {
20
+           pw_log_warn("%p: proxy %u: leaked object listener %p",
21
+                   proxy, proxy->id, h);
22
+           break;
23
+       }
24
+       spa_list_for_each(h, &proxy->listener_list.list, link) {
25
+           pw_log_warn("%p: proxy %u: leaked listener %p",
26
+                   proxy, proxy->id, h);
27
+           break;
28
+       }
29
+   }
30
+#endif
31
    free(proxy);
32
 }
33
 
34
pipewire-0.3.45.tar.gz/src/pipewire/stream.c -> pipewire-0.3.47.tar.gz/src/pipewire/stream.c Changed
9
 
1
@@ -48,7 +48,6 @@
2
 #define MAX_BUFFERS    64
3
 
4
 #define MASK_BUFFERS   (MAX_BUFFERS-1)
5
-#define MAX_PORTS  1
6
 
7
 static bool mlock_warned = false;
8
 
9
pipewire-0.3.45.tar.gz/src/pipewire/utils.c -> pipewire-0.3.47.tar.gz/src/pipewire/utils.c Changed
10
 
1
@@ -27,7 +27,7 @@
2
 #include <fcntl.h>
3
 #include <unistd.h>
4
 #include <errno.h>
5
-#if HAVE_SYS_RANDOM_H
6
+#ifdef HAVE_SYS_RANDOM_H
7
 #include <sys/random.h>
8
 #endif
9
 #include <string.h>
10
pipewire-0.3.45.tar.gz/src/tools/meson.build -> pipewire-0.3.47.tar.gz/src/tools/meson.build Changed
10
 
1
@@ -34,7 +34,7 @@
2
 endif
3
 
4
 build_pw_cat = false
5
-if not get_option('pw-cat').disabled() and sndfile_dep.found()
6
+if get_option('pw-cat').allowed() and sndfile_dep.found()
7
   build_pw_cat = true
8
 
9
   pwcat_sources = [
10
pipewire-0.3.45.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.47.tar.gz/src/tools/pw-cat.c Changed
53
 
1
@@ -648,7 +648,7 @@
2
    struct data *data = userdata;
3
 
4
    if (data->verbose)
5
-       fprintf(stdout, "remote %"PRIu32" is named \"%s\"\n",
6
+       printf("remote %"PRIu32" is named \"%s\"\n",
7
                info->id, info->name);
8
 }
9
 
10
@@ -808,7 +808,7 @@
11
                    id, type, name, media_class, desc ? : "", prio);
12
 
13
            spa_dict_for_each(item, props) {
14
-               fprintf(stdout, "\t\t%s = \"%s\"\n", item->key, item->value);
15
+               printf("\t\t%s = \"%s\"\n", item->key, item->value);
16
            }
17
        }
18
 
19
@@ -1533,7 +1533,7 @@
20
            return EXIT_SUCCESS;
21
 
22
        case OPT_VERSION:
23
-           fprintf(stdout, "%s\n"
24
+           printf("%s\n"
25
                "Compiled with libpipewire %s\n"
26
                "Linked with libpipewire %s\n",
27
                prog,
28
@@ -1930,14 +1930,21 @@
29
    }
30
 
31
 error_connect_fail:
32
-   if (data.stream)
33
+   if (data.stream) {
34
+       spa_hook_remove(&data.stream_listener);
35
        pw_stream_destroy(data.stream);
36
+   }
37
 error_no_stream:
38
-   if (data.metadata)
39
+   if (data.metadata) {
40
+       spa_hook_remove(&data.metadata_listener);
41
        pw_proxy_destroy((struct pw_proxy*)data.metadata);
42
-   if (data.registry)
43
+   }
44
+   if (data.registry) {
45
+       spa_hook_remove(&data.registry_listener);
46
        pw_proxy_destroy((struct pw_proxy*)data.registry);
47
+   }
48
 error_no_registry:
49
+   spa_hook_remove(&data.core_listener);
50
    pw_core_disconnect(data.core);
51
 error_ctx_connect_failed:
52
    pw_context_destroy(data.context);
53
pipewire-0.3.45.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.47.tar.gz/src/tools/pw-cli.c Changed
201
 
1
@@ -40,7 +40,7 @@
2
 #define FNM_EXTMATCH 0
3
 #endif
4
 
5
-#define spa_debug(...) fprintf(stdout,__VA_ARGS__);fputc('\n', stdout)
6
+#define spa_debug(fmt,...) printf(fmt, ## __VA_ARGS__)
7
 
8
 #include <spa/utils/result.h>
9
 #include <spa/utils/string.h>
10
@@ -157,15 +157,15 @@
11
    const struct spa_dict_item *item;
12
 
13
    if (header)
14
-       fprintf(stdout, "%c\tproperties:\n", mark);
15
+       printf("%c\tproperties:\n", mark);
16
    if (props == NULL || props->n_items == 0) {
17
        if (header)
18
-           fprintf(stdout, "\t\tnone\n");
19
+           printf("\t\tnone\n");
20
        return;
21
    }
22
 
23
    spa_dict_for_each(item, props) {
24
-       fprintf(stdout, "%c\t\t%s = \"%s\"\n", mark, item->key, item->value);
25
+       printf("%c\t\t%s = \"%s\"\n", mark, item->key, item->value);
26
    }
27
 }
28
 
29
@@ -174,16 +174,16 @@
30
    uint32_t i;
31
 
32
    if (header)
33
-       fprintf(stdout, "%c\tparams: (%u)\n", mark, n_params);
34
+       printf("%c\tparams: (%u)\n", mark, n_params);
35
    if (params == NULL || n_params == 0) {
36
        if (header)
37
-           fprintf(stdout, "\t\tnone\n");
38
+           printf("\t\tnone\n");
39
        return;
40
    }
41
    for (i = 0; i < n_params; i++) {
42
        const struct spa_type_info *type_info = spa_type_param;
43
 
44
-       fprintf(stdout, "%c\t  %d (%s) %c%c\n",
45
+       printf("%c\t  %d (%s) %c%c\n",
46
                params[i].user > 0 ? mark : ' ', params[i].id,
47
                spa_debug_type_find_name(type_info, params[i].id),
48
                params[i].flags & SPA_PARAM_INFO_READ ? 'r' : '-',
49
@@ -257,9 +257,9 @@
50
 {
51
    size_t i;
52
 
53
-   fprintf(stdout, "Available commands:\n");
54
+   printf("Available commands:\n");
55
    for (i = 0; i < SPA_N_ELEMENTS(command_list); i++) {
56
-       fprintf(stdout, "\t%-20.20s\t%s\n", command_list[i].name, command_list[i].description);
57
+       printf("\t%-20.20s\t%s\n", command_list[i].name, command_list[i].description);
58
    }
59
    return true;
60
 }
61
@@ -284,7 +284,7 @@
62
    }
63
 
64
    id = pw_map_insert_new(&data->vars, module);
65
-   fprintf(stdout, "%d = @module:%d\n", id, pw_global_get_id(pw_impl_module_get_global(module)));
66
+   printf("%d = @module:%d\n", id, pw_global_get_id(pw_impl_module_get_global(module)));
67
 
68
    return true;
69
 }
70
@@ -295,7 +295,7 @@
71
    free(rd->name);
72
    rd->name = info->name ? strdup(info->name) : NULL;
73
    if (rd->data->interactive)
74
-       fprintf(stdout, "remote %d is named '%s'\n", rd->id, rd->name);
75
+       printf("remote %d is named '%s'\n", rd->id, rd->name);
76
 }
77
 
78
 static void set_prompt(struct remote_data *rd)
79
@@ -353,7 +353,7 @@
80
    if (filter && !global_matches(global, filter))
81
        return 0;
82
 
83
-   fprintf(stdout, "\tid %d, type %s/%d\n", global->id,
84
+   printf("\tid %d, type %s/%d\n", global->id,
85
                    global->type, global->version);
86
    if (global->properties)
87
        print_properties(&global->properties->dict, ' ', false);
88
@@ -383,7 +383,7 @@
89
    global->properties = props ? pw_properties_new_dict(props) : NULL;
90
 
91
    if (rd->data->monitoring) {
92
-       fprintf(stdout, "remote %d added global: ", rd->id);
93
+       printf("remote %d added global: ", rd->id);
94
        print_global(global, NULL);
95
    }
96
 
97
@@ -396,7 +396,7 @@
98
    ret = bind_global(rd, global, &error);
99
    if (!ret) {
100
        if (rd->data->interactive)
101
-           fprintf(stdout, "Error: \"%s\"\n", error);
102
+           fprintf(stderr, "Error: \"%s\"\n", error);
103
        free(error);
104
    }
105
 }
106
@@ -424,12 +424,12 @@
107
 
108
    global = pw_map_lookup(&rd->globals, id);
109
    if (global == NULL) {
110
-       fprintf(stdout, "remote %d removed unknown global %d\n", rd->id, id);
111
+       fprintf(stderr, "remote %d removed unknown global %d\n", rd->id, id);
112
        return;
113
    }
114
 
115
    if (rd->data->monitoring) {
116
-       fprintf(stdout, "remote %d removed global: ", rd->id);
117
+       printf("remote %d removed global: ", rd->id);
118
        print_global(global, NULL);
119
    }
120
 
121
@@ -536,7 +536,7 @@
122
    spa_list_append(&data->remotes, &rd->link);
123
 
124
    if (rd->data->interactive)
125
-       fprintf(stdout, "%d = @remote:%p\n", rd->id, rd->core);
126
+       printf("%d = @remote:%p\n", rd->id, rd->core);
127
 
128
    data->current = rd;
129
 
130
@@ -592,7 +592,7 @@
131
    struct remote_data *rd;
132
 
133
    spa_list_for_each(rd, &data->remotes, link)
134
-       fprintf(stdout, "\t%d = @remote:%p '%s'\n", rd->id, rd->core, rd->name);
135
+       printf("\t%d = @remote:%p '%s'\n", rd->id, rd->core, rd->name);
136
 
137
    return true;
138
 }
139
@@ -631,10 +631,10 @@
140
    if (global == NULL)
141
        return;
142
 
143
-   fprintf(stdout, "\tid: %d\n", global->id);
144
-   fprintf(stdout, "\tpermissions: "PW_PERMISSION_FORMAT"\n",
145
+   printf("\tid: %d\n", global->id);
146
+   printf("\tpermissions: "PW_PERMISSION_FORMAT"\n",
147
            PW_PERMISSION_ARGS(global->permissions));
148
-   fprintf(stdout, "\ttype: %s/%d\n", global->type, global->version);
149
+   printf("\ttype: %s/%d\n", global->type, global->version);
150
 }
151
 
152
 static void info_core(struct proxy_data *pd)
153
@@ -642,11 +642,11 @@
154
    struct pw_core_info *info = pd->info;
155
 
156
    info_global(pd);
157
-   fprintf(stdout, "\tcookie: %u\n", info->cookie);
158
-   fprintf(stdout, "\tuser-name: \"%s\"\n", info->user_name);
159
-   fprintf(stdout, "\thost-name: \"%s\"\n", info->host_name);
160
-   fprintf(stdout, "\tversion: \"%s\"\n", info->version);
161
-   fprintf(stdout, "\tname: \"%s\"\n", info->name);
162
+   printf("\tcookie: %u\n", info->cookie);
163
+   printf("\tuser-name: \"%s\"\n", info->user_name);
164
+   printf("\thost-name: \"%s\"\n", info->host_name);
165
+   printf("\tversion: \"%s\"\n", info->version);
166
+   printf("\tname: \"%s\"\n", info->name);
167
    print_properties(info->props, MARK_CHANGE(PW_CORE_CHANGE_MASK_PROPS), true);
168
    info->change_mask = 0;
169
 }
170
@@ -656,9 +656,9 @@
171
    struct pw_module_info *info = pd->info;
172
 
173
    info_global(pd);
174
-   fprintf(stdout, "\tname: \"%s\"\n", info->name);
175
-   fprintf(stdout, "\tfilename: \"%s\"\n", info->filename);
176
-   fprintf(stdout, "\targs: \"%s\"\n", info->args);
177
+   printf("\tname: \"%s\"\n", info->name);
178
+   printf("\tfilename: \"%s\"\n", info->filename);
179
+   printf("\targs: \"%s\"\n", info->args);
180
    print_properties(info->props, MARK_CHANGE(PW_MODULE_CHANGE_MASK_PROPS), true);
181
    info->change_mask = 0;
182
 }
183
@@ -668,16 +668,16 @@
184
    struct pw_node_info *info = pd->info;
185
 
186
    info_global(pd);
187
-   fprintf(stdout, "%c\tinput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS),
188
+   printf("%c\tinput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS),
189
            info->n_input_ports, info->max_input_ports);
190
-   fprintf(stdout, "%c\toutput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS),
191
+   printf("%c\toutput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS),
192
            info->n_output_ports, info->max_output_ports);
193
-   fprintf(stdout, "%c\tstate: \"%s\"", MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE),
194
+   printf("%c\tstate: \"%s\"", MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE),
195
            pw_node_state_as_string(info->state));
196
    if (info->state == PW_NODE_STATE_ERROR && info->error)
197
-       fprintf(stdout, " \"%s\"\n", info->error);
198
+       printf(" \"%s\"\n", info->error);
199
    else
200
-       fprintf(stdout, "\n");
201
pipewire-0.3.45.tar.gz/src/tools/pw-dot.c -> pipewire-0.3.47.tar.gz/src/tools/pw-dot.c Changed
54
 
1
@@ -609,6 +609,8 @@
2
 static void destroy_proxy(void *user_data)
3
 {
4
    struct global *g = user_data;
5
+   spa_hook_remove(&g->object_listener);
6
+   spa_hook_remove(&g->proxy_listener);
7
    pw_properties_free(g->props);
8
    if (g->info)
9
        g->info_destroy(g->info);
10
@@ -760,9 +762,9 @@
11
    pw_main_loop_quit(d->loop);
12
 }
13
 
14
-static void show_help(const char *name)
15
+static void show_help(const char *name, bool error)
16
 {
17
-        fprintf(stdout, "%s [options]\n"
18
+        fprintf(error ? stderr : stdout, "%s [options]\n"
19
        "  -h, --help                            Show this help\n"
20
        "      --version                         Show version\n"
21
        "  -a, --all                             Show all object types\n"
22
@@ -801,10 +803,10 @@
23
    while ((c = getopt_long(argc, argv, "hVasdr:o:L9", long_options, NULL)) != -1) {
24
        switch (c) {
25
        case 'h' :
26
-           show_help(argv[0]);
27
+           show_help(argv[0], false);
28
            return 0;
29
        case 'V' :
30
-           fprintf(stdout, "%s\n"
31
+           printf("%s\n"
32
                "Compiled with libpipewire %s\n"
33
                "Linked with libpipewire %s\n",
34
                argv[0],
35
@@ -840,7 +842,7 @@
36
            fprintf(stderr, "orthogonal edges enabled\n");
37
            break;
38
        default:
39
-           show_help(argv[0]);
40
+           show_help(argv[0], true);
41
            return -1;
42
        }
43
    }
44
@@ -891,7 +893,9 @@
45
    draw_graph(&data, dot_path);
46
 
47
    dot_str_clear(&data.dot_str);
48
+   spa_hook_remove(&data.registry_listener);
49
    pw_proxy_destroy((struct pw_proxy*)data.registry);
50
+   spa_hook_remove(&data.core_listener);
51
    pw_context_destroy(data.context);
52
    pw_main_loop_destroy(data.loop);
53
    pw_deinit();
54
pipewire-0.3.45.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.47.tar.gz/src/tools/pw-dump.c Changed
57
 
1
@@ -1458,9 +1458,9 @@
2
    pw_main_loop_quit(d->loop);
3
 }
4
 
5
-static void show_help(struct data *data, const char *name)
6
+static void show_help(struct data *data, const char *name, bool error)
7
 {
8
-        fprintf(stdout, "%s [options] [<id>]\n"
9
+   fprintf(error ? stderr : stdout, "%s [options] [<id>]\n"
10
        "  -h, --help                            Show this help\n"
11
        "      --version                         Show version\n"
12
        "  -r, --remote                          Remote daemon name\n"
13
@@ -1492,14 +1492,15 @@
14
    data.out = stdout;
15
    if (isatty(fileno(data.out)) && getenv("NO_COLOR") == NULL)
16
        colors = true;
17
+   setlinebuf(data.out);
18
 
19
    while ((c = getopt_long(argc, argv, "hVr:mNC", long_options, NULL)) != -1) {
20
        switch (c) {
21
        case 'h' :
22
-           show_help(&data, argv[0]);
23
+           show_help(&data, argv[0], false);
24
            return 0;
25
        case 'V' :
26
-           fprintf(stdout, "%s\n"
27
+           printf("%s\n"
28
                "Compiled with libpipewire %s\n"
29
                "Linked with libpipewire %s\n",
30
                argv[0],
31
@@ -1524,12 +1525,13 @@
32
            else if (!strcmp(optarg, "always"))
33
                colors = true;
34
            else {
35
-               show_help(&data, argv[0]);
36
+               fprintf(stderr, "Unknown color: %s\n", optarg);
37
+               show_help(&data, argv[0], true);
38
                return -1;
39
            }
40
            break;
41
        default:
42
-           show_help(&data, argv[0]);
43
+           show_help(&data, argv[0], true);
44
            return -1;
45
        }
46
    }
47
@@ -1581,7 +1583,9 @@
48
    if (data.info)
49
        pw_core_info_free(data.info);
50
 
51
+   spa_hook_remove(&data.registry_listener);
52
    pw_proxy_destroy((struct pw_proxy*)data.registry);
53
+   spa_hook_remove(&data.core_listener);
54
    pw_context_destroy(data.context);
55
    pw_main_loop_destroy(data.loop);
56
    pw_deinit();
57
pipewire-0.3.45.tar.gz/src/tools/pw-link.c -> pipewire-0.3.47.tar.gz/src/tools/pw-link.c Changed
125
 
1
@@ -179,15 +179,15 @@
2
        prefix2 = "     ";
3
    }
4
 
5
-   fprintf(stdout, "%s%s%s%s\n", data->prefix, prefix,
6
+   printf("%s%s%s%s\n", data->prefix, prefix,
7
            id, port_name(buffer, sizeof(buffer), n, p));
8
    if (verbose) {
9
        port_path(buffer, sizeof(buffer), n, p);
10
        if (buffer[0] != '\0')
11
-           fprintf(stdout, "%s  %s%s%s\n", data->prefix, prefix2, prefix, buffer);
12
+           printf("%s  %s%s%s\n", data->prefix, prefix2, prefix, buffer);
13
        port_alias(buffer, sizeof(buffer), n, p);
14
        if (buffer[0] != '\0')
15
-           fprintf(stdout, "%s  %s%s%s\n", data->prefix, prefix2, prefix, buffer);
16
+           printf("%s  %s%s%s\n", data->prefix, prefix2, prefix, buffer);
17
    }
18
 }
19
 
20
@@ -426,7 +426,7 @@
21
    if (data->opt_id)
22
        snprintf(id, sizeof(id), "%4d ", link->id);
23
 
24
-   fprintf(stdout, "%s%s%s -> %s\n", data->prefix, id,
25
+   printf("%s%s%s -> %s\n", data->prefix, id,
26
            port_name(buffer1, sizeof(buffer1), n1, p1),
27
            port_name(buffer2, sizeof(buffer2), n2, p2));
28
    return 0;
29
@@ -552,9 +552,9 @@
30
    pw_main_loop_quit(data->loop);
31
 }
32
 
33
-static void show_help(struct data *data, const char *name)
34
+static void show_help(struct data *data, const char *name, bool error)
35
 {
36
-        fprintf(stdout, "%1$s : PipeWire port and link manager.\n"
37
+        fprintf(error ? stderr : stdout, "%1$s : PipeWire port and link manager.\n"
38
        "Generic: %1$s [options]\n"
39
        "  -h, --help                            Show this help\n"
40
        "      --version                         Show version\n"
41
@@ -563,11 +563,11 @@
42
        "  -o, --output                          List output ports\n"
43
        "  -i, --input                           List input ports\n"
44
        "  -l, --links                           List links\n"
45
-       "  -m, --monitor                         Monitor links\n"
46
+       "  -m, --monitor                         Monitor links and ports\n"
47
        "  -I, --id                              List IDs\n"
48
        "  -v, --verbose                         Verbose port properties\n"
49
        "Connect: %1$s [options] output input\n"
50
-       "  -L, --linger                          Linger (for use with -m)\n"
51
+       "  -L, --linger                          Linger (default, unless -m is used)\n"
52
        "  -P, --passive                         Passive link\n"
53
        "  -p, --props=PROPS                     Properties as JSON object\n"
54
        "Disconnect: %1$s -d [options] output input\n"
55
@@ -602,6 +602,8 @@
56
    pw_init(&argc, &argv);
57
    spa_list_init(&data.objects);
58
 
59
+   setlinebuf(stdout);
60
+
61
    data.props = pw_properties_new(NULL, NULL);
62
    if (data.props == NULL) {
63
        fprintf(stderr, "can't create properties: %m\n");
64
@@ -611,10 +613,10 @@
65
    while ((c = getopt_long(argc, argv, "hVr:oilmIvLPp:d", long_options, NULL)) != -1) {
66
        switch (c) {
67
        case 'h':
68
-           show_help(&data, argv[0]);
69
+           show_help(&data, argv[0], NULL);
70
            return 0;
71
        case 'V':
72
-           fprintf(stdout, "%s\n"
73
+           printf("%s\n"
74
                "Compiled with libpipewire %s\n"
75
                "Linked with libpipewire %s\n",
76
                argv[0],
77
@@ -655,12 +657,17 @@
78
            data.opt_mode |= MODE_DISCONNECT;
79
            break;
80
        default:
81
-           show_help(&data, argv[0]);
82
+           show_help(&data, argv[0], true);
83
            return -1;
84
        }
85
    }
86
    if (argc == 1)
87
-       show_help(&data, argv[0]);
88
+       show_help(&data, argv[0], true);
89
+
90
+   if (data.opt_id && (data.opt_mode & MODE_LIST) == 0) {
91
+       fprintf(stderr, "-I option needs one or more of -l, -i or -o\n");
92
+       return -1;
93
+   }
94
 
95
    if ((data.opt_mode & MODE_MONITOR) == 0)
96
        pw_properties_set(data.props, PW_KEY_OBJECT_LINGER, "true");
97
@@ -729,7 +736,7 @@
98
        do_list(&data);
99
    } else if (data.opt_mode & MODE_DISCONNECT) {
100
        if (data.opt_output == NULL) {
101
-           fprintf(stderr, "missing link-id or output and input port names\n");
102
+           fprintf(stderr, "missing link-id or output and input port names to disconnect\n");
103
            return -1;
104
        }
105
        if ((res = do_unlink_ports(&data)) < 0) {
106
@@ -739,7 +746,7 @@
107
    } else {
108
        if (data.opt_output == NULL ||
109
            data.opt_input == NULL) {
110
-           fprintf(stderr, "missing output and input port names\n");
111
+           fprintf(stderr, "missing output and input port names to connect\n");
112
            return -1;
113
        }
114
        if ((res = do_link_ports(&data)) < 0) {
115
@@ -758,7 +765,9 @@
116
        regfree(data.out_regex);
117
    if (data.in_regex)
118
        regfree(data.in_regex);
119
+   spa_hook_remove(&data.registry_listener);
120
    pw_proxy_destroy((struct pw_proxy*)data.registry);
121
+   spa_hook_remove(&data.core_listener);
122
    pw_core_disconnect(data.core);
123
    pw_context_destroy(data.context);
124
    pw_main_loop_destroy(data.loop);
125
pipewire-0.3.45.tar.gz/src/tools/pw-loopback.c -> pipewire-0.3.47.tar.gz/src/tools/pw-loopback.c Changed
35
 
1
@@ -80,9 +80,9 @@
2
 };
3
 
4
 
5
-static void show_help(struct data *data, const char *name)
6
+static void show_help(struct data *data, const char *name, bool error)
7
 {
8
-        fprintf(stdout, "%s [options]\n"
9
+        fprintf(error ? stderr : stdout, "%s [options]\n"
10
        "  -h, --help                            Show this help\n"
11
        "      --version                         Show version\n"
12
        "  -r, --remote                          Remote daemon name\n"
13
@@ -142,10 +142,10 @@
14
    while ((c = getopt_long(argc, argv, "hVr:g:c:m:l:C:P:i:o:", long_options, NULL)) != -1) {
15
        switch (c) {
16
        case 'h':
17
-           show_help(&data, argv[0]);
18
+           show_help(&data, argv[0], false);
19
            return 0;
20
        case 'V':
21
-           fprintf(stdout, "%s\n"
22
+           printf("%s\n"
23
                "Compiled with libpipewire %s\n"
24
                "Linked with libpipewire %s\n",
25
                argv[0],
26
@@ -180,7 +180,7 @@
27
            pw_properties_update_string(data.playback_props, optarg, strlen(optarg));
28
            break;
29
        default:
30
-           show_help(&data, argv[0]);
31
+           show_help(&data, argv[0], true);
32
            return -1;
33
        }
34
    }
35
pipewire-0.3.45.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.47.tar.gz/src/tools/pw-metadata.c Changed
98
 
1
@@ -70,11 +70,11 @@
2
    if ((d->opt_id == SPA_ID_INVALID || d->opt_id == id) &&
3
        (d->opt_key == NULL || spa_streq(d->opt_key, key))) {
4
        if (key == NULL) {
5
-           fprintf(stdout, "remove: id:%u all keys\n", id);
6
+           printf("remove: id:%u all keys\n", id);
7
        } else if (value == NULL) {
8
-           fprintf(stdout, "remove: id:%u key:'%s'\n", id, key);
9
+           printf("remove: id:%u key:'%s'\n", id, key);
10
        } else {
11
-           fprintf(stdout, "update: id:%u key:'%s' value:'%s' type:'%s'\n", id, key, value, type);
12
+           printf("update: id:%u key:'%s' value:'%s' type:'%s'\n", id, key, value, type);
13
        }
14
    }
15
 
16
@@ -106,23 +106,23 @@
17
        return;
18
    }
19
 
20
-   fprintf(stdout, "Found \"%s\" metadata %d\n", d->opt_name, id);
21
+   printf("Found \"%s\" metadata %d\n", d->opt_name, id);
22
    d->metadata = pw_registry_bind(d->registry,
23
            id, type, PW_VERSION_METADATA, 0);
24
 
25
    if (d->opt_delete) {
26
        if (d->opt_id != SPA_ID_INVALID) {
27
            if (d->opt_key != NULL)
28
-               fprintf(stdout, "delete property: id:%u key:%s\n", d->opt_id, d->opt_key);
29
+               printf("delete property: id:%u key:%s\n", d->opt_id, d->opt_key);
30
            else
31
-               fprintf(stdout, "delete properties: id:%u\n", d->opt_id);
32
+               printf("delete properties: id:%u\n", d->opt_id);
33
            pw_metadata_set_property(d->metadata, d->opt_id, d->opt_key, NULL, NULL);
34
        } else {
35
-           fprintf(stdout, "delete all properties\n");
36
+           printf("delete all properties\n");
37
            pw_metadata_clear(d->metadata);
38
        }
39
    } else if (d->opt_id != SPA_ID_INVALID && d->opt_key != NULL && d->opt_value != NULL) {
40
-       fprintf(stdout, "set property: id:%u key:%s value:%s type:%s\n",
41
+       printf("set property: id:%u key:%s value:%s type:%s\n",
42
                d->opt_id, d->opt_key, d->opt_value, d->opt_type);
43
        pw_metadata_set_property(d->metadata, d->opt_id, d->opt_key, d->opt_type, d->opt_value);
44
    } else {
45
@@ -170,9 +170,9 @@
46
    pw_main_loop_quit(data->loop);
47
 }
48
 
49
-static void show_help(struct data *data, const char *name)
50
+static void show_help(struct data *data, const char *name, bool error)
51
 {
52
-        fprintf(stdout, "%s [options] [ id [ key [ value [ type ] ] ] ]\n"
53
+        fprintf(error ? stderr : stdout, "%s [options] [ id [ key [ value [ type ] ] ] ]\n"
54
        "  -h, --help                            Show this help\n"
55
        "      --version                         Show version\n"
56
        "  -r, --remote                          Remote daemon name\n"
57
@@ -196,6 +196,8 @@
58
        { NULL, 0, NULL, 0}
59
    };
60
 
61
+   setlinebuf(stdout);
62
+
63
    pw_init(&argc, &argv);
64
 
65
    data.opt_name = "default";
66
@@ -203,10 +205,10 @@
67
    while ((c = getopt_long(argc, argv, "hVr:mdn:", long_options, NULL)) != -1) {
68
        switch (c) {
69
        case 'h':
70
-           show_help(&data, argv[0]);
71
+           show_help(&data, argv[0], false);
72
            return 0;
73
        case 'V':
74
-           fprintf(stdout, "%s\n"
75
+           printf("%s\n"
76
                "Compiled with libpipewire %s\n"
77
                "Linked with libpipewire %s\n",
78
                argv[0],
79
@@ -226,7 +228,7 @@
80
            data.opt_name = optarg;
81
            break;
82
        default:
83
-           show_help(&data, argv[0]);
84
+           show_help(&data, argv[0], true);
85
            return -1;
86
        }
87
    }
88
@@ -281,7 +283,9 @@
89
 
90
    if (data.metadata)
91
        pw_proxy_destroy((struct pw_proxy*)data.metadata);
92
+   spa_hook_remove(&data.registry_listener);
93
    pw_proxy_destroy((struct pw_proxy*)data.registry);
94
+   spa_hook_remove(&data.core_listener);
95
    pw_core_disconnect(data.core);
96
    pw_context_destroy(data.context);
97
    pw_main_loop_destroy(data.loop);
98
pipewire-0.3.45.tar.gz/src/tools/pw-mididump.c -> pipewire-0.3.47.tar.gz/src/tools/pw-mididump.c Changed
49
 
1
@@ -113,7 +113,7 @@
2
        ev.data = SPA_POD_BODY(&c->value),
3
        ev.size = SPA_POD_BODY_SIZE(&c->value);
4
 
5
-       fprintf(stdout, "%4d: ", c->offset);
6
+       printf("%4d: ", c->offset);
7
        midi_file_dump_event(stdout, &ev);
8
    }
9
 
10
@@ -175,9 +175,9 @@
11
    return 0;
12
 }
13
 
14
-static void show_help(const char *name)
15
+static void show_help(const char *name, bool error)
16
 {
17
-        fprintf(stdout, "%s [options] [FILE]\n"
18
+        fprintf(error ? stderr : stdout, "%s [options] [FILE]\n"
19
        "  -h, --help                            Show this help\n"
20
        "      --version                         Show version\n"
21
        "  -r, --remote                          Remote daemon name\n",
22
@@ -197,13 +197,15 @@
23
 
24
    pw_init(&argc, &argv);
25
 
26
+   setlinebuf(stdout);
27
+
28
    while ((c = getopt_long(argc, argv, "hVr:", long_options, NULL)) != -1) {
29
        switch (c) {
30
        case 'h':
31
-           show_help(argv[0]);
32
+           show_help(argv[0], false);
33
            return 0;
34
        case 'V':
35
-           fprintf(stdout, "%s\n"
36
+           printf("%s\n"
37
                "Compiled with libpipewire %s\n"
38
                "Linked with libpipewire %s\n",
39
                argv[0],
40
@@ -214,7 +216,7 @@
41
            data.opt_remote = optarg;
42
            break;
43
        default:
44
-           show_help(argv[0]);
45
+           show_help(argv[0], true);
46
            return -1;
47
        }
48
    }
49
pipewire-0.3.45.tar.gz/src/tools/pw-mon.c -> pipewire-0.3.47.tar.gz/src/tools/pw-mon.c Changed
201
 
1
@@ -48,10 +48,10 @@
2
    { .prefix = "*", .suffix = "" },
3
 };
4
 
5
-#define with_prefix(use_prefix_, stream_) \
6
-   for (bool once_ = !!fprintf(stream_, "%s", (pprefix[!!(use_prefix_)]).prefix); \
7
+#define with_prefix(use_prefix_) \
8
+   for (bool once_ = !!printf("%s", (pprefix[!!(use_prefix_)]).prefix); \
9
    once_; \
10
-   once_ = false, fprintf(stream_, "%s", (pprefix[!!(use_prefix_)]).suffix))
11
+   once_ = false, printf("%s", (pprefix[!!(use_prefix_)]).suffix))
12
 
13
 
14
 struct param {
15
@@ -175,13 +175,13 @@
16
 {
17
    struct param *p;
18
 
19
-   with_prefix(use_prefix, stderr) {
20
-       fprintf(stderr, "\tparams:\n");
21
+   with_prefix(use_prefix) {
22
+       printf("\tparams:\n");
23
    }
24
 
25
    spa_list_for_each(p, &data->param_list, link) {
26
-       with_prefix(p->changed, stderr) {
27
-           fprintf(stderr, "\t  id:%u (%s)\n",
28
+       with_prefix(p->changed) {
29
+           printf("\t  id:%u (%s)\n",
30
                p->id,
31
                spa_debug_type_find_name(spa_type_param, p->id));
32
            if (spa_pod_is_object_type(p->param, SPA_TYPE_OBJECT_Format))
33
@@ -197,20 +197,20 @@
34
 {
35
    const struct spa_dict_item *item;
36
 
37
-   with_prefix(use_prefix, stderr) {
38
-       fprintf(stderr, "\tproperties:\n");
39
+   with_prefix(use_prefix) {
40
+       printf("\tproperties:\n");
41
        if (props == NULL || props->n_items == 0) {
42
-           fprintf(stderr, "\t\tnone\n");
43
+           printf("\t\tnone\n");
44
            return;
45
        }
46
    }
47
 
48
    spa_dict_for_each(item, props) {
49
-       with_prefix(use_prefix, stderr) {
50
+       with_prefix(use_prefix) {
51
            if (item->value)
52
-               fprintf(stderr, "\t\t%s = \"%s\"\n", item->key, item->value);
53
+               printf("\t\t%s = \"%s\"\n", item->key, item->value);
54
            else
55
-               fprintf(stderr, "\t\t%s = (null)\n", item->key);
56
+               printf("\t\t%s = (null)\n", item->key);
57
        }
58
    }
59
 }
60
@@ -221,12 +221,12 @@
61
 {
62
    bool print_all = true, print_mark = true;
63
 
64
-   fprintf(stderr, "\ttype: %s\n", PW_TYPE_INTERFACE_Core);
65
-   fprintf(stderr, "\tcookie: %u\n", info->cookie);
66
-   fprintf(stderr, "\tuser-name: \"%s\"\n", info->user_name);
67
-   fprintf(stderr, "\thost-name: \"%s\"\n", info->host_name);
68
-   fprintf(stderr, "\tversion: \"%s\"\n", info->version);
69
-   fprintf(stderr, "\tname: \"%s\"\n", info->name);
70
+   printf("\ttype: %s\n", PW_TYPE_INTERFACE_Core);
71
+   printf("\tcookie: %u\n", info->cookie);
72
+   printf("\tuser-name: \"%s\"\n", info->user_name);
73
+   printf("\thost-name: \"%s\"\n", info->host_name);
74
+   printf("\tversion: \"%s\"\n", info->version);
75
+   printf("\tname: \"%s\"\n", info->name);
76
    if (print_all) {
77
        print_properties(info->props, MARK_CHANGE(PW_CORE_CHANGE_MASK_PROPS));
78
    }
79
@@ -239,23 +239,23 @@
80
 
81
    print_all = true;
82
         if (data->info == NULL) {
83
-       fprintf(stderr, "added:\n");
84
+       printf("added:\n");
85
        print_mark = false;
86
    }
87
         else {
88
-       fprintf(stderr, "changed:\n");
89
+       printf("changed:\n");
90
        print_mark = true;
91
    }
92
 
93
    info = data->info = pw_module_info_update(data->info, info);
94
 
95
-   fprintf(stderr, "\tid: %d\n", data->id);
96
-   fprintf(stderr, "\tpermissions: "PW_PERMISSION_FORMAT"\n",
97
+   printf("\tid: %d\n", data->id);
98
+   printf("\tpermissions: "PW_PERMISSION_FORMAT"\n",
99
            PW_PERMISSION_ARGS(data->permissions));
100
-   fprintf(stderr, "\ttype: %s (version %d)\n", data->type, data->version);
101
-   fprintf(stderr, "\tname: \"%s\"\n", info->name);
102
-   fprintf(stderr, "\tfilename: \"%s\"\n", info->filename);
103
-   fprintf(stderr, "\targs: \"%s\"\n", info->args);
104
+   printf("\ttype: %s (version %d)\n", data->type, data->version);
105
+   printf("\tname: \"%s\"\n", info->name);
106
+   printf("\tfilename: \"%s\"\n", info->filename);
107
+   printf("\targs: \"%s\"\n", info->args);
108
    if (print_all) {
109
        print_properties(info->props, MARK_CHANGE(PW_MODULE_CHANGE_MASK_PROPS));
110
    }
111
@@ -273,37 +273,37 @@
112
 
113
    print_all = true;
114
         if (data->first) {
115
-       fprintf(stderr, "added:\n");
116
+       printf("added:\n");
117
        print_mark = false;
118
        data->first = false;
119
    }
120
         else {
121
-       fprintf(stderr, "changed:\n");
122
+       printf("changed:\n");
123
        print_mark = true;
124
    }
125
 
126
-   fprintf(stderr, "\tid: %d\n", data->id);
127
-   fprintf(stderr, "\tpermissions: "PW_PERMISSION_FORMAT"\n",
128
+   printf("\tid: %d\n", data->id);
129
+   printf("\tpermissions: "PW_PERMISSION_FORMAT"\n",
130
            PW_PERMISSION_ARGS(data->permissions));
131
-   fprintf(stderr, "\ttype: %s (version %d)\n", data->type, data->version);
132
+   printf("\ttype: %s (version %d)\n", data->type, data->version);
133
    if (print_all) {
134
        print_params(data, MARK_CHANGE(PW_NODE_CHANGE_MASK_PARAMS));
135
-       with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS), stderr) {
136
-           fprintf(stderr, "\tinput ports: %u/%u\n",
137
+       with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS)) {
138
+           printf("\tinput ports: %u/%u\n",
139
                info->n_input_ports, info->max_input_ports);
140
        }
141
-       with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS), stderr) {
142
-           fprintf(stderr, "\toutput ports: %u/%u\n",
143
+       with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS)) {
144
+           printf("\toutput ports: %u/%u\n",
145
                info->n_output_ports, info->max_output_ports);
146
        }
147
-       with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE), stderr) {
148
-           fprintf(stderr, "\tstate: \"%s\"",
149
+       with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE)) {
150
+           printf("\tstate: \"%s\"",
151
                pw_node_state_as_string(info->state));
152
        }
153
        if (info->state == PW_NODE_STATE_ERROR && info->error)
154
-           fprintf(stderr, " \"%s\"\n", info->error);
155
+           printf(" \"%s\"\n", info->error);
156
        else
157
-           fprintf(stderr, "\n");
158
+           printf("\n");
159
        print_properties(info->props, MARK_CHANGE(PW_NODE_CHANGE_MASK_PROPS));
160
    }
161
 }
162
@@ -346,21 +346,21 @@
163
 
164
    print_all = true;
165
         if (data->first) {
166
-       fprintf(stderr, "added:\n");
167
+       printf("added:\n");
168
        print_mark = false;
169
        data->first = false;
170
    }
171
         else {
172
-       fprintf(stderr, "changed:\n");
173
+       printf("changed:\n");
174
        print_mark = true;
175
    }
176
 
177
-   fprintf(stderr, "\tid: %d\n", data->id);
178
-   fprintf(stderr, "\tpermissions: "PW_PERMISSION_FORMAT"\n",
179
+   printf("\tid: %d\n", data->id);
180
+   printf("\tpermissions: "PW_PERMISSION_FORMAT"\n",
181
            PW_PERMISSION_ARGS(data->permissions));
182
-   fprintf(stderr, "\ttype: %s (version %d)\n", data->type, data->version);
183
+   printf("\ttype: %s (version %d)\n", data->type, data->version);
184
 
185
-   fprintf(stderr, "\tdirection: \"%s\"\n", pw_direction_as_string(info->direction));
186
+   printf("\tdirection: \"%s\"\n", pw_direction_as_string(info->direction));
187
    if (print_all) {
188
        print_params(data, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS));
189
        print_properties(info->props, MARK_CHANGE(PW_PORT_CHANGE_MASK_PROPS));
190
@@ -405,23 +405,23 @@
191
 
192
    print_all = true;
193
         if (data->info == NULL) {
194
-       fprintf(stderr, "added:\n");
195
+       printf("added:\n");
196
        print_mark = false;
197
    }
198
         else {
199
-       fprintf(stderr, "changed:\n");
200
+       printf("changed:\n");
201
pipewire-0.3.45.tar.gz/src/tools/pw-profiler.c -> pipewire-0.3.47.tar.gz/src/tools/pw-profiler.c Changed
113
 
1
@@ -131,7 +131,7 @@
2
 
3
    if (d->driver_id == 0) {
4
        d->driver_id = driver_id;
5
-       fprintf(stderr, "logging driver %u\n", driver_id);
6
+       printf("logging driver %u\n", driver_id);
7
    }
8
    else if (d->driver_id != driver_id)
9
        return -1;
10
@@ -162,7 +162,7 @@
11
    strncpy(d->followers[idx].name, name, MAX_NAME);
12
    d->followers[idx].name[MAX_NAME-1] = '\0';
13
    d->followers[idx].id = id;
14
-   fprintf(stderr, "logging follower %u (\"%s\")\n", id, name);
15
+   printf("logging follower %u (\"%s\")\n", id, name);
16
 
17
    return idx;
18
 }
19
@@ -243,7 +243,7 @@
20
        d->last_status = point->clock.nsec;
21
    }
22
    else if (point->clock.nsec - d->last_status > SPA_NSEC_PER_SEC) {
23
-       fprintf(stderr, "logging %"PRIi64" samples  %"PRIi64" seconds [CPU %f %f %f]\r",
24
+       printf("logging %"PRIi64" samples  %"PRIi64" seconds [CPU %f %f %f]\r",
25
                d->count, (int64_t) ((d->last_status - d->start_status) / SPA_NSEC_PER_SEC),
26
                point->cpu_load[0], point->cpu_load[1], point->cpu_load[2]);
27
        d->last_status = point->clock.nsec;
28
@@ -259,7 +259,7 @@
29
    if (d->driver_id == 0)
30
        return;
31
 
32
-   fprintf(stderr, "\ndumping scripts for %d followers\n", d->n_followers);
33
+   printf("\ndumping scripts for %d followers\n", d->n_followers);
34
 
35
    out = fopen("Timing1.plot", "w");
36
    if (out == NULL) {
37
@@ -420,7 +420,7 @@
38
            "gnuplot Timing5.plot\n");
39
        fclose(out);
40
    }
41
-   fprintf(stderr, "run 'sh generate_timings.sh' and load Timings.html in a browser\n");
42
+   printf("run 'sh generate_timings.sh' and load Timings.html in a browser\n");
43
 }
44
 
45
 static void profiler_profile(void *data, const struct spa_pod *pod)
46
@@ -487,7 +487,7 @@
47
    if (proxy == NULL)
48
        goto error_proxy;
49
 
50
-   fprintf(stderr, "Attaching to Profiler id:%d\n", id);
51
+   printf("Attaching to Profiler id:%d\n", id);
52
    d->profiler = proxy;
53
    pw_proxy_add_object_listener(proxy, &d->profiler_listener, &profiler_events, d);
54
 
55
@@ -539,9 +539,9 @@
56
    pw_main_loop_quit(d->loop);
57
 }
58
 
59
-static void show_help(const char *name)
60
+static void show_help(const char *name, bool error)
61
 {
62
-        fprintf(stdout, "%s [options]\n"
63
+        fprintf(error ? stderr : stdout, "%s [options]\n"
64
        "  -h, --help                            Show this help\n"
65
        "      --version                         Show version\n"
66
        "  -r, --remote                          Remote daemon name\n"
67
@@ -570,10 +570,10 @@
68
    while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) {
69
        switch (c) {
70
        case 'h':
71
-           show_help(argv[0]);
72
+           show_help(argv[0], false);
73
            return 0;
74
        case 'V':
75
-           fprintf(stdout, "%s\n"
76
+           printf("%s\n"
77
                "Compiled with libpipewire %s\n"
78
                "Linked with libpipewire %s\n",
79
                argv[0],
80
@@ -587,7 +587,7 @@
81
            opt_remote = optarg;
82
            break;
83
        default:
84
-           show_help(argv[0]);
85
+           show_help(argv[0], true);
86
            return -1;
87
        }
88
    }
89
@@ -628,7 +628,7 @@
90
        return -1;
91
    }
92
 
93
-   fprintf(stderr, "Logging to %s\n", data.filename);
94
+   printf("Logging to %s\n", data.filename);
95
 
96
    pw_core_add_listener(data.core,
97
                   &data.core_listener,
98
@@ -643,8 +643,13 @@
99
 
100
    pw_main_loop_run(data.loop);
101
 
102
-   pw_proxy_destroy((struct pw_proxy*)data.profiler);
103
+   if (data.profiler) {
104
+       spa_hook_remove(&data.profiler_listener);
105
+       pw_proxy_destroy((struct pw_proxy*)data.profiler);
106
+   }
107
+   spa_hook_remove(&data.registry_listener);
108
    pw_proxy_destroy((struct pw_proxy*)data.registry);
109
+   spa_hook_remove(&data.core_listener);
110
    pw_context_destroy(data.context);
111
    pw_main_loop_destroy(data.loop);
112
 
113
pipewire-0.3.45.tar.gz/src/tools/pw-reserve.c -> pipewire-0.3.47.tar.gz/src/tools/pw-reserve.c Changed
71
 
1
@@ -50,24 +50,24 @@
2
 
3
 static void reserve_acquired(void *data, struct rd_device *d)
4
 {
5
-   fprintf(stdout, "reserve acquired\n");
6
+   printf("reserve acquired\n");
7
 }
8
 
9
 static void reserve_release(void *data, struct rd_device *d, int forced)
10
 {
11
    struct impl *impl = data;
12
-   fprintf(stdout, "reserve release\n");
13
+   printf("reserve release\n");
14
    rd_device_complete_release(impl->device, true);
15
 }
16
 
17
 static void reserve_busy(void *data, struct rd_device *d, const char *name, int32_t prio)
18
 {
19
-   fprintf(stdout, "reserve busy %s, prio %d\n", name, prio);
20
+   printf("reserve busy %s, prio %d\n", name, prio);
21
 }
22
 
23
 static void reserve_available(void *data, struct rd_device *d, const char *name)
24
 {
25
-   fprintf(stdout, "reserve available %s\n", name);
26
+   printf("reserve available %s\n", name);
27
 }
28
 
29
 static const struct rd_device_callbacks reserve_callbacks = {
30
@@ -86,9 +86,9 @@
31
 #define DEFAULT_APPNAME        "pw-reserve"
32
 #define DEFAULT_PRIORITY   0
33
 
34
-static void show_help(const char *name)
35
+static void show_help(const char *name, bool error)
36
 {
37
-        fprintf(stdout, "%s [options]\n"
38
+        fprintf(error ? stderr : stdout, "%s [options]\n"
39
              "  -h, --help                            Show this help\n"
40
              "      --version                         Show version\n"
41
              "  -n, --name                            Name to reserve (Audio0, Midi0, Video0, ..)\n"
42
@@ -119,15 +119,17 @@
43
        { NULL, 0, NULL, 0}
44
    };
45
 
46
+   setlinebuf(stdout);
47
+
48
    pw_init(&argc, &argv);
49
 
50
    while ((c = getopt_long(argc, argv, "hVn:a:p:m", long_options, NULL)) != -1) {
51
        switch (c) {
52
        case 'h':
53
-           show_help(argv[0]);
54
+           show_help(argv[0], false);
55
            return 0;
56
        case 'V':
57
-           fprintf(stdout, "%s\n"
58
+           printf("%s\n"
59
                "Compiled with libpipewire %s\n"
60
                "Linked with libpipewire %s\n",
61
                argv[0],
62
@@ -147,7 +149,7 @@
63
            opt_monitor = true;
64
            break;
65
        default:
66
-           fprintf(stderr, "invalid option '%c'\n", c);
67
+           show_help(argv[0], true);
68
            return -1;
69
        }
70
    }
71
pipewire-0.3.45.tar.gz/src/tools/pw-top.c -> pipewire-0.3.47.tar.gz/src/tools/pw-top.c Changed
59
 
1
@@ -374,7 +374,7 @@
2
        }
3
    } else if (spa_streq(type, PW_TYPE_INTERFACE_Profiler)) {
4
        if (d->profiler != NULL) {
5
-           fprintf(stderr, "Ignoring profiler %d: already attached\n", id);
6
+           printf("Ignoring profiler %d: already attached\n", id);
7
            return;
8
        }
9
 
10
@@ -443,9 +443,9 @@
11
    pw_main_loop_quit(d->loop);
12
 }
13
 
14
-static void show_help(const char *name)
15
+static void show_help(const char *name, bool error)
16
 {
17
-        fprintf(stdout, "%s [options]\n"
18
+        fprintf(error ? stderr : stdout, "%s [options]\n"
19
        "  -h, --help                            Show this help\n"
20
        "      --version                         Show version\n"
21
        "  -r, --remote                          Remote daemon name\n",
22
@@ -506,10 +506,10 @@
23
    while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) {
24
        switch (c) {
25
        case 'h':
26
-           show_help(argv[0]);
27
+           show_help(argv[0], false);
28
            return 0;
29
        case 'V':
30
-           fprintf(stdout, "%s\n"
31
+           printf("%s\n"
32
                "Compiled with libpipewire %s\n"
33
                "Linked with libpipewire %s\n",
34
                argv[0],
35
@@ -520,7 +520,7 @@
36
            opt_remote = optarg;
37
            break;
38
        default:
39
-           show_help(argv[0]);
40
+           show_help(argv[0], true);
41
            return -1;
42
        }
43
    }
44
@@ -584,8 +584,13 @@
45
    spa_list_consume(n, &data.node_list, link)
46
        remove_node(&data, n);
47
 
48
-   pw_proxy_destroy((struct pw_proxy*)data.profiler);
49
+   if (data.profiler) {
50
+       spa_hook_remove(&data.profiler_listener);
51
+       pw_proxy_destroy((struct pw_proxy*)data.profiler);
52
+   }
53
+   spa_hook_remove(&data.registry_listener);
54
    pw_proxy_destroy((struct pw_proxy*)data.registry);
55
+   spa_hook_remove(&data.core_listener);
56
    pw_context_destroy(data.context);
57
    pw_main_loop_destroy(data.loop);
58
 
59
pipewire-0.3.45.tar.gz/test/meson.build -> pipewire-0.3.47.tar.gz/test/meson.build Changed
16
 
1
@@ -75,6 +75,14 @@
2
                link_with: pwtest_lib)
3
 )
4
 
5
+test('test-loop',
6
+    executable('test-loop',
7
+               'test-loop.c',
8
+               include_directories: pwtest_inc,
9
+               dependencies: [ spa_dep ],
10
+               link_with: pwtest_lib)
11
+)
12
+
13
 test('test-context',
14
     executable('test-context',
15
                'test-context.c',
16
pipewire-0.3.45.tar.gz/test/pwtest-compat.c -> pipewire-0.3.47.tar.gz/test/pwtest-compat.c Changed
10
 
1
@@ -24,7 +24,7 @@
2
 
3
 #include "config.h"
4
 
5
-#if !HAVE_SIGABBREV_NP
6
+#ifndef HAVE_SIGABBREV_NP
7
 #include <stddef.h>
8
 #include <signal.h>
9
 
10
pipewire-0.3.45.tar.gz/test/pwtest.c -> pipewire-0.3.47.tar.gz/test/pwtest.c Changed
74
 
1
@@ -36,10 +36,10 @@
2
 #include <stdio.h>
3
 #include <unistd.h>
4
 #include <signal.h>
5
-#if HAVE_PIDFD_OPEN
6
+#ifdef HAVE_PIDFD_OPEN
7
 #include <sys/syscall.h>
8
 #endif
9
-#if HAVE_LIBCAP
10
+#ifdef HAVE_LIBCAP
11
 #include <sys/capability.h>
12
 #endif
13
 #include <sys/epoll.h>
14
@@ -177,7 +177,7 @@
15
 
16
 static void pwtest_backtrace(pid_t p)
17
 {
18
-#if HAVE_GSTACK
19
+#ifdef HAVE_GSTACK
20
    char pid[11];
21
    pid_t parent, child;
22
    int status;
23
@@ -305,12 +305,14 @@
24
    struct spa_handle **hnd;
25
 
26
    SPA_FOR_EACH_ELEMENT(plugin->handles, hnd) {
27
-       if (*hnd)
28
+       if (*hnd) {
29
+           spa_handle_clear(*hnd);
30
            free(*hnd);
31
+       }
32
    }
33
    SPA_FOR_EACH_ELEMENT(plugin->dlls, dll) {
34
        if (*dll)
35
-           dlclose(dll);
36
+           dlclose(*dll);
37
    }
38
    free(plugin);
39
 }
40
@@ -362,12 +364,13 @@
41
    r = spa_handle_factory_init(factory, handle, info, plugin->support, plugin->nsupport);
42
    pwtest_neg_errno_ok(r);
43
    if ((r = spa_handle_get_interface(handle, interface_name, &iface)) != 0) {
44
-       dlclose(hnd);
45
+       spa_handle_clear(handle);
46
        free(handle);
47
+       dlclose(hnd);
48
        return -ENOSYS;
49
    }
50
 
51
-   plugin->handles[plugin->ndlls++] = hnd;
52
+   plugin->dlls[plugin->ndlls++] = hnd;
53
    plugin->handles[plugin->nhandles++] = handle;
54
    plugin->support[plugin->nsupport++] = SPA_SUPPORT_INIT(interface_name, iface);
55
 
56
@@ -820,7 +823,7 @@
57
    size_t nevents = 0;
58
    int r;
59
 
60
-#if HAVE_PIDFD_OPEN
61
+#ifdef HAVE_PIDFD_OPEN
62
    pidfd = syscall(SYS_pidfd_open, pid, 0);
63
 #else
64
    errno = ENOSYS;
65
@@ -1168,7 +1171,7 @@
66
 static bool is_debugger_attached(void)
67
 {
68
    bool rc = false;
69
-#if HAVE_LIBCAP
70
+#ifdef HAVE_LIBCAP
71
    int status;
72
    int pid = fork();
73
 
74
pipewire-0.3.45.tar.gz/test/test-context.c -> pipewire-0.3.47.tar.gz/test/test-context.c Changed
10
 
1
@@ -233,7 +233,7 @@
2
        SPA_TYPE_INTERFACE_Loop,
3
        SPA_TYPE_INTERFACE_LoopUtils,
4
        SPA_TYPE_INTERFACE_Log,
5
-#if HAVE_DBUS
6
+#ifdef HAVE_DBUS
7
        SPA_TYPE_INTERFACE_DBus,
8
 #endif
9
        SPA_TYPE_INTERFACE_CPU
10
pipewire-0.3.45.tar.gz/test/test-lib.c -> pipewire-0.3.47.tar.gz/test/test-lib.c Changed
10
 
1
@@ -44,6 +44,8 @@
2
    pwtest_str_eq(headerversion, version_expected);
3
    pwtest_str_eq(libversion, version_expected);
4
 
5
+   pw_deinit();
6
+
7
    return PWTEST_PASS;
8
 }
9
 
10
pipewire-0.3.47.tar.gz/test/test-loop.c Added
201
 
1
@@ -0,0 +1,237 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <stdio.h>
27
+#include <stdint.h>
28
+#include <stdlib.h>
29
+#include <unistd.h>
30
+#include <sys/eventfd.h>
31
+
32
+#include "pwtest.h"
33
+
34
+#include <pipewire/pipewire.h>
35
+
36
+struct obj {
37
+   int x;
38
+   struct spa_source source;
39
+};
40
+
41
+struct data {
42
+   struct pw_main_loop *ml;
43
+   struct pw_loop *l;
44
+   struct obj *a, *b;
45
+   int count;
46
+};
47
+
48
+static void on_event(struct spa_source *source)
49
+{
50
+   struct data *d = source->data;
51
+
52
+   pw_loop_remove_source(d->l, &d->a->source);
53
+   pw_loop_remove_source(d->l, &d->b->source);
54
+   close(d->a->source.fd);
55
+   close(d->b->source.fd);
56
+   free(d->a);
57
+   free(d->b);
58
+
59
+   pw_main_loop_quit(d->ml);
60
+}
61
+
62
+PWTEST(pwtest_loop_destroy2)
63
+{
64
+   struct data data;
65
+
66
+   pw_init(0, NULL);
67
+
68
+   spa_zero(data);
69
+   data.ml = pw_main_loop_new(NULL);
70
+   pwtest_ptr_notnull(data.ml);
71
+
72
+   data.l = pw_main_loop_get_loop(data.ml);
73
+   pwtest_ptr_notnull(data.l);
74
+
75
+   data.a = calloc(1, sizeof(*data.a));
76
+   data.b = calloc(1, sizeof(*data.b));
77
+
78
+   data.a->source.func = on_event;
79
+   data.a->source.fd = eventfd(0, 0);
80
+   data.a->source.mask = SPA_IO_IN;
81
+   data.a->source.data = &data;
82
+   data.b->source.func = on_event;
83
+   data.b->source.fd = eventfd(0, 0);
84
+   data.b->source.mask = SPA_IO_IN;
85
+   data.b->source.data = &data;
86
+
87
+   pw_loop_add_source(data.l, &data.a->source);
88
+   pw_loop_add_source(data.l, &data.b->source);
89
+
90
+   write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t));
91
+   write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t));
92
+
93
+   pw_main_loop_run(data.ml);
94
+   pw_main_loop_destroy(data.ml);
95
+
96
+   pw_deinit();
97
+
98
+   return PWTEST_PASS;
99
+}
100
+
101
+static void
102
+on_event_recurse1(struct spa_source *source)
103
+{
104
+   static bool first = true;
105
+   struct data *d = source->data;
106
+   uint64_t val;
107
+
108
+   ++d->count;
109
+   pwtest_int_lt(d->count, 3);
110
+
111
+   read(source->fd, &val, sizeof(val));
112
+
113
+   if (first) {
114
+       first = false;
115
+       pw_loop_enter(d->l);
116
+       pw_loop_iterate(d->l, -1);
117
+       pw_loop_leave(d->l);
118
+   }
119
+   pw_main_loop_quit(d->ml);
120
+}
121
+
122
+PWTEST(pwtest_loop_recurse1)
123
+{
124
+   struct data data;
125
+
126
+   pw_init(0, NULL);
127
+
128
+   spa_zero(data);
129
+   data.ml = pw_main_loop_new(NULL);
130
+   pwtest_ptr_notnull(data.ml);
131
+
132
+   data.l = pw_main_loop_get_loop(data.ml);
133
+   pwtest_ptr_notnull(data.l);
134
+
135
+   data.a = calloc(1, sizeof(*data.a));
136
+   data.b = calloc(1, sizeof(*data.b));
137
+
138
+   data.a->source.func = on_event_recurse1;
139
+   data.a->source.fd = eventfd(0, 0);
140
+   data.a->source.mask = SPA_IO_IN;
141
+   data.a->source.data = &data;
142
+   data.b->source.func = on_event_recurse1;
143
+   data.b->source.fd = eventfd(0, 0);
144
+   data.b->source.mask = SPA_IO_IN;
145
+   data.b->source.data = &data;
146
+
147
+   pw_loop_add_source(data.l, &data.a->source);
148
+   pw_loop_add_source(data.l, &data.b->source);
149
+
150
+   write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t));
151
+   write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t));
152
+
153
+   pw_main_loop_run(data.ml);
154
+   pw_main_loop_destroy(data.ml);
155
+
156
+   pw_deinit();
157
+
158
+   free(data.a);
159
+   free(data.b);
160
+
161
+   return PWTEST_PASS;
162
+}
163
+
164
+static void
165
+on_event_recurse2(struct spa_source *source)
166
+{
167
+   static bool first = true;
168
+   struct data *d = source->data;
169
+   uint64_t val;
170
+
171
+   ++d->count;
172
+   pwtest_int_lt(d->count, 3);
173
+
174
+   read(source->fd, &val, sizeof(val));
175
+
176
+   if (first) {
177
+       first = false;
178
+       pw_loop_enter(d->l);
179
+       pw_loop_iterate(d->l, -1);
180
+       pw_loop_leave(d->l);
181
+   } else {
182
+       pw_loop_remove_source(d->l, &d->a->source);
183
+       pw_loop_remove_source(d->l, &d->b->source);
184
+       close(d->a->source.fd);
185
+       close(d->b->source.fd);
186
+       free(d->a);
187
+       free(d->b);
188
+   }
189
+   pw_main_loop_quit(d->ml);
190
+}
191
+
192
+PWTEST(pwtest_loop_recurse2)
193
+{
194
+   struct data data;
195
+
196
+   pw_init(0, NULL);
197
+
198
+   spa_zero(data);
199
+   data.ml = pw_main_loop_new(NULL);
200
+   pwtest_ptr_notnull(data.ml);
201
pipewire-0.3.45.tar.gz/test/test-pwtest.c -> pipewire-0.3.47.tar.gz/test/test-pwtest.c Changed
10
 
1
@@ -32,7 +32,7 @@
2
 
3
 PWTEST(compat_sigabbrev_np)
4
 {
5
-#if !HAVE_SIGABBREV_NP
6
+#ifndef HAVE_SIGABBREV_NP
7
    pwtest_str_eq(sigabbrev_np(SIGABRT), "ABRT");
8
    pwtest_str_eq(sigabbrev_np(SIGSEGV), "SEGV");
9
    pwtest_str_eq(sigabbrev_np(SIGSTOP), "STOP");
10