Changes of Revision 39

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,9 @@
2
 -------------------------------------------------------------------
3
+Fri Nov 24 19:29:49 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.85
6
+
7
+-------------------------------------------------------------------
8
 Fri Nov  3 13:41:27 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
 
10
 - Update to version 0.3.84
11
pipewire-aptx.spec Changed
10
 
1
@@ -7,7 +7,7 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        0.3.84
6
+Version:        0.3.85
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
pipewire-0.3.84.tar.gz/NEWS -> pipewire-0.3.85.tar.gz/NEWS Changed
73
 
1
@@ -1,3 +1,61 @@
2
+# PipeWire 0.3.85 (2023-11-16)
3
+
4
+This is the fifth (and last) 1.0 release candidate that is API and ABI
5
+compatible with previous 0.3.x releases.
6
+
7
+## Highlights
8
+  - Fix an issue where a link could end up paused while not negotiated.
9
+  - Fix an infinite recursion issue when finding runnable nodes.
10
+  - Support XDG base directories when loading ACP config.
11
+  - Fix MIDI event recording preview in Ardour.
12
+  - Many more small fixes, cleanups and improvements.
13
+
14
+
15
+## PipeWire
16
+  - Fix an issue where a link could end up paused while not negotiated.
17
+    (#3619)
18
+  - Fix an infinite recursion issue when finding runnable nodes by stopping
19
+    the scan on feedback links around the driver. (#3621)
20
+  - The system service now has better socket permissions.
21
+
22
+## Modules
23
+  - Add support for uclamp. This allows the scheduler to make better informed
24
+    decisions about where tasks should be placed, and what pstate to set
25
+    for the CPU it is running on.
26
+  - Emit warnings when applications are not doing the right locking instead
27
+    of crashing.
28
+  - Improve media.name for RAOP sinks. (#3801)
29
+  - Support pause/resume in pipe-tunnel. (#3197)
30
+  - Remove time rlimit when probing for realtime to avoid SIGXCPU.
31
+
32
+## SPA
33
+  - Fix a bug where the resampler would be activated even when there is an
34
+    ALSA pitch element. (#3628)
35
+  - Improve resume from suspend in ALSA. (#3646)
36
+  - Add option to expose ALSA controls as prop params.
37
+  - Support XDG base directories when loading ACP config. This makes it possible
38
+    to override the ACP config files.
39
+
40
+## Bluetooth
41
+  - Schedule nodes in the same ISO group together.
42
+  - More BAP fixes and cleanups.
43
+
44
+## JACK
45
+  - Fix MIDI events from peer ports. This makes the MIDI event recording preview
46
+    of Ardour work correctly.
47
+
48
+## GStreamer
49
+  - Fix some error handling in the source and sink.
50
+
51
+## ALSA plugin
52
+  - Improve poll descriptor handling. (#3648)
53
+
54
+## Docs
55
+  - Many improvements to the layout and organization.
56
+
57
+Older versions:
58
+
59
+
60
 # PipeWire 0.3.84 (2023-11-02)
61
 
62
 This is the fourth 1.0 release candidate that is API and ABI compatible
63
@@ -56,9 +114,6 @@
64
 ## ALSA
65
   - The ALSA plugin now handles NULL values from mmap_areas. (#3600)
66
 
67
-Older versions:
68
-
69
-
70
 # PipeWire 0.3.83 (2023-10-19)
71
 
72
 This is the third 1.0 release candidate that is API and ABI compatible
73
pipewire-0.3.84.tar.gz/doc/Doxyfile.in -> pipewire-0.3.85.tar.gz/doc/Doxyfile.in Changed
20
 
1
@@ -1,7 +1,7 @@
2
 PROJECT_NAME           = PipeWire
3
 PROJECT_NUMBER         = @PACKAGE_VERSION@
4
 OUTPUT_DIRECTORY       = "@output_directory@"
5
-FULL_PATH_NAMES        = NO
6
+FULL_PATH_NAMES        = YES
7
 JAVADOC_AUTOBRIEF      = YES
8
 TAB_SIZE               = 8
9
 OPTIMIZE_OUTPUT_FOR_C  = YES
10
@@ -36,6 +36,9 @@
11
 SEARCHENGINE           = YES
12
 GENERATE_LATEX         = NO
13
 
14
+TOC_INCLUDE_HEADINGS   = 0
15
+LAYOUT_FILE            = @layout@
16
+
17
 MACRO_EXPANSION        = YES
18
 EXPAND_ONLY_PREDEF     = YES
19
 PREDEFINED             = PA_C_DECL_BEGIN= \
20
pipewire-0.3.85.tar.gz/doc/DoxygenLayout.xml Added
201
 
1
@@ -0,0 +1,238 @@
2
+<doxygenlayout version="1.0">
3
+  <navindex>
4
+    <tab type="mainpage" visible="yes" title=""/>
5
+    <tab type="pages" visible="yes" title="Pages" intro=""/>
6
+    <tab type="modules" visible="yes" title="API Reference" intro="" />
7
+    <tab type="namespaces" visible="no" title="">
8
+      <tab type="namespacelist" visible="yes" title="" intro=""/>
9
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
10
+    </tab>
11
+    <tab type="concepts" visible="no" title="">
12
+    </tab>
13
+    <tab type="interfaces" visible="no" title="">
14
+      <tab type="interfacelist" visible="yes" title="" intro=""/>
15
+      <tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
16
+      <tab type="interfacehierarchy" visible="yes" title="" intro=""/>
17
+    </tab>
18
+    <tab type="classes" visible="yes" title="">
19
+      <tab type="classlist" visible="yes" title="" intro=""/>
20
+      <tab type="classindex" visible="yes" title=""/>
21
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
22
+      <tab type="classmembers" visible="no" title="" intro=""/>
23
+    </tab>
24
+    <tab type="structs" visible="no" title="">
25
+      <tab type="structlist" visible="yes" title="" intro=""/>
26
+      <tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
27
+    </tab>
28
+    <tab type="exceptions" visible="no" title="">
29
+      <tab type="exceptionlist" visible="yes" title="" intro=""/>
30
+      <tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
31
+      <tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
32
+    </tab>
33
+    <tab type="files" visible="yes" title="">
34
+      <tab type="filelist" visible="yes" title="" intro=""/>
35
+      <tab type="globals" visible="no" title="" intro=""/>
36
+    </tab>
37
+    <tab type="examples" visible="yes" title="" intro=""/>
38
+  </navindex>
39
+
40
+  <!-- Layout definition for a class page -->
41
+  <class>
42
+    <briefdescription visible="yes"/>
43
+    <includes visible="$SHOW_HEADERFILE"/>
44
+    <inheritancegraph visible="$CLASS_GRAPH"/>
45
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
46
+    <memberdecl>
47
+      <nestedclasses visible="yes" title=""/>
48
+      <publictypes title=""/>
49
+      <services title=""/>
50
+      <interfaces title=""/>
51
+      <publicslots title=""/>
52
+      <signals title=""/>
53
+      <publicmethods title=""/>
54
+      <publicstaticmethods title=""/>
55
+      <publicattributes title=""/>
56
+      <publicstaticattributes title=""/>
57
+      <protectedtypes title=""/>
58
+      <protectedslots title=""/>
59
+      <protectedmethods title=""/>
60
+      <protectedstaticmethods title=""/>
61
+      <protectedattributes title=""/>
62
+      <protectedstaticattributes title=""/>
63
+      <packagetypes title=""/>
64
+      <packagemethods title=""/>
65
+      <packagestaticmethods title=""/>
66
+      <packageattributes title=""/>
67
+      <packagestaticattributes title=""/>
68
+      <properties title=""/>
69
+      <events title=""/>
70
+      <privatetypes title=""/>
71
+      <privateslots title=""/>
72
+      <privatemethods title=""/>
73
+      <privatestaticmethods title=""/>
74
+      <privateattributes title=""/>
75
+      <privatestaticattributes title=""/>
76
+      <friends title=""/>
77
+      <related title="" subtitle=""/>
78
+      <membergroups visible="yes"/>
79
+    </memberdecl>
80
+    <detaileddescription title=""/>
81
+    <memberdef>
82
+      <inlineclasses title=""/>
83
+      <typedefs title=""/>
84
+      <enums title=""/>
85
+      <services title=""/>
86
+      <interfaces title=""/>
87
+      <constructors title=""/>
88
+      <functions title=""/>
89
+      <related title=""/>
90
+      <variables title=""/>
91
+      <properties title=""/>
92
+      <events title=""/>
93
+    </memberdef>
94
+    <allmemberslink visible="yes"/>
95
+    <usedfiles visible="$SHOW_USED_FILES"/>
96
+    <authorsection visible="yes"/>
97
+  </class>
98
+
99
+  <!-- Layout definition for a namespace page -->
100
+  <namespace>
101
+    <briefdescription visible="yes"/>
102
+    <memberdecl>
103
+      <nestednamespaces visible="yes" title=""/>
104
+      <constantgroups visible="yes" title=""/>
105
+      <interfaces visible="yes" title=""/>
106
+      <classes visible="yes" title=""/>
107
+      <concepts visible="yes" title=""/>
108
+      <structs visible="yes" title=""/>
109
+      <exceptions visible="yes" title=""/>
110
+      <typedefs title=""/>
111
+      <sequences title=""/>
112
+      <dictionaries title=""/>
113
+      <enums title=""/>
114
+      <functions title=""/>
115
+      <variables title=""/>
116
+      <membergroups visible="yes"/>
117
+    </memberdecl>
118
+    <detaileddescription title=""/>
119
+    <memberdef>
120
+      <inlineclasses title=""/>
121
+      <typedefs title=""/>
122
+      <sequences title=""/>
123
+      <dictionaries title=""/>
124
+      <enums title=""/>
125
+      <functions title=""/>
126
+      <variables title=""/>
127
+    </memberdef>
128
+    <authorsection visible="yes"/>
129
+  </namespace>
130
+
131
+  <!-- Layout definition for a concept page -->
132
+  <concept>
133
+    <briefdescription visible="yes"/>
134
+    <includes visible="$SHOW_HEADERFILE"/>
135
+    <definition visible="yes" title=""/>
136
+    <detaileddescription title=""/>
137
+    <authorsection visible="yes"/>
138
+  </concept>
139
+
140
+  <!-- Layout definition for a file page -->
141
+  <file>
142
+    <briefdescription visible="yes"/>
143
+    <includes visible="$SHOW_INCLUDE_FILES"/>
144
+    <includegraph visible="$INCLUDE_GRAPH"/>
145
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
146
+    <sourcelink visible="yes"/>
147
+    <memberdecl>
148
+      <interfaces visible="yes" title=""/>
149
+      <classes visible="yes" title=""/>
150
+      <structs visible="yes" title=""/>
151
+      <exceptions visible="yes" title=""/>
152
+      <namespaces visible="yes" title=""/>
153
+      <concepts visible="yes" title=""/>
154
+      <constantgroups visible="yes" title=""/>
155
+      <defines title=""/>
156
+      <typedefs title=""/>
157
+      <sequences title=""/>
158
+      <dictionaries title=""/>
159
+      <enums title=""/>
160
+      <functions title=""/>
161
+      <variables title=""/>
162
+      <membergroups visible="yes"/>
163
+    </memberdecl>
164
+    <detaileddescription title=""/>
165
+    <memberdef>
166
+      <inlineclasses title=""/>
167
+      <defines title=""/>
168
+      <typedefs title=""/>
169
+      <sequences title=""/>
170
+      <dictionaries title=""/>
171
+      <enums title=""/>
172
+      <functions title=""/>
173
+      <variables title=""/>
174
+    </memberdef>
175
+    <authorsection/>
176
+  </file>
177
+
178
+  <!-- Layout definition for a group page -->
179
+  <group>
180
+    <briefdescription visible="yes"/>
181
+    <groupgraph visible="$GROUP_GRAPHS"/>
182
+    <memberdecl>
183
+      <nestedgroups visible="yes" title=""/>
184
+      <dirs visible="yes" title=""/>
185
+      <files visible="yes" title=""/>
186
+      <namespaces visible="yes" title=""/>
187
+      <concepts visible="yes" title=""/>
188
+      <classes visible="yes" title=""/>
189
+      <typedefs title=""/>
190
+      <sequences title=""/>
191
+      <dictionaries title=""/>
192
+      <enums title=""/>
193
+      <enumvalues title=""/>
194
+      <defines title=""/>
195
+      <functions title=""/>
196
+      <variables title=""/>
197
+      <signals title=""/>
198
+      <publicslots title=""/>
199
+      <protectedslots title=""/>
200
+      <privateslots title=""/>
201
pipewire-0.3.84.tar.gz/doc/api-tree.dox -> pipewire-0.3.85.tar.gz/doc/api-tree.dox Changed
18
 
1
@@ -89,6 +89,7 @@
2
 \addtogroup spa_hooks
3
 \addtogroup spa_interfaces
4
 \addtogroup spa_json
5
+\addtogroup spa_json_pod
6
 \addtogroup spa_keys
7
 \addtogroup spa_names
8
 \addtogroup spa_result
9
@@ -119,8 +120,4 @@
10
 \{
11
 \}
12
 
13
-\defgroup pwtest Test Suite
14
-\{
15
-\}
16
-
17
 */
18
pipewire-0.3.84.tar.gz/doc/custom.css -> pipewire-0.3.85.tar.gz/doc/custom.css Changed
22
 
1
@@ -17,3 +17,20 @@
2
        --fragment-link: #729fcf;
3
    }
4
 }
5
+
6
+#nav-tree .arrow {
7
+    opacity: 1;
8
+    padding-right: 0.25em;
9
+}
10
+
11
+.textblock h1 {
12
+    font-size: 150%;
13
+}
14
+.textblock h2 {
15
+    font-size: 100%;
16
+}
17
+.textblock h3, .textblock h4, .textblock h5, .textblock h6 {
18
+    font-size: 100%;
19
+    font-style: italic;
20
+    font-size: medium;
21
+}
22
pipewire-0.3.84.tar.gz/doc/index.dox -> pipewire-0.3.85.tar.gz/doc/index.dox Changed
15
 
1
@@ -43,4 +43,13 @@
2
 - Intoduction to PipeWire(https://bootlin.com/blog/an-introduction-to-pipewire/)
3
 - A custom PipeWire node(https://bootlin.com/blog/a-custom-pipewire-node/)
4
 
5
+
6
+\page page_overview
7
+\page page_pipewire
8
+\page page_tools
9
+\page page_pipewire_modules
10
+\page page_api
11
+\page page_spa
12
+\page page_tutorial
13
+
14
 */
15
pipewire-0.3.84.tar.gz/doc/manpage.dox.in -> pipewire-0.3.85.tar.gz/doc/manpage.dox.in Changed
9
 
1
@@ -1,5 +1,7 @@
2
 /** \page @pagename@ @title@
3
 
4
+\brief Manual page for @title@
5
+
6
 \verbinclude @filename@
7
 
8
 */
9
pipewire-0.3.84.tar.gz/doc/meson.build -> pipewire-0.3.85.tar.gz/doc/meson.build Changed
37
 
1
@@ -68,7 +68,6 @@
2
 foreach h : module_sources
3
   inputs += meson.project_source_root() / 'src' / 'modules' / h
4
 endforeach
5
-inputs += meson.project_source_root() / 'test' / 'pwtest.h'
6
 input_dirs =  meson.project_source_root() / 'spa' / 'include' / 'spa' 
7
 
8
 path_prefixes = 
9
@@ -141,11 +140,16 @@
10
                           configuration: pw_tools_dox_conf)
11
 input_dirs +=  'doc/pipewire-tools.dox' 
12
 
13
+doxygen_layout = meson.project_source_root() / 'doc' / 'DoxygenLayout.xml'
14
+doxygen_filter_c = meson.project_source_root() / 'doc' / 'input-filter.sh'
15
+doxygen_filter_h = meson.project_source_root() / 'doc' / 'input-filter-h.sh'
16
+
17
 doxyfile_conf.set('inputs', ' '.join(inputs + input_dirs))
18
 doxyfile_conf.set('cssfiles', ' '.join(cssfiles))
19
+doxyfile_conf.set('layout', doxygen_layout)
20
 doxyfile_conf.set('path_prefixes', ' '.join(path_prefixes))
21
-doxyfile_conf.set('c_input_filter', meson.project_source_root() / 'doc' / 'input-filter.sh')
22
-doxyfile_conf.set('h_input_filter', meson.project_source_root() / 'doc' / 'input-filter-h.sh')
23
+doxyfile_conf.set('c_input_filter', doxygen_filter_c)
24
+doxyfile_conf.set('h_input_filter', doxygen_filter_h)
25
 
26
 doxyfile = configure_file(input: 'Doxyfile.in',
27
                           output: 'Doxyfile',
28
@@ -157,7 +161,7 @@
29
 endif
30
 
31
 html_target = custom_target('pipewire-docs',
32
-                            input:  doxyfile, examples_dox, pw_tools_dox  + inputs + cssfiles + man_doxygen,
33
+                            input:  doxyfile, doxygen_layout, examples_dox, pw_tools_dox, doxygen_filter_c, doxygen_filter_h  + inputs + cssfiles + man_doxygen,
34
                             output:  'html' ,
35
                             command:  doxygen, doxyfile ,
36
                             install: true,
37
pipewire-0.3.84.tar.gz/doc/pipewire.dox -> pipewire-0.3.85.tar.gz/doc/pipewire.dox Changed
12
 
1
@@ -17,10 +17,8 @@
2
 # Components
3
 
4
 - \subpage page_daemon
5
-- \subpage page_tools
6
 - \subpage page_session_manager
7
 
8
-
9
 # Backends
10
 
11
 - \subpage page_pulseaudio
12
pipewire-0.3.84.tar.gz/doc/tutorial4.c -> pipewire-0.3.85.tar.gz/doc/tutorial4.c Changed
10
 
1
@@ -42,6 +42,8 @@
2
 
3
    stride = sizeof(int16_t) * DEFAULT_CHANNELS;
4
    n_frames = buf->datas0.maxsize / stride;
5
+   if (b->requested)
6
+       n_frames = SPA_MIN(b->requested, n_frames);
7
 
8
    for (i = 0; i < n_frames; i++) {
9
        data->accumulator += M_PI_M2 * 440 / DEFAULT_RATE;
10
pipewire-0.3.84.tar.gz/meson.build -> pipewire-0.3.85.tar.gz/meson.build Changed
18
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', 'c' ,
3
-  version : '0.3.84',
4
+  version : '0.3.85',
5
   license :  'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
   meson_version : '>= 0.61.1',
7
   default_options :  'warning_level=3',
8
@@ -219,8 +219,7 @@
9
 cdata.set_quoted('PIPEWIRE_CONFIG_DIR', pipewire_configdir)
10
 cdata.set_quoted('PLUGINDIR', spa_plugindir)
11
 cdata.set_quoted('SPADATADIR', spa_datadir)
12
-cdata.set_quoted('PA_ALSA_PATHS_DIR', alsadatadir / 'paths')
13
-cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', alsadatadir / 'profile-sets')
14
+cdata.set_quoted('PA_ALSA_DATA_DIR', alsadatadir)
15
 
16
 if host_machine.endian() == 'big'
17
   cdata.set('WORDS_BIGENDIAN', 1)
18
pipewire-0.3.84.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c -> pipewire-0.3.85.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c Changed
104
 
1
@@ -89,7 +89,7 @@
2
 
3
 static int snd_pcm_pipewire_stop(snd_pcm_ioplug_t *io);
4
 
5
-static int check_active(snd_pcm_ioplug_t *io)
6
+static int update_active(snd_pcm_ioplug_t *io)
7
 {
8
    snd_pcm_pipewire_t *pw = io->private_data;
9
    snd_pcm_sframes_t avail;
10
@@ -97,7 +97,10 @@
11
 
12
    avail = snd_pcm_ioplug_avail(io, pw->hw_ptr, io->appl_ptr);
13
 
14
-   if (io->state == SND_PCM_STATE_DRAINING) {
15
+   if (pw->error > 0) {
16
+       active = true;
17
+   }
18
+   else if (io->state == SND_PCM_STATE_DRAINING) {
19
        active = pw->drained;
20
    }
21
    else if (avail >= 0 && avail < (snd_pcm_sframes_t)pw->min_avail) {
22
@@ -105,33 +108,27 @@
23
    }
24
    else if (avail >= (snd_pcm_sframes_t)pw->min_avail) {
25
        active = true;
26
-   } else {
27
+   }
28
+   else {
29
        active = false;
30
    }
31
    if (pw->active != active) {
32
+       uint64_t val;
33
+
34
        pw_log_trace("%p: avail:%lu min-avail:%lu state:%s hw:%lu appl:%lu active:%d->%d state:%s",
35
            pw, avail, pw->min_avail, snd_pcm_state_name(io->state),
36
            pw->hw_ptr, io->appl_ptr, pw->active, active,
37
            snd_pcm_state_name(io->state));
38
+
39
+       pw->active = active;
40
+       if (active)
41
+           spa_system_eventfd_write(pw->system, io->poll_fd, 1);
42
+       else
43
+           spa_system_eventfd_read(pw->system, io->poll_fd, &val);
44
    }
45
    return active;
46
 }
47
 
48
-
49
-static int update_active(snd_pcm_ioplug_t *io)
50
-{
51
-   snd_pcm_pipewire_t *pw = io->private_data;
52
-   pw->active = check_active(io);
53
-   uint64_t val;
54
-
55
-   if (pw->active || pw->error < 0)
56
-       spa_system_eventfd_write(pw->system, io->poll_fd, 1);
57
-   else
58
-       spa_system_eventfd_read(pw->system, io->poll_fd, &val);
59
-
60
-   return pw->active;
61
-}
62
-
63
 static void snd_pcm_pipewire_free(snd_pcm_pipewire_t *pw)
64
 {
65
    if (pw == NULL)
66
@@ -162,15 +159,6 @@
67
    return 0;
68
 }
69
 
70
-static int snd_pcm_pipewire_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space)
71
-{
72
-   snd_pcm_pipewire_t *pw = io->private_data;
73
-   update_active(io);
74
-   pfds->fd = pw->fd;
75
-   pfds->events = POLLIN | POLLERR | POLLNVAL;
76
-   return 1;
77
-}
78
-
79
 static int snd_pcm_pipewire_poll_revents(snd_pcm_ioplug_t *io,
80
                     struct pollfd *pfds, unsigned int nfds,
81
                     unsigned short *revents)
82
@@ -183,10 +171,10 @@
83
        return pw->error;
84
 
85
    *revents = pfds0.revents & ~(POLLIN | POLLOUT);
86
-   if (pfds0.revents & POLLIN && check_active(io)) {
87
+   if (pfds0.revents & POLLIN && update_active(io))
88
        *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN;
89
-       update_active(io);
90
-   }
91
+
92
+   pw_log_trace_fp("poll %d", *revents);
93
 
94
    return 0;
95
 }
96
@@ -911,7 +899,6 @@
97
    .delay = snd_pcm_pipewire_delay,
98
    .drain = snd_pcm_pipewire_drain,
99
    .prepare = snd_pcm_pipewire_prepare,
100
-   .poll_descriptors = snd_pcm_pipewire_poll_descriptors,
101
    .poll_revents = snd_pcm_pipewire_poll_revents,
102
    .hw_params = snd_pcm_pipewire_hw_params,
103
    .sw_params = snd_pcm_pipewire_sw_params,
104
pipewire-0.3.84.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.85.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
201
 
1
@@ -110,6 +110,10 @@
2
 static struct globals globals;
3
 static bool mlock_warned = false;
4
 
5
+#define MIDI_SCRATCH_FRAMES    8192
6
+static float midi_scratchMIDI_SCRATCH_FRAMES;
7
+
8
+
9
 #define OBJECT_CHUNK       8
10
 #define RECYCLE_THRESHOLD  128
11
 
12
@@ -122,9 +126,10 @@
13
 
14
    struct client *client;
15
 
16
-#define INTERFACE_Port     0
17
-#define INTERFACE_Node     1
18
-#define INTERFACE_Link     2
19
+#define INTERFACE_Invalid  0
20
+#define INTERFACE_Port     1
21
+#define INTERFACE_Node     2
22
+#define INTERFACE_Link     3
23
    uint32_t type;
24
    uint32_t id;
25
    uint32_t serial;
26
@@ -502,7 +507,7 @@
27
    pthread_mutex_lock(&globals.lock);
28
    spa_list_for_each_safe(o, t, &c->context.objects, link) {
29
        if (o->removed) {
30
-           pw_log_info("%p: recycle object:%p type:%d id:%u/%u",
31
+           pw_log_debug("%p: recycle object:%p type:%d id:%u/%u",
32
                    c, o, o->type, o->id, o->serial);
33
            spa_list_remove(&o->link);
34
            memset(o, 0, sizeof(struct object));
35
@@ -531,6 +536,15 @@
36
 
37
 }
38
 
39
+static inline struct object *port_to_object(const jack_port_t *port)
40
+{
41
+   return (struct object*)port;
42
+}
43
+static inline jack_port_t *object_to_port(struct object *o)
44
+{
45
+   return (jack_port_t*)o;
46
+}
47
+
48
 struct io_info {
49
    struct mix *mix;
50
    void *data;
51
@@ -2522,6 +2536,17 @@
52
    return 0;
53
 }
54
 
55
+static void midi_init_buffer(void *data, uint32_t max_frames)
56
+{
57
+   struct midi_buffer *mb = data;
58
+   mb->magic = MIDI_BUFFER_MAGIC;
59
+   mb->buffer_size = max_frames * sizeof(float);
60
+   mb->nframes = max_frames;
61
+   mb->write_pos = 0;
62
+   mb->event_count = 0;
63
+   mb->lost_events = 0;
64
+}
65
+
66
 static inline void *init_buffer(struct port *p)
67
 {
68
    struct client *c = p->client;
69
@@ -2531,12 +2556,7 @@
70
 
71
    if (p->object->port.type_id == TYPE_ID_MIDI) {
72
        struct midi_buffer *mb = data;
73
-       mb->magic = MIDI_BUFFER_MAGIC;
74
-       mb->buffer_size = c->max_frames * sizeof(float);
75
-       mb->nframes = c->max_frames;
76
-       mb->write_pos = 0;
77
-       mb->event_count = 0;
78
-       mb->lost_events = 0;
79
+       midi_init_buffer(data, c->max_frames);
80
        pw_log_debug("port %p: init midi buffer size:%d", p, mb->buffer_size);
81
    } else
82
        memset(data, 0, c->max_frames * sizeof(float));
83
@@ -3218,7 +3238,7 @@
84
 }
85
 
86
 static const struct pw_node_events node_events = {
87
-   PW_VERSION_NODE,
88
+   PW_VERSION_NODE_EVENTS,
89
    .info = node_info,
90
 };
91
 
92
@@ -3243,7 +3263,7 @@
93
 }
94
 
95
 static const struct pw_port_events port_events = {
96
-   PW_VERSION_PORT,
97
+   PW_VERSION_PORT_EVENTS,
98
    .param = port_param,
99
 };
100
 
101
@@ -5005,7 +5025,7 @@
102
        goto error_free;
103
    }
104
 
105
-   return (jack_port_t *) o;
106
+   return object_to_port(o);
107
 
108
 error_free:
109
    free_port(c, p, true);
110
@@ -5037,7 +5057,7 @@
111
 int jack_port_unregister (jack_client_t *client, jack_port_t *port)
112
 {
113
    struct client *c = (struct client *) client;
114
-   struct object *o = (struct object *) port;
115
+   struct object *o = port_to_object(port);
116
    struct port *p;
117
    int res;
118
 
119
@@ -5214,41 +5234,58 @@
120
 SPA_EXPORT
121
 void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
122
 {
123
-   struct object *o = (struct object *) port;
124
-   struct port *p;
125
-   void *ptr;
126
+   struct object *o = port_to_object(port);
127
+   struct port *p = NULL;
128
+   void *ptr = NULL;
129
 
130
    return_val_if_fail(o != NULL, NULL);
131
 
132
    if (o->type != INTERFACE_Port || o->client == NULL)
133
-       return NULL;
134
+       goto done;
135
 
136
    if ((p = o->port.port) == NULL) {
137
        struct mix *mix;
138
        struct buffer *b;
139
 
140
        if ((mix = find_mix_peer(o->client, o->id)) == NULL)
141
-           return NULL;
142
+           goto done;
143
 
144
        pw_log_trace("peer mix: %p %d", mix, mix->peer_id);
145
 
146
        if ((b = get_mix_buffer(mix, frames)) == NULL)
147
-           return NULL;
148
+           goto done;
149
 
150
-       return get_buffer_data(b, frames);
151
+       if (o->port.type_id == TYPE_ID_MIDI) {
152
+           struct spa_pod_sequence *seq1;
153
+           struct spa_data *d;
154
+           void *pod;
155
+
156
+           ptr = midi_scratch;
157
+           midi_init_buffer(ptr, MIDI_SCRATCH_FRAMES);
158
+
159
+           d = &b->datas0;
160
+           if ((pod = spa_pod_from_data(d->data, d->maxsize,
161
+                           d->chunk->offset, d->chunk->size)) == NULL)
162
+               goto done;
163
+           if (!spa_pod_is_sequence(pod))
164
+               goto done;
165
+           seq0 = pod;
166
+           convert_to_midi(seq, 1, ptr, o->client->fix_midi_events);
167
+       } else {
168
+           ptr = get_buffer_data(b, frames);
169
+       }
170
+   } else if (p->valid) {
171
+       ptr = p->get_buffer(p, frames);
172
    }
173
-   if (!p->valid)
174
-       return NULL;
175
-
176
-   ptr = p->get_buffer(p, frames);
177
-   pw_log_trace_fp("%p: port %p buffer %p empty:%u", p->client, p, ptr, p->empty_out);
178
+done:
179
+   pw_log_trace_fp("%p: port %p buffer %p", p->client, p, ptr);
180
    return ptr;
181
 }
182
 
183
 SPA_EXPORT
184
 jack_uuid_t jack_port_uuid (const jack_port_t *port)
185
 {
186
-   struct object *o = (struct object *) port;
187
+   struct object *o = port_to_object(port);
188
    return_val_if_fail(o != NULL, 0);
189
    return jack_port_uuid_generate(o->serial);
190
 }
191
@@ -5269,47 +5306,57 @@
192
 SPA_EXPORT
193
 const char * jack_port_name (const jack_port_t *port)
194
 {
195
-   struct object *o = (struct object *) port;
196
+   struct object *o = port_to_object(port);
197
    return_val_if_fail(o != NULL, NULL);
198
+   if (o->type != INTERFACE_Port)
199
+       return NULL;
200
    return port_name(o);
201
pipewire-0.3.84.tar.gz/spa/include/spa/debug/log.h -> pipewire-0.3.85.tar.gz/spa/include/spa/debug/log.h Changed
10
 
1
@@ -38,7 +38,7 @@
2
 SPA_PRINTF_FUNC(2,3)
3
 static inline void spa_debug_log_log(struct spa_debug_context *ctx, const char *fmt, ...)
4
 {
5
-   struct spa_debug_log_ctx *c = (struct spa_debug_log_ctx*)ctx;
6
+   struct spa_debug_log_ctx *c = SPA_CONTAINER_OF(ctx, struct spa_debug_log_ctx, ctx);
7
    va_list args;
8
    va_start(args, fmt);
9
    spa_log_logtv(c->log, c->level, c->topic, c->file, c->line, c->func, fmt, args);
10
pipewire-0.3.84.tar.gz/spa/include/spa/param/props.h -> pipewire-0.3.85.tar.gz/spa/include/spa/param/props.h Changed
36
 
1
@@ -64,24 +64,26 @@
2
    SPA_PROP_patternType,
3
    SPA_PROP_ditherType,
4
    SPA_PROP_truncate,
5
-   SPA_PROP_channelVolumes,        /**< a volume array, one volume per channel
6
+   SPA_PROP_channelVolumes,        /**< a volume array, one (linear) volume per channel
7
                          * (Array of Float). 0.0 is silence, 1.0 is
8
-                         *  without attenuation. This is the effective volume
9
-                         *  that is applied. It can result in a hardware volume
10
-                         *  and software volume (see softVolumes) */
11
+                         *  without attenuation. This is the effective
12
+                         *  volume that is applied. It can result
13
+                         *  in a hardware volume and software volume
14
+                         *  (see softVolumes) */
15
    SPA_PROP_volumeBase,            /**< a volume base (Float) */
16
    SPA_PROP_volumeStep,            /**< a volume step (Float) */
17
    SPA_PROP_channelMap,            /**< a channelmap array
18
                          * (Array (Id enum spa_audio_channel)) */
19
    SPA_PROP_monitorMute,           /**< mute (Bool) */
20
-   SPA_PROP_monitorVolumes,        /**< a volume array, one volume per
21
+   SPA_PROP_monitorVolumes,        /**< a volume array, one (linear) volume per
22
                          *  channel (Array of Float) */
23
    SPA_PROP_latencyOffsetNsec,     /**< delay adjustment */
24
    SPA_PROP_softMute,          /**< mute (Bool) applied in software */
25
-   SPA_PROP_softVolumes,           /**< a volume array, one volume per channel
26
+   SPA_PROP_softVolumes,           /**< a volume array, one (linear) volume per channel
27
                          * (Array of Float). 0.0 is silence, 1.0 is without
28
-                         * attenuation. This is the volume applied in software,
29
-                         * there might be a part applied in hardware. */
30
+                         * attenuation. This is the volume applied in
31
+                         * software, there might be a part applied in
32
+                         * hardware. */
33
 
34
    SPA_PROP_iec958Codecs,          /**< enabled IEC958 (S/PDIF) codecs,
35
                          *  (Array (Id enum spa_audio_iec958_codec) */
36
pipewire-0.3.84.tar.gz/spa/include/spa/utils/keys.h -> pipewire-0.3.85.tar.gz/spa/include/spa/utils/keys.h Changed
9
 
1
@@ -44,6 +44,7 @@
2
 #define SPA_KEY_API_ALSA_OPEN_UCM  "api.alsa.open.ucm"     /**< if UCM should be opened card */
3
 #define SPA_KEY_API_ALSA_DISABLE_LONGNAME  \
4
                    "api.alsa.disable-longname" /**< if card long name should not be passed to MIDI port */
5
+#define SPA_KEY_API_ALSA_BIND_CTLS "api.alsa.bind-ctls"        /**< alsa controls to bind as params */
6
 
7
 /** info from alsa card_info */
8
 #define SPA_KEY_API_ALSA_CARD_ID   "api.alsa.card.id"      /**< id from card_info */
9
pipewire-0.3.84.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c Changed
75
 
1
@@ -2795,20 +2795,6 @@
2
     return 0;
3
 }
4
 
5
-static const char *get_default_paths_dir(void) {
6
-    const char *str;
7
-#ifdef HAVE_RUNNING_FROM_BUILD_TREE
8
-    if (pa_run_from_build_tree())
9
-        return PA_SRCDIR "mixer/paths";
10
-    else
11
-#endif
12
-    if (getenv("ACP_BUILDDIR") != NULL)
13
-        return "mixer/paths";
14
-    if ((str = getenv("ACP_PATHS_DIR")) != NULL)
15
-        return str;
16
-    return PA_ALSA_PATHS_DIR;
17
-}
18
-
19
 pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa_direction_t direction) {
20
     pa_alsa_path *p;
21
     char *fn;
22
@@ -2873,10 +2859,9 @@
23
     items2.data = &p->description;
24
     items3.data = &mute_during_activation;
25
 
26
-    if (!paths_dir)
27
-        paths_dir = get_default_paths_dir();
28
+    fn = get_data_path(paths_dir, "paths", fname);
29
 
30
-    fn = pa_maybe_prefix_path(fname, paths_dir);
31
+    pa_log_info("Loading path config: %s", fn);
32
 
33
     r = pa_config_parse(fn, NULL, items, p->proplist, false, p);
34
     pa_xfree(fn);
35
@@ -4827,20 +4812,6 @@
36
     pa_xfree(db_values);
37
 }
38
 
39
-static const char *get_default_profile_dir(void) {
40
-    const char *str;
41
-#ifdef HAVE_RUNNING_FROM_BUILD_TREE
42
-    if (pa_run_from_build_tree())
43
-        return PA_SRCDIR "mixer/profile-sets";
44
-    else
45
-#endif
46
-    if (getenv("ACP_BUILDDIR") != NULL)
47
-        return "mixer/profile-sets";
48
-    if ((str = getenv("ACP_PROFILES_DIR")) != NULL)
49
-        return str;
50
-    return PA_ALSA_PROFILE_SETS_DIR;
51
-}
52
-
53
 pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus) {
54
     pa_alsa_profile_set *ps;
55
     pa_alsa_profile *p;
56
@@ -4890,13 +4861,14 @@
57
 
58
     items0.data = &ps->auto_profiles;
59
 
60
-    fn = pa_maybe_prefix_path(fname ? fname : "default.conf",
61
-           get_default_profile_dir());
62
+    fn = get_data_path(NULL, "profile-sets", fname ? fname : "default.conf");
63
+
64
+    pa_log_info("Loading profile set: %s", fn);
65
+
66
     if ((r = access(fn, R_OK)) != 0) {
67
         if (fname != NULL) {
68
             pa_log_warn("profile-set '%s' can't be accessed: %m", fn);
69
-            fn = pa_maybe_prefix_path("default.conf",
70
-               get_default_profile_dir());
71
+            fn = get_data_path(NULL, "profile-sets", "default.conf");
72
             r = access(fn, R_OK);
73
    }
74
    if (r != 0) {
75
pipewire-0.3.84.tar.gz/spa/plugins/alsa/acp/compat.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/acp/compat.c Changed
92
 
1
@@ -18,9 +18,13 @@
2
   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
3
 ***/
4
 
5
+#include <spa/utils/string.h>
6
+#include <spa/utils/cleanup.h>
7
+
8
 #include "compat.h"
9
 #include "device-port.h"
10
 #include "alsa-mixer.h"
11
+#include "config.h"
12
 
13
 static const char *port_types = {
14
    PA_DEVICE_PORT_TYPE_UNKNOWN = "unknown",
15
@@ -208,3 +212,76 @@
16
 
17
     return true;
18
 }
19
+
20
+static char *try_path(const char *fname, const char *path)
21
+{
22
+    char *result = pa_maybe_prefix_path(fname, path);
23
+
24
+    pa_log_trace("Check for file: %s", result);
25
+
26
+    if (access(result, R_OK) == 0)
27
+   return result;
28
+
29
+    pa_xfree(result);
30
+    return NULL;
31
+}
32
+
33
+static char *get_xdg_home(const char *key, const char *fallback)
34
+{
35
+    const char *e;
36
+
37
+    e = getenv(key);
38
+    if (e && *e) {
39
+   return strdup(e);
40
+    } else {
41
+   e = getenv("HOME");
42
+   if (!(e && *e))
43
+       e = getenv("USERPROFILE");
44
+   if (e && *e)
45
+       return spa_aprintf("%s/%s", e, fallback);
46
+    }
47
+    return NULL;
48
+}
49
+
50
+char *get_data_path(const char *data_dir, const char *data_type, const char *fname)
51
+{
52
+    static const char * const subpaths = {
53
+   "alsa-card-profile/mixer",
54
+   "alsa-card-profile",
55
+    };
56
+    const char *e;
57
+    spa_autofree char *base = NULL;
58
+    char *result;
59
+
60
+    if (data_dir)
61
+   if ((result = try_path(fname, data_dir)) != NULL)
62
+       return result;
63
+
64
+    e = getenv("ACP_PATHS_DIR");
65
+    if (e && *e && spa_streq(data_type, "paths"))
66
+   if ((result = try_path(fname, e)) != NULL)
67
+       return result;
68
+
69
+    e = getenv("ACP_PROFILES_DIR");
70
+    if (e && *e && spa_streq(data_type, "profile-sets"))
71
+   if ((result = try_path(fname, e)) != NULL)
72
+       return result;
73
+
74
+    base = get_xdg_home("XDG_CONFIG_HOME", ".config");
75
+    if (base) {
76
+   SPA_FOR_EACH_ELEMENT_VAR(subpaths, subpath) {
77
+       spa_autofree char *path = spa_aprintf("%s/%s/%s", base, *subpath, data_type);
78
+       if ((result = try_path(fname, path)) != NULL)
79
+       return result;
80
+   }
81
+    }
82
+
83
+    SPA_FOR_EACH_ELEMENT_VAR(subpaths, subpath) {
84
+   spa_autofree char *path = spa_aprintf("/etc/%s/%s", *subpath, data_type);
85
+   if ((result = try_path(fname, path)) != NULL)
86
+       return result;
87
+    }
88
+
89
+    spa_autofree char *path = spa_aprintf("%s/%s", PA_ALSA_DATA_DIR, data_type);
90
+    return pa_maybe_prefix_path(fname, path);
91
+}
92
pipewire-0.3.84.tar.gz/spa/plugins/alsa/acp/compat.h -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/acp/compat.h Changed
26
 
1
@@ -214,6 +214,7 @@
2
    PA_LOG_NOTICE = 2,    /* Notice messages */
3
    PA_LOG_INFO   = 3,    /* Info messages */
4
    PA_LOG_DEBUG  = 4,    /* Debug messages */
5
+   PA_LOG_TRACE = 5,
6
    PA_LOG_LEVEL_MAX
7
 } pa_log_level_t;
8
 
9
@@ -245,6 +246,7 @@
10
 #define pa_log_notice(fmt,...) pa_logl(PA_LOG_NOTICE, fmt, ##__VA_ARGS__)
11
 #define pa_log_info(fmt,...)   pa_logl(PA_LOG_INFO, fmt, ##__VA_ARGS__)
12
 #define pa_log_debug(fmt,...)  pa_logl(PA_LOG_DEBUG, fmt, ##__VA_ARGS__)
13
+#define pa_log_trace(fmt,...)  pa_logl(PA_LOG_TRACE, fmt, ##__VA_ARGS__)
14
 #define pa_log         pa_log_error
15
 
16
 #define pa_assert_se(expr)                                              \
17
@@ -677,6 +679,8 @@
18
 #endif
19
 }
20
 
21
+char *get_data_path(const char *data_dir, const char *data_type, const char *fname);
22
+
23
 #include <spa/support/i18n.h>
24
 
25
 extern struct spa_i18n *acp_i18n;
26
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-compress-offload-device.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-compress-offload-device.c Changed
10
 
1
@@ -86,7 +86,7 @@
2
         * hardware that can capture audio is difficult to do. The only hardware
3
         * known is the Wolfson ADSP; the only driver in the kernel that exposes
4
         * Compress-Offload capture devices is the one for that hardware. */
5
-       assert(false);
6
+       spa_assert_not_reached();
7
    }
8
 
9
    info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
10
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c Changed
155
 
1
@@ -8,8 +8,6 @@
2
 
3
 #include <spa/node/node.h>
4
 #include <spa/node/utils.h>
5
-#include <spa/node/keys.h>
6
-#include <spa/monitor/device.h>
7
 #include <spa/utils/keys.h>
8
 #include <spa/utils/names.h>
9
 #include <spa/utils/string.h>
10
@@ -31,75 +29,6 @@
11
    props->use_chmap = DEFAULT_USE_CHMAP;
12
 }
13
 
14
-static void emit_node_info(struct state *this, bool full)
15
-{
16
-   uint64_t old = full ? this->info.change_mask : 0;
17
-
18
-   if (full)
19
-       this->info.change_mask = this->info_all;
20
-   if (this->info.change_mask) {
21
-       struct spa_dict_item items7;
22
-       uint32_t i, n_items = 0;
23
-       char latency64, period64, nperiods64, headroom64;
24
-
25
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa");
26
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Sink");
27
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
28
-       if (this->have_format) {
29
-           snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate);
30
-           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency);
31
-           snprintf(period, sizeof(period), "%lu", this->period_frames);
32
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period);
33
-           snprintf(nperiods, sizeof(nperiods), "%lu",
34
-                   this->period_frames != 0 ? this->buffer_frames / this->period_frames : 0);
35
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods);
36
-           snprintf(headroom, sizeof(headroom), "%u", this->headroom);
37
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom);
38
-       } else {
39
-           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, NULL);
40
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", NULL);
41
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", NULL);
42
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", NULL);
43
-       }
44
-       this->info.props = &SPA_DICT_INIT(items, n_items);
45
-
46
-       if (this->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
47
-           for (i = 0; i < this->info.n_params; i++) {
48
-               if (this->paramsi.user > 0) {
49
-                   this->paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
50
-                   this->paramsi.user = 0;
51
-               }
52
-           }
53
-       }
54
-       spa_node_emit_info(&this->hooks, &this->info);
55
-
56
-       this->info.change_mask = old;
57
-   }
58
-}
59
-
60
-static void emit_port_info(struct state *this, bool full)
61
-{
62
-   uint64_t old = full ? this->port_info.change_mask : 0;
63
-
64
-   if (full)
65
-       this->port_info.change_mask = this->port_info_all;
66
-   if (this->port_info.change_mask) {
67
-       uint32_t i;
68
-
69
-       if (this->port_info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
70
-           for (i = 0; i < this->port_info.n_params; i++) {
71
-               if (this->port_paramsi.user > 0) {
72
-                   this->port_paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
73
-                   this->port_paramsi.user = 0;
74
-               }
75
-           }
76
-       }
77
-       spa_node_emit_port_info(&this->hooks,
78
-               SPA_DIRECTION_INPUT, 0, &this->port_info);
79
-       this->port_info.change_mask = old;
80
-   }
81
-}
82
-
83
 static int impl_node_enum_params(void *object, int seq,
84
                 uint32_t id, uint32_t start, uint32_t num,
85
                 const struct spa_pod *filter)
86
@@ -348,8 +277,8 @@
87
            info.ns = lat_ns;
88
            handle_process_latency(this, &info);
89
        }
90
-       emit_node_info(this, false);
91
-       emit_port_info(this, false);
92
+       spa_alsa_emit_node_info(this, false);
93
+       spa_alsa_emit_port_info(this, false);
94
        break;
95
    }
96
    case SPA_PARAM_ProcessLatency:
97
@@ -362,8 +291,8 @@
98
 
99
        handle_process_latency(this, &info);
100
 
101
-       emit_node_info(this, false);
102
-       emit_port_info(this, false);
103
+       spa_alsa_emit_node_info(this, false);
104
+       spa_alsa_emit_port_info(this, false);
105
        break;
106
    }
107
    default:
108
@@ -425,8 +354,8 @@
109
 
110
    spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
111
 
112
-   emit_node_info(this, true);
113
-   emit_port_info(this, true);
114
+   spa_alsa_emit_node_info(this, true);
115
+   spa_alsa_emit_port_info(this, true);
116
 
117
    spa_hook_list_join(&this->hooks, &save);
118
 
119
@@ -673,7 +602,7 @@
120
    }
121
 
122
    this->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS;
123
-   emit_node_info(this, false);
124
+   spa_alsa_emit_node_info(this, false);
125
 
126
    this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
127
    this->port_info.rate = SPA_FRACTION(1, this->rate);
128
@@ -686,7 +615,7 @@
129
        this->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
130
        this->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
131
    }
132
-   emit_port_info(this, false);
133
+   spa_alsa_emit_port_info(this, false);
134
 
135
    return err;
136
 }
137
@@ -722,7 +651,7 @@
138
        this->latencyinfo.direction = info;
139
        this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
140
        this->port_paramsPORT_Latency.user++;
141
-       emit_port_info(this, false);
142
+       spa_alsa_emit_port_info(this, false);
143
        break;
144
    }
145
    case SPA_PARAM_Tag:
146
@@ -741,7 +670,7 @@
147
 
148
            this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
149
            this->port_paramsPORT_Tag.user++;
150
-           emit_port_info(this, false);
151
+           spa_alsa_emit_port_info(this, false);
152
        }
153
        break;
154
    }
155
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm-source.c Changed
157
 
1
@@ -8,12 +8,10 @@
2
 
3
 #include <spa/node/node.h>
4
 #include <spa/node/utils.h>
5
-#include <spa/node/keys.h>
6
 #include <spa/utils/keys.h>
7
 #include <spa/utils/names.h>
8
 #include <spa/utils/list.h>
9
 #include <spa/utils/string.h>
10
-#include <spa/monitor/device.h>
11
 #include <spa/param/audio/format.h>
12
 #include <spa/pod/filter.h>
13
 #include <spa/pod/dynamic.h>
14
@@ -32,73 +30,6 @@
15
    props->use_chmap = DEFAULT_USE_CHMAP;
16
 }
17
 
18
-static void emit_node_info(struct state *this, bool full)
19
-{
20
-   uint64_t old = full ? this->info.change_mask : 0;
21
-   if (full)
22
-       this->info.change_mask = this->info_all;
23
-   if (this->info.change_mask) {
24
-       struct spa_dict_item items7;
25
-       uint32_t i, n_items = 0;
26
-       char latency64, period64, nperiods64, headroom64;
27
-
28
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa");
29
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Source");
30
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
31
-       if (this->have_format) {
32
-           snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate);
33
-           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency);
34
-           snprintf(period, sizeof(period), "%lu", this->period_frames);
35
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period);
36
-           snprintf(nperiods, sizeof(nperiods), "%lu",
37
-                   this->period_frames != 0 ? this->buffer_frames / this->period_frames : 0);
38
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods);
39
-           snprintf(headroom, sizeof(headroom), "%u", this->headroom);
40
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom);
41
-       } else {
42
-           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, NULL);
43
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", NULL);
44
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", NULL);
45
-           itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", NULL);
46
-       }
47
-       this->info.props = &SPA_DICT_INIT(items, n_items);
48
-
49
-       if (this->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
50
-           for (i = 0; i < this->info.n_params; i++) {
51
-               if (this->paramsi.user > 0) {
52
-                   this->paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
53
-                   this->paramsi.user = 0;
54
-               }
55
-           }
56
-       }
57
-       spa_node_emit_info(&this->hooks, &this->info);
58
-       this->info.change_mask = old;
59
-   }
60
-}
61
-
62
-static void emit_port_info(struct state *this, bool full)
63
-{
64
-   uint64_t old = full ? this->port_info.change_mask : 0;
65
-   if (full)
66
-       this->port_info.change_mask = this->port_info_all;
67
-   if (this->port_info.change_mask) {
68
-       uint32_t i;
69
-
70
-       if (this->port_info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
71
-           for (i = 0; i < this->port_info.n_params; i++) {
72
-               if (this->port_paramsi.user > 0) {
73
-                   this->port_paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
74
-                   this->port_paramsi.user = 0;
75
-               }
76
-           }
77
-       }
78
-       spa_node_emit_port_info(&this->hooks,
79
-               SPA_DIRECTION_OUTPUT, 0, &this->port_info);
80
-       this->port_info.change_mask = old;
81
-   }
82
-}
83
-
84
-
85
 static int impl_node_enum_params(void *object, int seq,
86
                 uint32_t id, uint32_t start, uint32_t num,
87
                 const struct spa_pod *filter)
88
@@ -311,8 +242,8 @@
89
            handle_process_latency(this, &info);
90
        }
91
 
92
-       emit_node_info(this, false);
93
-       emit_port_info(this, false);
94
+       spa_alsa_emit_node_info(this, false);
95
+       spa_alsa_emit_port_info(this, false);
96
        break;
97
    }
98
    case SPA_PARAM_ProcessLatency:
99
@@ -325,8 +256,8 @@
100
 
101
        handle_process_latency(this, &info);
102
 
103
-       emit_node_info(this, false);
104
-       emit_port_info(this, false);
105
+       spa_alsa_emit_node_info(this, false);
106
+       spa_alsa_emit_port_info(this, false);
107
        break;
108
    }
109
    default:
110
@@ -388,8 +319,8 @@
111
 
112
    spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
113
 
114
-   emit_node_info(this, true);
115
-   emit_port_info(this, true);
116
+   spa_alsa_emit_node_info(this, true);
117
+   spa_alsa_emit_port_info(this, true);
118
 
119
    spa_hook_list_join(&this->hooks, &save);
120
 
121
@@ -607,7 +538,7 @@
122
    }
123
 
124
    this->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS;
125
-   emit_node_info(this, false);
126
+   spa_alsa_emit_node_info(this, false);
127
 
128
    this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
129
    this->port_info.rate = SPA_FRACTION(1, this->rate);
130
@@ -620,7 +551,7 @@
131
        this->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
132
        this->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
133
    }
134
-   emit_port_info(this, false);
135
+   spa_alsa_emit_port_info(this, false);
136
 
137
    return err;
138
 }
139
@@ -656,7 +587,7 @@
140
        this->latencyinfo.direction = info;
141
        this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
142
        this->port_paramsPORT_Latency.user++;
143
-       emit_port_info(this, false);
144
+       spa_alsa_emit_port_info(this, false);
145
        break;
146
    }
147
    case SPA_PARAM_Tag:
148
@@ -675,7 +606,7 @@
149
 
150
            this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
151
            this->port_paramsPORT_Tag.user++;
152
-           emit_port_info(this, false);
153
+           spa_alsa_emit_port_info(this, false);
154
        }
155
        break;
156
    }
157
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm.c Changed
201
 
1
@@ -13,6 +13,8 @@
2
 #include <spa/utils/result.h>
3
 #include <spa/support/system.h>
4
 #include <spa/utils/keys.h>
5
+#include <spa/node/keys.h>
6
+#include <spa/monitor/device.h>
7
 
8
 #include "alsa-pcm.h"
9
 
10
@@ -184,6 +186,69 @@
11
    return 0;
12
 }
13
 
14
+static struct spa_pod *enum_bind_ctl_propinfo(struct state *state, uint32_t idx, struct spa_pod_builder *b)
15
+{
16
+   char param_name1024;
17
+   char param_desc1024;
18
+   snd_ctl_elem_info_t *info = state->bound_ctlsidx.info;
19
+
20
+   if (!info) {
21
+       // This will end iteration early, so print a warning
22
+       spa_log_warn(state->log, "Don't have prop info for bind ctl, bailing");
23
+       return NULL;
24
+   }
25
+
26
+   snprintf(param_name, sizeof(param_name), "api.alsa.bind-ctl.%s",
27
+           snd_ctl_elem_info_get_name(info));
28
+   snprintf(param_desc, sizeof(param_desc), "Value of ALSA control '%s'",
29
+           snd_ctl_elem_info_get_name(info));
30
+
31
+   // We don't have meaningful default values
32
+   switch (snd_ctl_elem_info_get_type(info)) {
33
+       case SND_CTL_ELEM_TYPE_BOOLEAN:
34
+           return spa_pod_builder_add_object(b,
35
+                   SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
36
+                   SPA_PROP_INFO_name, SPA_POD_String(param_name),
37
+                   SPA_PROP_INFO_description, SPA_POD_String(param_desc),
38
+                   SPA_PROP_INFO_type, SPA_POD_Bool(false),
39
+                   SPA_PROP_INFO_params, SPA_POD_Bool(true));
40
+
41
+       case SND_CTL_ELEM_TYPE_INTEGER:
42
+           return spa_pod_builder_add_object(b,
43
+                   SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
44
+                   SPA_PROP_INFO_name, SPA_POD_String(param_name),
45
+                   SPA_PROP_INFO_description, SPA_POD_String(param_desc),
46
+                   SPA_PROP_INFO_type, SPA_POD_Int(0),
47
+                   SPA_PROP_INFO_params, SPA_POD_Bool(true));
48
+           break;
49
+
50
+       case SND_CTL_ELEM_TYPE_INTEGER64:
51
+           return spa_pod_builder_add_object(b,
52
+                   SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
53
+                   SPA_PROP_INFO_name, SPA_POD_String(param_name),
54
+                   SPA_PROP_INFO_description, SPA_POD_String(param_desc),
55
+                   SPA_PROP_INFO_type, SPA_POD_Long(0),
56
+                   SPA_PROP_INFO_params, SPA_POD_Bool(true));
57
+           break;
58
+
59
+       case SND_CTL_ELEM_TYPE_ENUMERATED:
60
+           return spa_pod_builder_add_object(b,
61
+                   SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
62
+                   SPA_PROP_INFO_name, SPA_POD_String(param_name),
63
+                   SPA_PROP_INFO_description, SPA_POD_String(param_desc),
64
+                   SPA_PROP_INFO_type, SPA_POD_Int(0),
65
+                   SPA_PROP_INFO_params, SPA_POD_Bool(true));
66
+           break;
67
+
68
+       default:
69
+           // FIXME: we can probably support bytes but the length seems unknown in the API
70
+           spa_log_warn(state->log, "%s ctl '%s' not supported",
71
+                   snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info)),
72
+                   snd_ctl_elem_info_get_name(info));
73
+           return NULL;
74
+   }
75
+}
76
+
77
 struct spa_pod *spa_alsa_enum_propinfo(struct state *state,
78
        uint32_t idx, struct spa_pod_builder *b)
79
 {
80
@@ -346,12 +411,67 @@
81
            SPA_PROP_INFO_type, SPA_POD_String(state->clock_name),
82
            SPA_PROP_INFO_params, SPA_POD_Bool(true));
83
        break;
84
+   // While adding params here, update the math in default too
85
    default:
86
-       return NULL;
87
+       idx -= 17;
88
+       if (idx <= state->num_bind_ctls)
89
+           param = enum_bind_ctl_propinfo(state, idx - 1, b);
90
+       else
91
+           return NULL;
92
    }
93
    return param;
94
 }
95
 
96
+static void add_bind_ctl_param(struct state *state, const snd_ctl_elem_value_t *elem, const snd_ctl_elem_info_t *info,
97
+       struct spa_pod_builder *b)
98
+{
99
+   char param_name1024;
100
+
101
+   snprintf(param_name, sizeof(param_name), "api.alsa.bind-ctl.%s",
102
+           snd_ctl_elem_info_get_name(info));
103
+   spa_pod_builder_string(b, param_name);
104
+
105
+   switch (snd_ctl_elem_info_get_type(info)) {
106
+       case SND_CTL_ELEM_TYPE_BOOLEAN:
107
+           spa_pod_builder_bool(b, snd_ctl_elem_value_get_boolean(elem, 0));
108
+           break;
109
+
110
+       case SND_CTL_ELEM_TYPE_INTEGER:
111
+           spa_pod_builder_int(b, snd_ctl_elem_value_get_integer(elem, 0));
112
+           break;
113
+
114
+       case SND_CTL_ELEM_TYPE_INTEGER64:
115
+           spa_pod_builder_long(b, snd_ctl_elem_value_get_integer64(elem, 0));
116
+           break;
117
+
118
+       case SND_CTL_ELEM_TYPE_ENUMERATED:
119
+           spa_pod_builder_int(b, snd_ctl_elem_value_get_enumerated(elem, 0));
120
+           break;
121
+
122
+       default:
123
+           // FIXME: we can probably support bytes but the length seems unknown in the API
124
+           spa_log_warn(state->log, "%s ctl '%s' not supported",
125
+                   snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info)),
126
+                   snd_ctl_elem_info_get_name(info));
127
+           break;
128
+   }
129
+}
130
+
131
+static void add_bind_ctl_params(struct state *state, struct spa_pod_builder *b)
132
+{
133
+   int err;
134
+
135
+   for (unsigned int i = 0; i < state->num_bind_ctls; i++) {
136
+       err = snd_ctl_elem_read(state->ctl, state->bound_ctlsi.value);
137
+       if (err < 0) {
138
+           spa_log_warn(state->log, "Could not read elem value for '%s': %s",
139
+                   state->bound_ctlsi.name, snd_strerror(err));
140
+       }
141
+
142
+       add_bind_ctl_param(state, state->bound_ctlsi.value, state->bound_ctlsi.info, b);
143
+   }
144
+}
145
+
146
 int spa_alsa_add_prop_params(struct state *state, struct spa_pod_builder *b)
147
 {
148
    struct spa_pod_frame f1;
149
@@ -419,6 +539,8 @@
150
    spa_pod_builder_string(b, "clock.name");
151
    spa_pod_builder_string(b, state->clock_name);
152
 
153
+   add_bind_ctl_params(state, b);
154
+
155
    spa_pod_builder_pop(b, &f0);
156
    return 0;
157
 }
158
@@ -498,6 +620,123 @@
159
 {
160
 }
161
 
162
+static void fill_device_name(struct state *state, const char *params, char device_name, size_t len)
163
+{
164
+   spa_scnprintf(device_name, len, "%s%s%s",
165
+           state->card->ucm_prefix ? state->card->ucm_prefix : "",
166
+           state->props.device, params ? params : "");
167
+}
168
+
169
+static void bind_ctl_event(struct spa_source *source)
170
+{
171
+   // We don't know if a bound element changed or not, so let's find out
172
+   struct state *state = source->data;
173
+   snd_ctl_elem_value_t *old_value;
174
+   bool changed = false;
175
+
176
+   snd_ctl_elem_value_alloca(&old_value);
177
+
178
+   for (unsigned int i = 0; i < state->num_bind_ctls; i++) {
179
+       int err;
180
+
181
+       snd_ctl_elem_value_copy(old_value, state->bound_ctlsi.value);
182
+
183
+       err = snd_ctl_elem_read(state->ctl, state->bound_ctlsi.value);
184
+       if (err < 0) {
185
+           spa_log_warn(state->log, "Could not read ctl '%s': %s",
186
+                   state->bound_ctlsi.name, snd_strerror(err));
187
+           continue;
188
+       }
189
+
190
+       if (snd_ctl_elem_value_compare(old_value, state->bound_ctlsi.value) != 0) {
191
+           // We don't need to check all the ctls, if one changed,
192
+           // we'll emit a notification and they'll be read when
193
+           // the props are read
194
+           spa_log_debug(state->log, "bound ctl '%s' has changed", state->bound_ctlsi.name);
195
+           changed = true;
196
+           break;
197
+       }
198
+   }
199
+
200
+   if (changed) {
201
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm.h Changed
45
 
1
@@ -92,6 +92,12 @@
2
    unsigned int following:1;
3
 };
4
 
5
+struct bound_ctl {
6
+   char name256;
7
+   snd_ctl_elem_info_t *info;
8
+   snd_ctl_elem_value_t *value;
9
+};
10
+
11
 struct state {
12
    struct spa_handle handle;
13
    struct spa_node node;
14
@@ -240,11 +246,19 @@
15
 
16
    struct spa_pod *tag2;
17
 
18
-   /* Rate match via an ALSA ctl */
19
+   /* for rate match and bind ctls */
20
    snd_ctl_t *ctl;
21
+
22
+   /* Rate match via an ALSA ctl */
23
    snd_ctl_elem_value_t *pitch_elem;
24
    double last_rate;
25
 
26
+   /* ALSA ctls exposed as params */
27
+   unsigned int num_bind_ctls;
28
+   struct bound_ctl bound_ctls16;
29
+   struct spa_source ctl_sourcesMAX_POLL;
30
+   int ctl_n_fds;
31
+
32
    struct spa_list link;
33
 
34
    struct spa_list followers;
35
@@ -282,6 +296,9 @@
36
 
37
 void spa_alsa_recycle_buffer(struct state *state, uint32_t buffer_id);
38
 
39
+void spa_alsa_emit_node_info(struct state *state, bool full);
40
+void spa_alsa_emit_port_info(struct state *state, bool full);
41
+
42
 static inline uint32_t spa_alsa_format_from_name(const char *name, size_t len)
43
 {
44
    int i;
45
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c Changed
26
 
1
@@ -556,12 +556,13 @@
2
            spa_pod_builder_int(b, 8000);
3
        spa_pod_builder_int(b, 8000);
4
    }
5
-   if (i == 0)
6
-       return -EINVAL;
7
    if (i > 1)
8
        choice->body.type = SPA_CHOICE_Enum;
9
    spa_pod_builder_pop(b, &f1);
10
 
11
+   if (i == 0)
12
+       return -EINVAL;
13
+
14
    res = channels_to_positions(conf.channels, position);
15
    if (res == 0)
16
        return -EINVAL;
17
@@ -674,6 +675,8 @@
18
    if (endpoint_qos->latency >= 0x0005 && endpoint_qos->latency <= 0x0FA0)
19
        /* Values outside the range are RFU */
20
        qos->latency = endpoint_qos->latency;
21
+   if (endpoint_qos->retransmission)
22
+       qos->retransmission = endpoint_qos->retransmission;
23
    if (endpoint_qos->delay_min)
24
        qos->delay = SPA_MAX(qos->delay, endpoint_qos->delay_min);
25
    if (endpoint_qos->delay_max)
26
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/bluez5-dbus.c Changed
36
 
1
@@ -971,6 +971,11 @@
2
            goto error_invalid;
3
        }
4
 
5
+       spa_log_debug(monitor->log, "select qos: interval:%d framing:%d phy:%d sdu:%d "
6
+               "rtn:%d latency:%d delay:%d target_latency:%d",
7
+               qos.interval, qos.framing, qos.phy, qos.sdu, qos.retransmission,
8
+               qos.latency, (int)qos.delay, qos.target_latency);
9
+
10
        dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
11
        dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &entry_key);
12
        dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}", &variant);
13
@@ -3465,6 +3470,9 @@
14
                SPA_BT_PROFILE_BAP_BROADCAST_SINK | SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)))
15
            continue;
16
 
17
+       if (t->device->adapter != transport->device->adapter)
18
+           continue;
19
+
20
        if ((transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) ||
21
            (transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) {
22
            if (t->bap_big != transport->bap_big)
23
@@ -3587,10 +3595,10 @@
24
        /* For broadcast there initiator moves the transport state to SPA_BT_TRANSPORT_STATE_ACTIVE */
25
        if ((transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) ||
26
            (transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE))    {
27
-           spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ACTIVE);
28
+           spa_bt_transport_set_state(t_linked, SPA_BT_TRANSPORT_STATE_ACTIVE);
29
        } else {
30
            if (!transport->bap_initiator)
31
-               spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ACTIVE);
32
+               spa_bt_transport_set_state(t_linked, SPA_BT_TRANSPORT_STATE_ACTIVE);
33
        }
34
    }
35
 
36
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/codec-loader.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/codec-loader.c Changed
10
 
1
@@ -173,7 +173,7 @@
2
 #undef MEDIA_CODEC_FACTORY_LIB
3
    };
4
 
5
-   impl = calloc(sizeof(struct impl), 1);
6
+   impl = calloc(1, sizeof(struct impl));
7
    if (impl == NULL)
8
        return NULL;
9
 
10
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/iso-io.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/iso-io.c Changed
77
 
1
@@ -37,7 +37,7 @@
2
    struct spa_source source;
3
    struct spa_list streams;
4
    int timerfd;
5
-   uint8_t cig;
6
+   uint8_t id;
7
    uint64_t next;
8
    uint64_t duration;
9
    uint32_t paused;
10
@@ -155,7 +155,7 @@
11
    if ((res = spa_system_timerfd_read(group->data_system, group->timerfd, &exp)) < 0) {
12
        if (res != -EAGAIN)
13
            spa_log_warn(group->log, "%p: ISO group:%u error reading timerfd: %s",
14
-                   group, group->cig, spa_strerror(res));
15
+                   group, group->id, spa_strerror(res));
16
        return;
17
    }
18
 
19
@@ -178,7 +178,7 @@
20
 
21
    if (group->paused) {
22
        --group->paused;
23
-       spa_log_debug(group->log, "%p: ISO group:%d paused:%u", group, group->cig, group->paused);
24
+       spa_log_debug(group->log, "%p: ISO group:%u paused:%u", group, group->id, group->paused);
25
    }
26
 
27
    /* Produce output */
28
@@ -194,7 +194,7 @@
29
        }
30
        if (stream->this.size == 0) {
31
            spa_log_debug(group->log, "%p: ISO group:%u miss fd:%d",
32
-                   group, group->cig, stream->fd);
33
+                   group, group->id, stream->fd);
34
            if (stream_silence(stream) < 0) {
35
                fail = true;
36
                continue;
37
@@ -208,7 +208,7 @@
38
        }
39
 
40
        spa_log_trace(group->log, "%p: ISO group:%u sent fd:%d size:%u ts:%u idle:%d res:%d",
41
-               group, group->cig, stream->fd, (unsigned)stream->this.size,
42
+               group, group->id, stream->fd, (unsigned)stream->this.size,
43
                (unsigned)stream->this.timestamp, stream->idle, res);
44
 
45
        stream->this.size = 0;
46
@@ -243,19 +243,29 @@
47
        struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system)
48
 {
49
    struct group *group;
50
+   uint8_t id;
51
 
52
    if (t->bap_interval <= 5000) {
53
        errno = EINVAL;
54
        return NULL;
55
    }
56
 
57
+   if (t->profile & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) {
58
+       id = t->bap_cig;
59
+   } else if (t->profile & (SPA_BT_PROFILE_BAP_BROADCAST_SINK | SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) {
60
+       id = t->bap_big;
61
+   } else {
62
+       errno = EINVAL;
63
+       return NULL;
64
+   }
65
+
66
    group = calloc(1, sizeof(struct group));
67
    if (group == NULL)
68
        return NULL;
69
 
70
    spa_log_topic_init(log, &log_topic);
71
 
72
-   group->cig = t->bap_cig;
73
+   group->id = id;
74
    group->log = log;
75
    group->data_loop = data_loop;
76
    group->data_system = data_system;
77
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/media-sink.c Changed
31
 
1
@@ -1405,6 +1405,21 @@
2
 
3
 static void emit_node_info(struct impl *this, bool full)
4
 {
5
+   char node_group_buf256;
6
+   char *node_group = NULL;
7
+
8
+   if (this->transport && (this->transport->profile & SPA_BT_PROFILE_BAP_SINK)) {
9
+       spa_scnprintf(node_group_buf, sizeof(node_group_buf), "bluez-iso-%s-cig-%d",
10
+               this->transport->device->adapter->address,
11
+               this->transport->bap_cig);
12
+       node_group = node_group_buf;
13
+   } else if (this->transport && (this->transport->profile & SPA_BT_PROFILE_BAP_BROADCAST_SINK)) {
14
+       spa_scnprintf(node_group_buf, sizeof(node_group_buf), "bluez-iso-%s-big-%d",
15
+               this->transport->device->adapter->address,
16
+               this->transport->bap_big);
17
+       node_group = node_group_buf;
18
+   }
19
+
20
    struct spa_dict_item node_info_items = {
21
        { SPA_KEY_DEVICE_API, "bluez5" },
22
        { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Sink/Internal" :
23
@@ -1412,6 +1427,7 @@
24
        { "media.name", ((this->transport && this->transport->device->name) ?
25
                    this->transport->device->name : this->codec->bap ? "BAP" : "A2DP" ) },
26
        { SPA_KEY_NODE_DRIVER, this->is_output ? "true" : "false" },
27
+       { "node.group", node_group },
28
    };
29
    uint64_t old = full ? this->info.change_mask : 0;
30
    if (full)
31
pipewire-0.3.84.tar.gz/spa/plugins/libcamera/libcamera-device.cpp -> pipewire-0.3.85.tar.gz/spa/plugins/libcamera/libcamera-device.cpp Changed
24
 
1
@@ -106,7 +106,7 @@
2
    uint32_t n_items = 0;
3
    struct spa_device_info info;
4
    struct spa_param_info params2;
5
-   char path256, model256, name256, devices_str128;
6
+   char path256, name256, devices_str128;
7
    struct spa_strbuf buf;
8
 
9
    info = SPA_DEVICE_INFO_INIT();
10
@@ -123,9 +123,10 @@
11
    if (auto location = cameraLoc(impl->camera.get()))
12
        ADD_ITEM(SPA_KEY_API_LIBCAMERA_LOCATION, location);
13
 
14
-   snprintf(model, sizeof(model), "%s", cameraModel(impl->camera.get()).c_str());
15
-   ADD_ITEM(SPA_KEY_DEVICE_PRODUCT_NAME, model);
16
-   ADD_ITEM(SPA_KEY_DEVICE_DESCRIPTION, model);
17
+   const auto model = cameraModel(impl->camera.get());
18
+   ADD_ITEM(SPA_KEY_DEVICE_PRODUCT_NAME, model.c_str());
19
+   ADD_ITEM(SPA_KEY_DEVICE_DESCRIPTION, model.c_str());
20
+
21
    snprintf(name, sizeof(name), "libcamera_device.%s", impl->device_id.c_str());
22
    ADD_ITEM(SPA_KEY_DEVICE_NAME, name);
23
 
24
pipewire-0.3.84.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.85.tar.gz/src/daemon/pipewire-pulse.conf.in Changed
10
 
1
@@ -31,6 +31,8 @@
2
             rt.prio      = 65
3
             #rt.time.soft = -1
4
             #rt.time.hard = -1
5
+            #uclamp.min = 0
6
+            #uclamp.max = 1024
7
         }
8
         flags =  ifexists nofail 
9
     }
10
pipewire-0.3.84.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.85.tar.gz/src/daemon/pipewire.conf.in Changed
19
 
1
@@ -90,13 +90,16 @@
2
 
3
     # Uses realtime scheduling to boost the audio thread priorities. This uses
4
     # RTKit if the user doesn't have permission to use regular realtime
5
-    # scheduling.
6
+    # scheduling. You can also clamp utilisation values to improve scheduling
7
+    # on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices.
8
     { name = libpipewire-module-rt
9
         args = {
10
             nice.level    = -11
11
             #rt.prio      = 88
12
             #rt.time.soft = -1
13
             #rt.time.hard = -1
14
+            #uclamp.min = 0
15
+            #uclamp.max = 1024
16
         }
17
         flags =  ifexists nofail 
18
     }
19
pipewire-0.3.84.tar.gz/src/daemon/systemd/system/meson.build -> pipewire-0.3.85.tar.gz/src/daemon/systemd/system/meson.build Changed
10
 
1
@@ -3,7 +3,7 @@
2
   systemd_system_services_dir = get_option('systemd-system-unit-dir')
3
 endif
4
 
5
-install_data(sources : 'pipewire.socket',
6
+install_data(sources : 'pipewire.socket', 'pipewire-manager.socket',
7
              install_dir : systemd_system_services_dir)
8
 
9
 systemd_config = configuration_data()
10
pipewire-0.3.85.tar.gz/src/daemon/systemd/system/pipewire-manager.socket Added
15
 
1
@@ -0,0 +1,13 @@
2
+Unit
3
+Description=PipeWire Multimedia System Manager Socket
4
+
5
+Socket
6
+Service=pipewire.service
7
+Priority=6
8
+ListenStream=%t/pipewire/pipewire-0-manager
9
+SocketUser=pipewire
10
+SocketGroup=pipewire
11
+SocketMode=0600
12
+
13
+Install
14
+WantedBy=sockets.target
15
pipewire-0.3.84.tar.gz/src/daemon/systemd/system/pipewire.service.in -> pipewire-0.3.85.tar.gz/src/daemon/systemd/system/pipewire.service.in Changed
8
 
1
@@ -31,5 +31,5 @@
2
 Environment=PIPEWIRE_RUNTIME_DIR=%t/pipewire
3
 
4
 Install
5
-Also=pipewire.socket
6
+Also=pipewire.socket pipewire-manager.socket
7
 WantedBy=default.target
8
pipewire-0.3.84.tar.gz/src/daemon/systemd/system/pipewire.socket -> pipewire-0.3.85.tar.gz/src/daemon/systemd/system/pipewire.socket Changed
13
 
1
@@ -1,10 +1,9 @@
2
 Unit
3
-Description=PipeWire Multimedia System Sockets
4
+Description=PipeWire Multimedia System Socket
5
 
6
 Socket
7
 Priority=6
8
 ListenStream=%t/pipewire/pipewire-0
9
-ListenStream=%t/pipewire/pipewire-0-manager
10
 SocketUser=pipewire
11
 SocketGroup=pipewire
12
 SocketMode=0660
13
pipewire-0.3.84.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.85.tar.gz/src/gst/gstpipewiresink.c Changed
17
 
1
@@ -532,8 +532,13 @@
2
         pw_stream_trigger_process (pwsink->stream);
3
       break;
4
     case PW_STREAM_STATE_ERROR:
5
-      GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED,
6
-          ("stream error: %s", error), (NULL));
7
+      /* make the error permanent, if it is not already;
8
+         pw_stream_set_error() will recursively call us again */
9
+      if (pw_stream_get_state (pwsink->stream, NULL) != PW_STREAM_STATE_ERROR)
10
+        pw_stream_set_error (pwsink->stream, -EPIPE, "%s", error);
11
+      else
12
+        GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED,
13
+            ("stream error: %s", error), (NULL));
14
       break;
15
   }
16
   pw_thread_loop_signal (pwsink->core->loop, FALSE);
17
pipewire-0.3.84.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.85.tar.gz/src/gst/gstpipewiresrc.c Changed
18
 
1
@@ -681,9 +681,13 @@
2
     case PW_STREAM_STATE_STREAMING:
3
       break;
4
     case PW_STREAM_STATE_ERROR:
5
-      pw_stream_set_error (pwsrc->stream, -EPIPE, "%s", error);
6
-      GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED,
7
-          ("stream error: %s", error), (NULL));
8
+      /* make the error permanent, if it is not already;
9
+         pw_stream_set_error() will recursively call us again */
10
+      if (pw_stream_get_state (pwsrc->stream, NULL) != PW_STREAM_STATE_ERROR)
11
+        pw_stream_set_error (pwsrc->stream, -EPIPE, "%s", error);
12
+      else
13
+        GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED,
14
+            ("stream error: %s", error), (NULL));
15
       break;
16
   }
17
   pw_thread_loop_signal (pwsrc->core->loop, FALSE);
18
pipewire-0.3.84.tar.gz/src/modules/meson.build -> pipewire-0.3.85.tar.gz/src/modules/meson.build Changed
13
 
1
@@ -218,8 +218,10 @@
2
 summary({'ffado-driver': build_module_ffado_driver}, bool_yn: true, section: 'Optional Modules')
3
 
4
 opus_custom_h = cc.has_header('opus/opus_custom.h', dependencies: opus_dep)
5
+opus_custom_lib = cc.has_function('opus_custom_encoder_ctl', dependencies: opus_dep)
6
+
7
 # One would imagine that opus_dep is a requirement but for some reason it's not, so we need to manually check that
8
-if opus_dep.found() and opus_custom_h
9
+if opus_dep.found() and opus_custom_h and opus_custom_lib
10
   opus_custom_dep = declare_dependency(compile_args: '-DHAVE_OPUS_CUSTOM', dependencies: opus_dep)
11
 else
12
   opus_custom_dep = dependency('', required: false)
13
pipewire-0.3.84.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.85.tar.gz/src/modules/module-pipe-tunnel.c Changed
169
 
1
@@ -40,6 +40,7 @@
2
  * ## Module Options
3
  *
4
  * - `tunnel.mode`: the desired tunnel to create. (Default `playback`)
5
+ * - `tunnel.may-pause`: if the tunnel stream is allowed to pause on xrun
6
  * - `pipe.filename`: the filename of the pipe.
7
  * - `stream.props`: Extra properties for the local stream.
8
  *
9
@@ -55,6 +56,12 @@
10
  * When `tunnel.mode` is `source`, a source node is created. Samples read from
11
  * the the pipe will be made available on the source.
12
  *
13
+ * `tunnel.may-pause` allows the tunnel stream to become inactive (paused) when
14
+ * there is no data in the fifo or when the fifo is full. For `capture` and
15
+ * `playback` `tunnel.mode` this is by default true. For `source` and `sink`
16
+ * `tunnel.mode`, this is by default false. A paused stream will consume no
17
+ * CPU and will resume when the fifo becomes readable or writable again.
18
+ *
19
  * When `pipe.filename` is not given, a default fifo in `/tmp/fifo_input` or
20
  * `/tmp/fifo_output` will be created that can be written and read respectively,
21
  * depending on the selected `tunnel.mode`.
22
@@ -86,6 +93,7 @@
23
  * {   name = libpipewire-module-pipe-tunnel
24
  *     args = {
25
  *         tunnel.mode = playback
26
+ *         #tunnel.may-pause = true
27
  *         # Set the pipe name to tunnel to
28
  *         pipe.filename = "/tmp/fifo_output"
29
  *         #audio.format=<sample format>
30
@@ -128,6 +136,7 @@
31
            "( audio.channels=<number of channels> ) "      \
32
            "( audio.position=<channel map> ) "         \
33
            "( tunnel.mode=capture|playback|sink|source )"      \
34
+           "( tunnel.may-pause=<bool, if the stream can pause> )"  \
35
            "( pipe.filename=<filename> )"              \
36
            "( stream.props=<properties> ) "
37
 
38
@@ -141,6 +150,7 @@
39
 
40
 struct impl {
41
    struct pw_context *context;
42
+   struct pw_loop *main_loop;
43
    struct pw_loop *data_loop;
44
 
45
 #define MODE_PLAYBACK  0
46
@@ -174,6 +184,8 @@
47
    unsigned int do_disconnect:1;
48
    unsigned int driving:1;
49
    unsigned int have_sync:1;
50
+   unsigned int may_pause:1;
51
+   unsigned int paused:1;
52
 
53
    struct spa_ringbuffer ring;
54
    void *buffer;
55
@@ -262,7 +274,7 @@
56
        break;
57
    case PW_STREAM_STATE_PAUSED:
58
        if (impl->direction == PW_DIRECTION_OUTPUT) {
59
-           pw_loop_update_io(impl->data_loop, impl->socket, 0);
60
+           pw_loop_update_io(impl->data_loop, impl->socket, impl->paused ? SPA_IO_IN : 0);
61
            set_timeout(impl, 0);
62
        }
63
        break;
64
@@ -281,6 +293,26 @@
65
    }
66
 }
67
 
68
+static int do_pause(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
69
+       size_t size, void *user_data)
70
+{
71
+   struct impl *impl = user_data;
72
+   const bool *paused = data;
73
+   pw_log_info("set paused: %d", *paused);
74
+   impl->paused = *paused;
75
+   pw_stream_set_active(impl->stream, !*paused);
76
+   return 0;
77
+}
78
+
79
+static void pause_stream(struct impl *impl, bool paused)
80
+{
81
+   if (!impl->may_pause)
82
+       return;
83
+   if (impl->direction == PW_DIRECTION_INPUT)
84
+       pw_loop_update_io(impl->data_loop, impl->socket, paused ? SPA_IO_OUT : 0);
85
+   pw_loop_invoke(impl->main_loop, do_pause, 1, &paused, sizeof(bool), false, impl);
86
+}
87
+
88
 static void playback_stream_process(void *data)
89
 {
90
    struct impl *impl = data;
91
@@ -308,8 +340,8 @@
92
                    continue;
93
                } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
94
                    /* Don't continue writing */
95
-                   pw_log_debug("pipe (%s) overrun: %m",
96
-                           impl->filename);
97
+                   pw_log_debug("pipe (%s) overrun: %m", impl->filename);
98
+                   pause_stream(impl, true);
99
                    break;
100
                } else {
101
                    pw_log_warn("Failed to write to pipe (%s): %m",
102
@@ -370,8 +402,10 @@
103
 
104
    if (avail < (int32_t)size) {
105
        memset(bd->data, 0, size);
106
-       if (avail > 0)
107
+       if (avail >= 0) {
108
            pw_log_warn("underrun %d < %u", avail, size);
109
+           pause_stream(impl, true);
110
+       }
111
        impl->have_sync = false;
112
    }
113
    if (avail > (int32_t)RINGBUFFER_SIZE) {
114
@@ -456,6 +490,8 @@
115
    paramsn_params++ = spa_format_audio_raw_build(&b,
116
            SPA_PARAM_EnumFormat, &impl->info);
117
 
118
+   impl->paused = false;
119
+
120
    if ((res = pw_stream_connect(impl->stream,
121
            impl->direction,
122
            PW_ID_ANY,
123
@@ -550,6 +586,8 @@
124
        pw_loop_update_io(impl->data_loop, impl->socket, 0);
125
        return;
126
    }
127
+   if (impl->paused)
128
+       pause_stream(impl, false);
129
    if (mask & SPA_IO_IN)
130
        handle_pipe_read(impl);
131
 }
132
@@ -839,6 +877,7 @@
133
 
134
    impl->module = module;
135
    impl->context = context;
136
+   impl->main_loop = pw_context_get_main_loop(context);
137
    data_loop = pw_context_get_data_loop(context);
138
    impl->data_loop = pw_data_loop_get_loop(data_loop);
139
 
140
@@ -848,22 +887,28 @@
141
    if (spa_streq(str, "capture")) {
142
        impl->mode = MODE_CAPTURE;
143
        impl->direction = PW_DIRECTION_INPUT;
144
+       impl->may_pause = true;
145
    } else if (spa_streq(str, "playback")) {
146
        impl->mode = MODE_PLAYBACK;
147
        impl->direction = PW_DIRECTION_OUTPUT;
148
+       impl->may_pause = true;
149
    }else if (spa_streq(str, "sink")) {
150
        impl->mode = MODE_SINK;
151
        impl->direction = PW_DIRECTION_INPUT;
152
+       impl->may_pause = false;
153
        media_class = "Audio/Sink";
154
    } else if (spa_streq(str, "source")) {
155
        impl->mode = MODE_SOURCE;
156
        impl->direction = PW_DIRECTION_OUTPUT;
157
+       impl->may_pause = false;
158
        media_class = "Audio/Source";
159
    } else {
160
        pw_log_error("invalid tunnel.mode '%s'", str);
161
        res = -EINVAL;
162
        goto error;
163
    }
164
+   if ((str = pw_properties_get(props, "tunnel.may-pause")) != NULL)
165
+       impl->may_pause = spa_atob(str);
166
 
167
    if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
168
        pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
169
pipewire-0.3.84.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.85.tar.gz/src/modules/module-protocol-native.c Changed
17
 
1
@@ -1489,6 +1489,7 @@
2
 {
3
    struct pw_core *core = proxy->core;
4
    struct client *impl = SPA_CONTAINER_OF(core->conn, struct client, this);
5
+   ensure_loop(impl->context->main_loop);
6
    assert_single_pod(builder);
7
    marshal_core_footers(&impl->footer_state, core, builder);
8
    return core->send_seq = pw_protocol_native_connection_end(impl->connection, builder);
9
@@ -1518,6 +1519,7 @@
10
 {
11
    struct client_data *data = resource->client->user_data;
12
    struct pw_impl_client *client = resource->client;
13
+   ensure_loop(client->context->main_loop);
14
    assert_single_pod(builder);
15
    marshal_client_footers(&data->footer_state, client, builder);
16
    return client->send_seq = pw_protocol_native_connection_end(data->connection, builder);
17
pipewire-0.3.84.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.85.tar.gz/src/modules/module-raop-sink.c Changed
18
 
1
@@ -1854,6 +1854,8 @@
2
    if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
3
        pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.%s",
4
                hostname, ip, port);
5
+   if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL)
6
+       pw_properties_setf(props, PW_KEY_MEDIA_NAME, "RAOP to %s", name);
7
    if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
8
        pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s", name);
9
    if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL)
10
@@ -1891,6 +1893,7 @@
11
    copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
12
    copy_props(impl, props, PW_KEY_MEDIA_CLASS);
13
    copy_props(impl, props, PW_KEY_MEDIA_FORMAT);
14
+   copy_props(impl, props, PW_KEY_MEDIA_NAME);
15
    copy_props(impl, props, "net.mtu");
16
    copy_props(impl, props, "rtp.sender-ts-offset");
17
    copy_props(impl, props, "sess.media");
18
pipewire-0.3.84.tar.gz/src/modules/module-rt.c -> pipewire-0.3.85.tar.gz/src/modules/module-rt.c Changed
186
 
1
@@ -82,6 +82,8 @@
2
  * - `rlimits.enabled`: enable the use of rtlimits, default true.
3
  * - `rtportal.enabled`: enable the use of realtime portal, default true
4
  * - `rtkit.enabled`: enable the use of rtkit, default true
5
+ * - `uclamp.min`: the minimum utilisation value the scheduler should consider
6
+ * - `uclamp.max`: the maximum utilisation value the scheduler should consider
7
 
8
  * The nice level is by default set to an invalid value so that clients don't
9
  * automatically have the nice level raised.
10
@@ -101,6 +103,8 @@
11
  *         #rlimits.enabled = true
12
  *         #rtportal.enabled = true
13
  *         #rtkit.enabled = true
14
+ *         #uclamp.min = 0
15
+ *         #uclamp.max = 1024
16
  *     }
17
  *     flags =  ifexists nofail 
18
  * }
19
@@ -131,13 +135,18 @@
20
 #define DEFAULT_RT_TIME_SOFT   -1
21
 #define DEFAULT_RT_TIME_HARD   -1
22
 
23
+#define DEFAULT_UCLAMP_MIN      0
24
+#define DEFAULT_UCLAMP_MAX      1024
25
+
26
 #define MODULE_USAGE   "( nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL)"(don't change)> ) " \
27
            "( rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO)"> ) "     \
28
            "( rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"> ) "    \
29
            "( rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"> ) "    \
30
            "( rlimits.enabled=<default true> ) " \
31
            "( rtportal.enabled=<default true> ) " \
32
-           "( rtkit.enabled=<default true> ) "
33
+           "( rtkit.enabled=<default true> ) " \
34
+           "( uclamp.min=<default "SPA_STRINGIFY(DEFAULT_UCLAMP_MIN)"> ) " \
35
+           "( uclamp.max=<default "SPA_STRINGIFY(DEFAULT_UCLAMP_MAX)"> )"
36
 
37
 static const struct spa_dict_item module_props = {
38
    { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
39
@@ -183,6 +192,9 @@
40
    rlim_t rt_time_soft;
41
    rlim_t rt_time_hard;
42
 
43
+   int uclamp_min;
44
+   int uclamp_max;
45
+
46
    struct spa_hook module_listener;
47
 
48
    unsigned rlimits_enabled:1;
49
@@ -537,6 +549,8 @@
50
    int err, old_policy, new_policy, min, max;
51
    struct sched_param old_sched_params;
52
    struct sched_param new_sched_params;
53
+   struct rlimit old_rlim;
54
+   struct rlimit no_rlim = { -1, -1 };
55
    int try = 0;
56
 
57
    if (!impl->rlimits_enabled)
58
@@ -584,11 +598,21 @@
59
        if ((old_policy & PW_SCHED_RESET_ON_FORK) != 0)
60
            new_policy |= PW_SCHED_RESET_ON_FORK;
61
 
62
+       /* Disable RLIMIT_RTTIME while trying new_policy. */
63
+       if ((err = getrlimit(RLIMIT_RTTIME, &old_rlim)) < 0)
64
+           pw_log_debug("getrlimit() failed: %s", spa_strerror(err));
65
+       if ((err = setrlimit(RLIMIT_RTTIME, &no_rlim)) < 0)
66
+           pw_log_debug("setrlimit() failed: %s", spa_strerror(err));
67
+
68
        if (pthread_setschedparam(pthread_self(), new_policy, &new_sched_params) == 0) {
69
            impl->rt_prio = new_sched_params.sched_priority;
70
            pthread_setschedparam(pthread_self(), old_policy, &old_sched_params);
71
+           if ((err = setrlimit(RLIMIT_RTTIME, &old_rlim)) < 0)
72
+               pw_log_debug("setrlimit() failed: %s", spa_strerror(err));
73
            return true;
74
        }
75
+       if ((err = setrlimit(RLIMIT_RTTIME, &old_rlim)) < 0)
76
+           pw_log_debug("setrlimit() failed: %s", spa_strerror(err));
77
    }
78
    pw_log_info("Can't set rt prio to %d: %m (try increasing rlimits)", (int)priority);
79
    return false;
80
@@ -636,18 +660,18 @@
81
    return res;
82
 }
83
 
84
-static int set_rlimit(struct impl *impl)
85
+static int set_rlimit(struct rlimit *rlim)
86
 {
87
    int res = 0;
88
 
89
-   if (setrlimit(RLIMIT_RTTIME, &impl->rl) < 0)
90
+   if (setrlimit(RLIMIT_RTTIME, rlim) < 0)
91
        res = -errno;
92
 
93
    if (res < 0)
94
        pw_log_debug("setrlimit() failed: %s", spa_strerror(res));
95
    else
96
        pw_log_debug("rt.time.soft:%"PRIi64" rt.time.hard:%"PRIi64,
97
-               (int64_t)impl->rl.rlim_cur, (int64_t)impl->rl.rlim_max);
98
+               (int64_t)rlim->rlim_cur, (int64_t)rlim->rlim_max);
99
 
100
    return res;
101
 }
102
@@ -1011,12 +1035,56 @@
103
    impl->rl.rlim_cur = SPA_MIN(impl->rl.rlim_cur, impl->rttime_max);
104
    impl->rl.rlim_max = SPA_MIN(impl->rl.rlim_max, impl->rttime_max);
105
 
106
-   set_rlimit(impl);
107
+   set_rlimit(&impl->rl);
108
 
109
    return 0;
110
 }
111
 #endif /* HAVE_DBUS */
112
 
113
+int set_uclamp(int uclamp_min, int uclamp_max, pid_t pid) {
114
+#ifdef __linux__
115
+   int ret;
116
+   struct sched_attr {
117
+       uint32_t size;
118
+       uint32_t sched_policy;
119
+       uint64_t sched_flags;
120
+       int32_t sched_nice;
121
+       uint32_t sched_priority;
122
+       uint64_t sched_runtime;
123
+       uint64_t sched_deadline;
124
+       uint64_t sched_period;
125
+       uint32_t sched_util_min;
126
+       uint32_t sched_util_max;
127
+   } attr;
128
+
129
+   ret = syscall(SYS_sched_getattr, pid, &attr, sizeof(struct sched_attr), 0);
130
+   if (ret) {
131
+       pw_log_warn("Could not retrieve scheduler attributes: %d", -errno);
132
+       return -errno;
133
+   }
134
+
135
+   /* SCHED_FLAG_KEEP_POLICY |
136
+    * SCHED_FLAG_KEEP_PARAMS |
137
+    * SCHED_FLAG_UTIL_CLAMP_MIN |
138
+    * SCHED_FLAG_UTIL_CLAMP_MAX */
139
+   attr.sched_flags = 0x8 | 0x10 | 0x20 | 0x40;
140
+   attr.sched_util_min = uclamp_min;
141
+   attr.sched_util_max = uclamp_max;
142
+
143
+   ret = syscall(SYS_sched_setattr, pid, &attr, 0);
144
+
145
+   if (ret) {
146
+       pw_log_warn("Could not set scheduler attributes: %d", -errno);
147
+       return -errno;
148
+   }
149
+   return 0;
150
+#else
151
+   pw_log_warn("Setting UCLAMP values is only supported on Linux");
152
+   return -EOPNOTSUPP;
153
+#endif /* __linux__ */
154
+}
155
+
156
+
157
 SPA_EXPORT
158
 int pipewire__module_init(struct pw_impl_module *module, const char *args)
159
 {
160
@@ -1047,6 +1115,8 @@
161
    impl->rlimits_enabled = pw_properties_get_bool(props, "rlimits.enabled", true);
162
    impl->rtportal_enabled = pw_properties_get_bool(props, "rtportal.enabled", true);
163
    impl->rtkit_enabled = pw_properties_get_bool(props, "rtkit.enabled", true);
164
+   impl->uclamp_min = pw_properties_get_int32(props, "uclamp.min", DEFAULT_UCLAMP_MIN);
165
+   impl->uclamp_max = pw_properties_get_int32(props, "uclamp.max", DEFAULT_UCLAMP_MAX);
166
 
167
    impl->rl.rlim_cur = impl->rt_time_soft;
168
    impl->rl.rlim_max = impl->rt_time_hard;
169
@@ -1086,7 +1156,15 @@
170
            use_rtkit = can_use_rtkit;
171
    }
172
    if (!use_rtkit)
173
-       set_rlimit(impl);
174
+       set_rlimit(&impl->rl);
175
+
176
+   if (impl->uclamp_max > 1024) {
177
+       pw_log_warn("uclamp.max out of bounds. Got %d, clamping to 1024.", impl->uclamp_max);
178
+       impl->uclamp_max = 1024;
179
+   }
180
+
181
+   if (impl->uclamp_min || impl->uclamp_max < 1024)
182
+       set_uclamp(impl->uclamp_min, impl->uclamp_max, impl->main_pid);
183
 
184
 #ifdef HAVE_DBUS
185
    impl->use_rtkit = use_rtkit;
186
pipewire-0.3.84.tar.gz/src/pipewire/context.c -> pipewire-0.3.85.tar.gz/src/pipewire/context.c Changed
77
 
1
@@ -32,6 +32,8 @@
2
 PW_LOG_TOPIC_EXTERN(log_context);
3
 #define PW_LOG_TOPIC_DEFAULT log_context
4
 
5
+#define MAX_HOPS   64
6
+
7
 /** \cond */
8
 struct impl {
9
    struct pw_context this;
10
@@ -791,12 +793,17 @@
11
  * and groups to active nodes and make them recursively runnable as well.
12
  */
13
 static inline int run_nodes(struct pw_context *context, struct pw_impl_node *node,
14
-       struct spa_list *nodes, enum pw_direction direction)
15
+       struct spa_list *nodes, enum pw_direction direction, int hop)
16
 {
17
    struct pw_impl_node *t;
18
    struct pw_impl_port *p;
19
    struct pw_impl_link *l;
20
 
21
+   if (hop == MAX_HOPS) {
22
+       pw_log_warn("exceeded hops (%d)", hop);
23
+       return -EIO;
24
+   }
25
+
26
    pw_log_debug("node %p: '%s' direction:%s", node, node->name,
27
            pw_direction_as_string(direction));
28
 
29
@@ -810,10 +817,12 @@
30
                if (!t->active || !l->prepared ||
31
                    (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction)))
32
                    continue;
33
+               if (t->driving && p->node == t)
34
+                   continue;
35
 
36
                pw_log_debug("  peer %p: '%s'", t, t->name);
37
                t->runnable = true;
38
-               run_nodes(context, t, nodes, direction);
39
+               run_nodes(context, t, nodes, direction, hop + 1);
40
            }
41
        }
42
    } else {
43
@@ -824,10 +833,12 @@
44
                if (!t->active || !l->prepared ||
45
                    (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction)))
46
                    continue;
47
+               if (t->driving && p->node == t)
48
+                   continue;
49
 
50
                pw_log_debug("  peer %p: '%s'", t, t->name);
51
                t->runnable = true;
52
-               run_nodes(context, t, nodes, direction);
53
+               run_nodes(context, t, nodes, direction, hop + 1);
54
            }
55
        }
56
    }
57
@@ -847,7 +858,7 @@
58
            pw_log_debug("  group %p: '%s'", t, t->name);
59
            t->runnable = true;
60
            if (!t->driving)
61
-               run_nodes(context, t, nodes, direction);
62
+               run_nodes(context, t, nodes, direction, hop + 1);
63
        }
64
    }
65
    return 0;
66
@@ -950,8 +961,8 @@
67
    }
68
    spa_list_for_each(n, collect, sort_link)
69
        if (!n->driving && n->runnable) {
70
-           run_nodes(context, n, collect, PW_DIRECTION_OUTPUT);
71
-           run_nodes(context, n, collect, PW_DIRECTION_INPUT);
72
+           run_nodes(context, n, collect, PW_DIRECTION_OUTPUT, 0);
73
+           run_nodes(context, n, collect, PW_DIRECTION_INPUT, 0);
74
        }
75
 
76
    return 0;
77
pipewire-0.3.84.tar.gz/src/pipewire/impl-client.h -> pipewire-0.3.85.tar.gz/src/pipewire/impl-client.h Changed
19
 
1
@@ -13,6 +13,8 @@
2
 
3
 /** \page page_client_impl Client Implementation
4
  *
5
+ * \see \ref pw_impl_client
6
+ *
7
  * \section sec_page_client_impl_overview Overview
8
  *
9
  * The \ref pw_impl_client object is created by a protocol implementation when
10
@@ -51,7 +53,7 @@
11
  * Each client has its own list of resources it is bound to along with
12
  * a mapping between the client types and server types.
13
  *
14
- * See: \ref page_client_impl
15
+ * \see \ref page_client_impl
16
  */
17
 
18
 /**
19
pipewire-0.3.84.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.85.tar.gz/src/pipewire/impl-link.c Changed
16
 
1
@@ -884,9 +884,11 @@
2
 
3
    impl->activated = false;
4
    pw_log_info("(%s) deactivated", this->name);
5
-   link_update_state(this, this->destroyed ?
6
-           PW_LINK_STATE_INIT : PW_LINK_STATE_PAUSED,
7
-           0, NULL);
8
+   
9
+   if (this->info.state < PW_LINK_STATE_PAUSED || this->destroyed)
10
+       link_update_state(this, PW_LINK_STATE_INIT, 0, NULL);
11
+   else
12
+       link_update_state(this, PW_LINK_STATE_PAUSED, 0, NULL);
13
    return 0;
14
 }
15
 
16
pipewire-0.3.84.tar.gz/src/pipewire/proxy.h -> pipewire-0.3.85.tar.gz/src/pipewire/proxy.h Changed
19
 
1
@@ -13,6 +13,8 @@
2
 
3
 /** \page page_proxy Proxy
4
  *
5
+ * \see \ref pw_proxy
6
+ *
7
  * \section sec_page_proxy_overview Overview
8
  *
9
  * The proxy object is a client side representation of a resource
10
@@ -76,7 +78,7 @@
11
  * invoked by the client to PipeWire messages. Events will call the handlers
12
  * set in listener.
13
  *
14
- * See \ref page_proxy
15
+ * \see \ref page_proxy
16
  */
17
 
18
 /**
19
pipewire-0.3.84.tar.gz/src/pipewire/stream.h -> pipewire-0.3.85.tar.gz/src/pipewire/stream.h Changed
19
 
1
@@ -11,6 +11,8 @@
2
 
3
 /** \page page_streams Streams
4
  *
5
+ * \see \ref pw_stream
6
+ *
7
  * \section sec_overview Overview
8
  *
9
  * \ref pw_stream "Streams" are used to exchange data with the
10
@@ -162,7 +164,7 @@
11
  * The stream object provides a convenient way to send and
12
  * receive data streams from/to PipeWire.
13
  *
14
- * See also \ref page_streams and \ref api_pw_core
15
+ * \see \ref page_streams, \ref api_pw_core
16
  */
17
 
18
 /**
19
pipewire-0.3.84.tar.gz/src/pipewire/thread-loop.h -> pipewire-0.3.85.tar.gz/src/pipewire/thread-loop.h Changed
19
 
1
@@ -13,6 +13,8 @@
2
 
3
 /** \page page_thread_loop Thread Loop
4
  *
5
+ * \see \ref pw_thread_loop
6
+ *
7
  * \section sec_thread_loop_overview Overview
8
  *
9
  * The threaded loop implementation is a special wrapper around the
10
@@ -68,7 +70,7 @@
11
  * All of the loop callbacks will be executed with the loop
12
  * lock held.
13
  *
14
- * See also \ref page_thread_loop
15
+ * \see \ref page_thread_loop
16
  */
17
 
18
 /**
19
pipewire-0.3.84.tar.gz/src/pipewire/utils.c -> pipewire-0.3.85.tar.gz/src/pipewire/utils.c Changed
10
 
1
@@ -162,7 +162,7 @@
2
  * \since 0.3.84
3
  */
4
 SPA_EXPORT
5
-int pw_strv_find(char **a, char *b)
6
+int pw_strv_find(char **a, const char *b)
7
 {
8
    int i;
9
    if (a == NULL || b == NULL)
10
pipewire-0.3.84.tar.gz/src/pipewire/utils.h -> pipewire-0.3.85.tar.gz/src/pipewire/utils.h Changed
10
 
1
@@ -48,7 +48,7 @@
2
 
3
 char **pw_strv_parse(const char *val, size_t len, int max_tokens, int *n_tokens);
4
 
5
-int pw_strv_find(char **a, char *b);
6
+int pw_strv_find(char **a, const char *b);
7
 
8
 int pw_strv_find_common(char **a, char **b);
9
 
10
pipewire-0.3.84.tar.gz/src/tools/pw-top.c -> pipewire-0.3.85.tar.gz/src/tools/pw-top.c Changed
10
 
1
@@ -282,7 +282,7 @@
2
 }
3
 
4
 static const struct pw_node_events node_events = {
5
-   PW_VERSION_NODE,
6
+   PW_VERSION_NODE_EVENTS,
7
    .info = node_info,
8
    .param = node_param,
9
 };
10