We truncated the diff of some files because they were too big.
If you want to see the full diff for every file, click here.
Changes of Revision 28
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Sat May 20 12:08:17 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.71
6
+
7
+-------------------------------------------------------------------
8
Sun May 14 10:53:41 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.70
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.70
6
+Version: 0.3.71
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.70.tar.gz/NEWS -> pipewire-0.3.71.tar.gz/NEWS
Changed
160
1
2
+# PipeWire 0.3.71 (2023-05-17)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - A new zero-latency jackdbus bridge was added. This works similar to what
9
+ PulseAudio has to offer and creates a sink/source when jackdbus is
10
+ started. It is however much more efficient and runs the complete PipeWire
11
+ graph as a synchronous JACK client with no added latency.
12
+ - Many performance improvements. Activation of remote nodes is more
13
+ efficient, fewer eventfds are required on the clients, less callback
14
+ overhead in performence critical paths and an optimized poll function
15
+ was added. This was mainly driven by the jackdbus module to get the lowest
16
+ possible overhead when running the graph.
17
+ - The JACK notify callback implementation was reworked to emulate better what
18
+ JACK does, improving compatibility with ardour7 and the JACK stress test.
19
+ - More work on BAP devices. Device latency is now passed on to
20
+ applications also for multi-device headsets, and channel allocation
21
+ is handled better.
22
+ - Many more improvements and bugfixes.
23
+
24
+
25
+## PipeWire
26
+ - Remove the hardcoded limit on io_areas. This is used to link nodes together
27
+ and exchange buffers, it was limited to 2048 but now dynamically scales
28
+ based on requirements.
29
+ - Rate and quantum changes are now applied correctly in more cases. (#3159)
30
+ - Updates to client-node to more efficiently process the driver.
31
+ - The profiler information was improved to be more accurate. It should
32
+ now work better for remote drivers.
33
+ - Some potential memory map errors were fixed in the protocol because in some
34
+ case with large messages, some fds were closed too soon.
35
+ - pw-filter now implements the pw_filter_set_active() method.
36
+ - A potential out-of-buffers case was fixed in capture pw-streams where buffers
37
+ were not moved to the recycle queue when the node suspended.
38
+ - Nodes are now always woken up with the eventfd. Previously there were
39
+ some optimiztions in the server to directly call into the node process
40
+ function but that optimization is not necessary. Without this optimization
41
+ it is now possible to run nodes in different threads.
42
+ - pw-stream trigger is now implemented correctly in all cases.
43
+ - Remote nodes now use one eventfd less because they get triggered with the
44
+ node eventfd directly.
45
+ - Monitor ports are now ignored in latency updates.
46
+ - A potential race when reporting an error to a client was fixed. (#3192)
47
+ - Fix a bug where always_process nodes would sometimes IDLE. (#3189)
48
+ - Optimize peer activation. Nodes are now activated more efficiently and
49
+ independent of the number of links. It also reduces the number of eventfds
50
+ and memory in remote clients.
51
+ - A bug in property serialization was fixed. Values with spaces would only
52
+ serialize the first part of the value.
53
+
54
+## Modules
55
+ - Correctly handle the echo-canceler plugin init method fallback. The
56
+ samplerate was not correctly configured. This is only a regression for people
57
+ that have external echo-canceler plugins.
58
+ - RAOP sink now only sets the volume on the remote end when the stream is
59
+ recording. (#3175)
60
+ - RAOP discover now tries to deduplicate entries from the same host.
61
+ - A new zero-latency jackdbus bridge was added. This works similar to what
62
+ pulseaudio has to offer and creates a sink/source when jackdbus is
63
+ started. It is however much more efficient and runs the complete PipeWire
64
+ graph as a synchronous JACK client.
65
+ - The access module uses a more secure way to check the application
66
+ executable.
67
+ - module-combine-stream now has configurable delay and latency for each
68
+ stream. This can be used to align sinks/sources with different latencies.
69
+ - A potential crash in module-pulse-tunnel was fixed when shutting down.
70
+ (#3199)
71
+ - Module-rt will now clamp the nice value to the min allowed value to avoid
72
+ errors from rtkit. (#3186)
73
+ - Fix a bug with the session counters in module-rtp-sap. Also use the right
74
+ format for L24. Improve the AES67 example config.
75
+ - Improve some warning and info messages in module-rt. (#3194)
76
+ - module-rtp-session should now do something when started without arguments.
77
+ - A potential crash in module-rtp-session was fixed. (#3217)
78
+ - module-filter-chain has better error reporting when a convolver fails to
79
+ load. (#3223)
80
+
81
+## SPA
82
+ - Move some things around to avoid compiler warnings. (#3171)
83
+ - Increase mixer ports. Reorganize some things and bump mixer input ports
84
+ from 128 to 512.
85
+ - Fix a potential crash when a node is scheduled before it completes
86
+ the setup.
87
+ - The JACK sink and source SPA plugins have seen some improvements.
88
+ - Allow the peaks resampler still if we disabled resampling.
89
+ - Perform more cleanup in audioadapter when in error.
90
+ - An optimized non-cancellable loop implementation was added.
91
+ - Callbacks were optimized with a _fast() varsion that doesn't check the
92
+ version and method. When this check is performed earlier, it can
93
+ be skipped in performance critical places.
94
+ - Some of the callbacks and system methods are now using the fast function
95
+ calls in critical paths.
96
+ - A potential division by zero was fixed in the ALSA plugins.
97
+ - Improve rate and quantum when starting audioconvert.
98
+ - Make it possible to override node.driver in the SPA null-audio-driver.
99
+ (#3220)
100
+
101
+## pulse-server
102
+ - The audio info parameter parsing was refactored and improved.
103
+ - Fix some races with clients exiting when playing samples.
104
+ - An option was added to change or disable the dbus name registration.
105
+ (#2987)
106
+
107
+## Bluetooth
108
+ - Implement battery reporting using AT+XEVENT.
109
+ - Disable hardware volume for 3M WorkTunes.
110
+ - Implement BAP audio locations (channel positions) by using the new
111
+ bluez properties.
112
+
113
+## JACK
114
+ - Fix some errors reported by JACK test.cpp. (#2638)
115
+ - Add jack.show-midi option to show/hide midi ports.
116
+ - Add jack.max-client-ports option. JACK also has a port limit and so
117
+ PipeWire needs it as well to make the tests happy.
118
+ - Call the shutdown callback only when the server stopped, not when there
119
+ is a random error. (#3070)
120
+ - Avoid registering the same port name twice.
121
+ - Call port registration callbacks in activate/deactivate.
122
+ - Improve jack_port_connected().
123
+ - Improve some error reporting.
124
+ - The JACK headers were updated to a newer version.
125
+ - JACK callbacks are now managed with an event queue to simulate
126
+ more what JACK does. This avoids emiting callbacks when a method is blocking
127
+ for a reply and causing deadlocks. (#3183)
128
+ - Assign unique names to JACK clients. (#2833)
129
+ - Fix a potential crash when the thread_utils was used after free.
130
+ - Aliases are now not filled in by default to improve JACK compatibility.
131
+ (#3154)
132
+
133
+# ALSA
134
+ - The ALSA plugin will now wait for negotiation to complete or an error
135
+ before _prepare() completes. This makes more applications deal correctly
136
+ with the potential errors.
137
+
138
+# Docs
139
+ - A new document about how scheduling is implemented was added.
140
+ - Update the pw-cli man page. (#2988)
141
+ - Document the SPA Pod serialization.
142
+ - Document the PipeWire native protocol.
143
+
144
+
145
+Older versions:
146
+
147
# PipeWire 0.3.70 (2023-04-20)
148
149
This is a quick bugfix release that is API and ABI compatible with previous
150
151
- The GStreamer source now uses the BaseSrc clocking code to implement
152
the clock and timing code.
153
154
-
155
-Older versions:
156
-
157
# PipeWire 0.3.69 (2023-04-13)
158
159
This is a quick bugfix release that is API and ABI compatible with previous
160
pipewire-0.3.70.tar.gz/doc/meson.build -> pipewire-0.3.71.tar.gz/doc/meson.build
Changed
10
1
2
'pipewire-session-manager.dox',
3
'pipewire-objects-design.dox',
4
'pipewire-audio.dox',
5
+ 'pipewire-scheduling.dox',
6
+ 'pipewire-protocol.dox',
7
'tutorial.dox',
8
'tutorial1.dox',
9
'tutorial2.dox',
10
pipewire-0.3.70.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.71.tar.gz/doc/pipewire-modules.dox
Changed
10
1
2
- \subpage page_module_example_source
3
- \subpage page_module_fallback_sink
4
- \subpage page_module_filter_chain
5
+- \subpage page_module_jackdbus_detect
6
+- \subpage page_module_jack_tunnel
7
- \subpage page_module_link_factory
8
- \subpage page_module_loopback
9
- \subpage page_module_metadata
10
pipewire-0.3.71.tar.gz/doc/pipewire-protocol.dox
Added
201
1
2
+/** \page page_native_protocol Native Protocol
3
+
4
+PipeWire has a pluggable client/server IPC protocol.
5
+
6
+The reference implementation uses unix sockets and is implemented in
7
+\ref page_module_protocol_native.
8
+
9
+We document the messages here.
10
+
11
+# Message header
12
+
13
+Each message on the unix socket contains a 16 bytes header and a
14
+variable length payload size:
15
+
16
+```
17
+ 0 1 2 3
18
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
19
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20
+ | Id |
21
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22
+ | opcode | size |
23
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24
+ | seq |
25
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26
+ | n_fds |
27
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+ | payload POD |
29
+ . .
30
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
+ | optional footer POD |
32
+ . .
33
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34
+```
35
+
36
+
37
+These are four uint32 words to be read in native endianness.
38
+
39
+- Id: the message id this is the destination resource/proxy id
40
+- opcode: the opcode on the resource/proxy interface
41
+- size: the size of the payload and optional footer of the message
42
+- seq: an increasing sequence number for each message
43
+- n_fds: number of file descriptors in this message.
44
+
45
+The sender should send along with each message the fds that belong to
46
+the message. If there are more than the maximum number of fds in the
47
+message than can fit in one message, the message is split into multiple
48
+parts.
49
+
50
+The payload is a single POD see \ref page_spa_pod for details.
51
+
52
+After the payload, there is an optional footer POD object.
53
+
54
+# Making a connection
55
+
56
+First a connection is made to a unix domain socket. By default, the socket is
57
+named as "pipewire-0" and searched in the following directories:
58
+
59
+ - getenv("PIPEWIRE_RUNTIME_DIR")
60
+ - getenv("XDG_RUNTIME_DIR")
61
+ - getenv("USERPROFILE")
62
+
63
+
64
+The client opens the socket and allocates a Core proxy with id 0 and a Client
65
+proxy with id 1.
66
+
67
+The server will allocate a new Core resource with id 0.
68
+
69
+The client sends the Core::Hello message on the socket to start the
70
+communication.
71
+
72
+The server binds the client resource with id 1 to the client.
73
+
74
+The client then sends client properties to the server.
75
+
76
+```
77
+ client server
78
+ |---------------------------------------->|
79
+ | open socket |
80
+ | |
81
+ |---------------------------------------->|
82
+ | Core::Hello(version) |
83
+ | |
84
+ |---------------------------------------->|
85
+ | Client::UpdateProperties |
86
+ . .
87
+```
88
+
89
+This completes the setup of the client. The newly connected client will
90
+appear in the registry at this point.
91
+
92
+# Core proxy/resource
93
+
94
+The core is always the object with Id 0.
95
+
96
+## Core Methods (Id 0)
97
+
98
+### Core::Hello (Opcode 1)
99
+
100
+The first message sent by a client is the Hello message and contains the
101
+version number of the client.
102
+
103
+```
104
+ Struct(
105
+ Int: version
106
+ )
107
+```
108
+
109
+The version is 3.
110
+
111
+### Core::Sync (Opcode 2)
112
+
113
+The Sync message will result in a Done event from the server. When the Done
114
+event is received, the client can be sure that all operations before the Sync
115
+method have been completed.
116
+
117
+```
118
+ Struct(
119
+ Int: id
120
+ Int: seq
121
+ )
122
+```
123
+
124
+- id: the id will be returned in the Done event.
125
+- seq: is usually generated automatically and will be returned in the Done event.
126
+
127
+### Core::Pong (Opcode 3)
128
+
129
+Is sent from the client to the server when the server emits the Ping event.
130
+The id and seq should be copied from the Ping event.
131
+
132
+```
133
+ Struct(
134
+ Int: id
135
+ Int: seq
136
+ )
137
+```
138
+
139
+### Core::Error (Opcode 4)
140
+
141
+An error occured in an object on the client.
142
+
143
+```
144
+ Struct(
145
+ Int: id
146
+ Int: seq
147
+ Int: res
148
+ String: message
149
+ )
150
+```
151
+
152
+- id: The id of the proxy that is in error.
153
+- seq: a seq number from the failing request (if any)
154
+- res: a negative errno style error code
155
+- message: an error message
156
+
157
+### Core::GetRegistry (Opcode 5)
158
+
159
+A client requests to bind to the registry object and list the available objects
160
+on the server.
161
+
162
+Like with all bindings, first the client allocates a new proxy id and puts this
163
+as the new_id field. Methods and Events can then be sent and received on the
164
+new_id (in the message Id field).
165
+
166
+```
167
+ Struct(
168
+ Int: version
169
+ Int: new_id
170
+ )
171
+```
172
+- version: the version of the registry interface used on the client
173
+- new_id: the id of the new proxy with the registry interface
174
+
175
+After this method, the server will start sending Registry::Global events
176
+to the proxy with new_id.
177
+
178
+```
179
+ client server
180
+ | |
181
+ | new proxy(new_id) |
182
+ |---------------------------------------->| new resource(new_id)
183
+ | Core::GetRegistry(version) |
184
+ | |
185
+ |<----------------------------------------| new_id
186
+ | Registry::Global() |
187
+ |<----------------------------------------|
188
+ | Registry::Global() |
189
+ . .
190
+```
191
+
192
+There is no explicit last Global event to signal that the last object
193
+has been received. The usual way of knowing this is to send a Core::Sync
194
+method right after the Core::GetRegistry method and to wait for the
195
+Core::Done event.
196
+
197
+```
198
+ client server
199
+ | |
200
+ | new proxy(new_id) |
201
pipewire-0.3.71.tar.gz/doc/pipewire-scheduling.dox
Added
193
1
2
+/** \page page_scheduling Graph Scheduling
3
+
4
+This document tries to explain how the PipeWire graph is scheduled.
5
+
6
+Graph are constructed from linked nodes together with their ports. This
7
+results in a dependency graph between nodes. Special care is taken for
8
+loopback links so that the graph remains a directed graph.
9
+
10
+
11
+# Nodes
12
+
13
+Nodes are objects with 0 or more input and output ports.
14
+
15
+Each node also has:
16
+
17
+- an eventfd to signal the node that it can start processing
18
+- an activation record that lives in shared memory with memfd.
19
+
20
+```
21
+ evenfd
22
+ +-^---------+
23
+ | |
24
+ in out
25
+ | |
26
+ +-v---------+
27
+ activation {
28
+ status:OK, // bitmask of NEED_DATA, HAVE_DATA or OK
29
+ pending:0, // number of unsatisfied dependencies to be able to run
30
+ required:0 // number of dependencies with other nodes
31
+ }
32
+```
33
+
34
+The activation record has the following information:
35
+
36
+ - processing state and pending dependencies. As long as there are pending dependencies
37
+ the node can not be processed. This is the only relevant information for actually
38
+ scheduling the graph and is shown in the above illustration.
39
+ - Current status of the node and profiling info (TRIGGERED, AWAKE, FINISHED, timestamps
40
+ when the node changed state).
41
+ - Timing information, mostly for drivers when the processing started, the time, duration
42
+ and rate (quantum) etc..
43
+ - Information about repositions (seek) and timebase owners.
44
+
45
+
46
+# links.
47
+
48
+When two nodes are linked together, the output node becomes a dependency for the input
49
+node. This means the input node can only start processing when the output node is finished.
50
+
51
+This dependency is reflected in the required counter in the activation record. In below
52
+illustration, B's required field is incremented with 1. The pending field is set to the
53
+required field when the graph is started. Node A will keep a list of all targets (B) that it
54
+is a dependency of.
55
+
56
+This dependency update is only performed when the link is ready (negotiated) and the nodes
57
+are ready to schedule (runnable).
58
+
59
+
60
+```
61
+ evenfd eventfd
62
+ +-^---------+ +-^---------+
63
+ | | link | |
64
+ in A out ---------------------> in B out
65
+ | | | |
66
+ +-v---------+ +-v---------+
67
+ activation { target activation {
68
+ status:OK, --------------------> status:OK,
69
+ pending:0, pending:1,
70
+ required:0 required:1
71
+ } }
72
+```
73
+
74
+Multiple links between A and B will only result in 1 target link between A and B.
75
+
76
+
77
+# Drivers
78
+
79
+The graph can only run if there is a driver node that is in some way linked to an
80
+active node.
81
+
82
+The driver is special because it will have to initiate the processing in the graph. It
83
+will use a timer or some sort of interrupt from hardware to start the cycle.
84
+
85
+Any node can also be a candidate for a driver (when the node.driver property is true).
86
+PipeWire will select the node with the highest priority.driver property as the driver.
87
+
88
+Nodes will be assigned to the driver node they will be scheduled with. Each node holds
89
+a reference to the driver and increments the required field of the driver.
90
+
91
+When a node is ready to be scheduled, the driver adds the node to its list of targets
92
+and increments the required field.
93
+
94
+
95
+```
96
+ evenfd eventfd
97
+ +-^---------+ +-^---------+
98
+ | | link | |
99
+ in A out ---------------------> in B out
100
+ | | | |
101
+ +-v---------+ +-v---------+
102
+ activation { target activation {
103
+ status:OK, --------------------> status:OK,
104
+ pending:0, pending:0,
105
+ required:1 required:2
106
+ } }
107
+ | ^ ^
108
+ | | / /
109
+ | | / /
110
+ | | / /
111
+ | | / /
112
+ | | / /
113
+ v | /-------------/ /
114
+ activation { /
115
+ status:OK, V---------------/
116
+ pending:0,
117
+ required:2
118
+ }
119
+ +-^---------+
120
+ | |
121
+ | driver |
122
+ | |
123
+ +-v---------+
124
+ eventfd
125
+```
126
+
127
+As seen in the illustration above, the driver holds a link to each node it needs to
128
+schedule and each node holds a link to the driver. Some nodes hold a link to other
129
+nodes.
130
+
131
+It is possible that the driver is the same as a node in the graph (for example node A)
132
+but conceptually, the links above are still valid.
133
+
134
+The driver will then start processing the graph by emitting the ready signal. PipeWire
135
+will then:
136
+
137
+ - Perform some statistics about the previous cycle. Did it complete? compute processing
138
+ times, cpu usage etc.
139
+ - Perform reposition requests if any, timebase changes, etc..
140
+ - The pending counter of each follower node is set to the required field.
141
+ - it then loops over all targets of the driver and atomically decrements the required
142
+ field of the activation record. When the required field is 0, the eventfd is signaled
143
+ and the node can be scheduled.
144
+
145
+In our example above, Node A and be will have their pending state decremented. Node A
146
+will be 0 and will be triggered first (node B has 2 pending dependencies to start with and
147
+will not be triggered yet). The driver itself also has 2 dependcies left and will not
148
+be triggered (complete) yet.
149
+
150
+## Scheduling node A
151
+
152
+When the eventfd is signaled on a node, we say the node is triggered and it will be able
153
+to process data. It consumes the input on the input ports and produces more data on the
154
+output ports.
155
+
156
+After processing, node A goes through the list of targets and decrements each pending
157
+field (node A has a reference to B and the driver).
158
+
159
+In our above example, the driver is decremented (from 2 to 1) but is not yet triggered.
160
+node B is decremented (from 1 to 0) and is triggered by writing to the eventfd.
161
+
162
+## Scheduling node B
163
+
164
+Node B is scheduled and processes the input from node A. It then goes through the list of
165
+targets and decrements the pending fields. It decrements the pending field of the
166
+driver (from 1 to 0) and triggers the driver.
167
+
168
+## Scheduling the driver
169
+
170
+The graph always completes after the driver is triggered and scheduled. All required
171
+fields from all the nodes in the target list of the driver are now 0.
172
+
173
+# Remote nodes.
174
+
175
+For remote nodes, the eventfd and the activation is transfered from the server
176
+to the client.
177
+
178
+This means that writing to the remote client eventfd will wake the client directly
179
+without going to the server first.
180
+
181
+All remote clients also get the activation and eventfd of the peer and driver they
182
+are linked to and can directly trigger peers and drivers without going to the
183
+server first.
184
+
185
+## Remote driver nodes.
186
+
187
+Currently the graph start cycle is managed by the server.
188
+
189
+Remote driver nodes therefore have an extra eventfd to wake up the server and signal
190
+the graph start.
191
+
192
+*/
193
pipewire-0.3.70.tar.gz/doc/pipewire.dox -> pipewire-0.3.71.tar.gz/doc/pipewire.dox
Changed
10
1
2
- \subpage page_objects_design
3
- \subpage page_library
4
- \subpage page_dma_buf
5
+- \subpage page_scheduling
6
+- \subpage page_native_protocol
7
8
9
# Components
10
pipewire-0.3.70.tar.gz/doc/spa-pod.dox -> pipewire-0.3.71.tar.gz/doc/spa-pod.dox
Changed
201
1
2
3
# POD Layout
4
5
-Each POD has a 32 bits size field, followed by a 32 bits type field. The size
6
-field specifies the size following the type field.
7
-
8
-Each POD is aligned to an 8 byte boundary.
9
-
10
+A POD always starts with a size/type pair of uint32_t in native endianness,
11
+followed by size in bytes of the payload data and padding. See
12
+\ref page_spa_pod for more details.
13
+
14
+The payload is always padded to 8 bytes so that a complete pod is always
15
+a multiple of 8 bytes.
16
+
17
+```
18
+ 0 1 2 3
19
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
20
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ | size |
22
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23
+ | type |
24
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25
+ | payload ... |
26
+ . | ... padding .
27
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+```
29
+
30
+The total size of the POD is thus ROUND_UP_8(8 + size).
31
+
32
+# POD Types
33
+
34
+Here follows the layout of the POD types.
35
+
36
+## None (1)
37
+
38
+Type 1 is the None type or the null pointer. It has a size of 0 and thus
39
+no payload.
40
+
41
+```
42
+ 0 1 2 3
43
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
44
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45
+ | 0 |
46
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47
+ | 1 |
48
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49
+```
50
+
51
+## Bool (2)
52
+
53
+Type 2 is the Bool type. I contains a true or false value. The value is
54
+stored in a int32, a value of 0 is false, any other value is true.
55
+
56
+```
57
+ 0 1 2 3
58
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
59
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60
+ | 4 |
61
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62
+ | 2 |
63
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64
+ | value (int32) |
65
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66
+ | padding |
67
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68
+```
69
+
70
+## Id (3)
71
+
72
+An id is stored as a uint32. The id refers to an index in a table where more
73
+information about the value can be found. This is typically a type table
74
+containing some well known ids.
75
+
76
+```
77
+ 0 1 2 3
78
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
79
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80
+ | 4 |
81
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82
+ | 3 |
83
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84
+ | id (uint32) |
85
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86
+ | padding |
87
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88
+```
89
+
90
+## Int (4)
91
+
92
+A 32 bit signed integer.
93
+
94
+```
95
+ 0 1 2 3
96
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
97
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98
+ | 4 |
99
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100
+ | 4 |
101
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102
+ | value (int32) |
103
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104
+ | padding |
105
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106
+```
107
+
108
+## Long (5)
109
+
110
+A 64 bit signed integer.
111
+
112
+```
113
+ 0 1 2 3
114
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
115
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116
+ | 4 |
117
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118
+ | 5 |
119
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120
+ | value (int64) |
121
+ + +
122
+ | |
123
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124
+```
125
+
126
+## Float (6)
127
+
128
+A 32 bit float value.
129
+
130
+```
131
+ 0 1 2 3
132
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
133
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134
+ | 4 |
135
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136
+ | 6 |
137
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138
+ | value (float32) |
139
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140
+ | padding |
141
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
142
+```
143
+
144
+## Double (7)
145
+
146
+A 64 bit float value.
147
+
148
+```
149
+ 0 1 2 3
150
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
151
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
152
+ | 4 |
153
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154
+ | 7 |
155
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156
+ | value (float64) |
157
+ + +
158
+ | |
159
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160
+```
161
+
162
+## String (8)
163
+
164
+A string. This does not have to be valid UTF8 but it is 0 terminated.
165
+The size field is set to the length of the string, including the 0
166
+byte.
167
+
168
+```
169
+ 0 1 2 3
170
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
171
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
172
+ | size |
173
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174
+ | 8 |
175
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176
+ | chars .... |
177
+ . .
178
+ | ... 0 | padding.. |
179
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
180
+```
181
+
182
+
183
+## Bytes (9)
184
+
185
+A byte array. The size field is set to the number of bytes.
186
+
187
+```
188
+ 0 1 2 3
189
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
190
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
191
+ | size |
192
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193
+ | 9 |
194
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195
+ | bytes .... |
196
+ . .
197
+ | | padding.. |
198
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
199
+```
200
+
201
pipewire-0.3.70.tar.gz/man/pw-cli.1.rst.in -> pipewire-0.3.71.tar.gz/man/pw-cli.1.rst.in
Changed
52
1
2
*pipewire-0*.
3
4
Connections to other, remote instances can be made. The current instance
5
-name is displayed at the prompt. Some commands operate on the current
6
-instance and some on the local instance.
7
+name is displayed at the prompt.
8
+
9
+Note that **pw-cli** also creates a local PipeWire instance. Some commands
10
+operate on the current (remote) instance and some on the local instance, such
11
+as module loading.
12
13
Use the 'help' command to list the available commands.
14
15
16
| instance.
17
18
load-module *name* *arguments...*
19
- Load a module specified by its name and arguments. For most
20
- modules it is OK to be loaded more than once.
21
+ Load a module specified by its name and arguments in the local instance.
22
+ For most modules it is OK to be loaded more than once.
23
24
This command returns a module variable that can be used
25
to unload the module.
26
27
+ The locally module is *not* visible in the remote instance. It is not
28
+ possible in PipeWire to load modules in a remote instance.
29
+
30
unload-module *module-var*
31
Unload a module, specified either by its variable.
32
33
34
If no remote name is specified, a connection is made to
35
the default remote instance, usually *pipewire-0*.
36
37
+ The special remote name called *internal* can be used to connect to
38
+ the local **pw-cli** PipeWire instance.
39
+
40
This command returns a remote var that can be used to disconnect or
41
switch remotes.
42
43
44
switch-remote *remote-var*
45
Make the specified *remote* the current instance.
46
47
- If no remote name is specified, the local instance is made current.
48
+ If no remote name is specified, the first instance is made current.
49
50
NODE MANAGEMENT
51
===============
52
pipewire-0.3.70.tar.gz/meson.build -> pipewire-0.3.71.tar.gz/meson.build
Changed
16
1
2
project('pipewire', 'c' ,
3
- version : '0.3.70',
4
+ version : '0.3.71',
5
license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
meson_version : '>= 0.61.1',
7
default_options : 'warning_level=3',
8
9
versiondata.set_quoted('PIPEWIRE_API_VERSION', apiversion)
10
11
cdata = configuration_data()
12
+cdata.set_quoted('PREFIX', prefix)
13
cdata.set_quoted('PIPEWIRE_CONFDATADIR', pipewire_confdatadir)
14
cdata.set_quoted('LOCALEDIR', pipewire_localedir)
15
cdata.set_quoted('LIBDIR', pipewire_libdir)
16
pipewire-0.3.70.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c -> pipewire-0.3.71.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c
Changed
66
1
2
unsigned int xrun_detected:1;
3
unsigned int hw_params_changed:1;
4
unsigned int active:1;
5
+ unsigned int negotiated:1;
6
7
snd_pcm_uframes_t hw_ptr;
8
snd_pcm_uframes_t boundary;
9
10
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(pw->stride));
11
12
pw_stream_update_params(pw->stream, params, n_params);
13
+
14
+ pw->negotiated = true;
15
+ pw_thread_loop_signal(pw->main_loop, false);
16
+}
17
+
18
+static void on_stream_state_changed(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error)
19
+{
20
+ snd_pcm_pipewire_t *pw = data;
21
+
22
+ if (state == PW_STREAM_STATE_ERROR) {
23
+ pw_log_warn("%s", error);
24
+ pw->error = -EIO;
25
+ update_active(&pw->io);
26
+ }
27
}
28
29
static void on_stream_drained(void *data)
30
31
static const struct pw_stream_events stream_events = {
32
PW_VERSION_STREAM_EVENTS,
33
.param_changed = on_stream_param_changed,
34
+ .state_changed = on_stream_state_changed,
35
.process = on_stream_process,
36
.drained = on_stream_drained,
37
};
38
39
40
pw->error = 0;
41
42
+ pw->negotiated = false;
43
pw_stream_connect(pw->stream,
44
io->stream == SND_PCM_STREAM_PLAYBACK ?
45
PW_DIRECTION_OUTPUT :
46
47
pw->drained = false;
48
pw->draining = false;
49
50
+ while (!pw->negotiated && pw->error >= 0)
51
+ pw_thread_loop_wait(pw->main_loop);
52
+ if (pw->error < 0)
53
+ goto error;
54
+
55
pw_thread_loop_unlock(pw->main_loop);
56
57
return 0;
58
59
error:
60
pw_thread_loop_unlock(pw->main_loop);
61
- return -ENOMEM;
62
+ return pw->error < 0 ? pw->error : -ENOMEM;
63
}
64
65
static int snd_pcm_pipewire_start(snd_pcm_ioplug_t *io)
66
pipewire-0.3.70.tar.gz/pipewire-jack/jack/control.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/control.h
Changed
10
1
2
const char *format,
3
...);
4
5
-/* @} */
6
+/**@}*/
7
8
#if 0
9
{ /* Adjust editor indent */
10
pipewire-0.3.70.tar.gz/pipewire-jack/jack/jack.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/jack.h
Changed
118
1
2
*/
3
jack_native_thread_t jack_client_thread_id (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
4
5
-/*@}*/
6
+/**@}*/
7
8
/**
9
* @param client pointer to JACK client structure.
10
11
*/
12
int jack_set_process_thread(jack_client_t* client, JackThreadCallback thread_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT;
13
14
-/*@}*/
15
+/**@}*/
16
17
/**
18
* @defgroup ClientCallbacks Setting Client Callbacks
19
20
int jack_set_xrun_callback (jack_client_t *client,
21
JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT;
22
23
-/*@}*/
24
-
25
/**
26
* Tell the Jack server to call @a latency_callback whenever it
27
* is necessary to recompute the latencies for some or all
28
29
* @ref jack_port_get_latency_range(), which only returns meaningful
30
* values when ports get connected and latency values change.
31
*
32
- * See the documentation for @ref jack_port_set_latency_range()
33
+ * See the documentation for @ref jack_port_set_latency_range()
34
* on how the callback should operate. Remember that the @a mode
35
* argument given to the latency callback will need to be
36
* passed into @ref jack_port_set_latency_range()
37
38
int jack_set_latency_callback (jack_client_t *client,
39
JackLatencyCallback latency_callback,
40
void *) JACK_WEAK_EXPORT;
41
-/*@}*/
42
+/**@}*/
43
44
/**
45
* @defgroup ServerClientControl Controlling & querying JACK server operation
46
47
*/
48
float jack_cpu_load (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
49
50
-/*@}*/
51
+/**@}*/
52
53
/**
54
* @defgroup PortFunctions Creating & manipulating ports
55
56
*/
57
size_t jack_port_type_get_buffer_size (jack_client_t *client, const char *port_type) JACK_WEAK_EXPORT;
58
59
-/*@}*/
60
+/**@}*/
61
62
/**
63
* @defgroup LatencyFunctions Managing and determining latency
64
+ * @{
65
*
66
* The purpose of JACK's latency API is to allow clients to
67
* easily answer two questions:
68
69
* clients that add latency to the signal path should interact
70
* with JACK to ensure that the correct latency figures are
71
* used.
72
- * @{
73
*/
74
75
/**
76
77
*/
78
int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT;
79
80
-/*@}*/
81
+/**@}*/
82
83
/**
84
* @defgroup PortSearching Looking up ports
85
86
jack_port_t * jack_port_by_id (jack_client_t *client,
87
jack_port_id_t port_id) JACK_OPTIONAL_WEAK_EXPORT;
88
89
-/*@}*/
90
+/**@}*/
91
92
/**
93
* @defgroup TimeFunctions Handling time
94
95
*/
96
jack_time_t jack_get_time(void) JACK_OPTIONAL_WEAK_EXPORT;
97
98
-/*@}*/
99
+/**@}*/
100
101
/**
102
* @defgroup ErrorOutput Controlling error/information output
103
+ * @{
104
*/
105
-/*@{*/
106
107
/**
108
* Display JACK error message.
109
110
*/
111
void jack_set_info_function (void (*func)(const char *)) JACK_OPTIONAL_WEAK_EXPORT;
112
113
-/*@}*/
114
+/**@}*/
115
116
/**
117
* The free function to be used on memory returned by jack_port_get_connections,
118
pipewire-0.3.70.tar.gz/pipewire-jack/jack/midiport.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/midiport.h
Changed
10
1
2
uint32_t
3
jack_midi_get_lost_event_count(void *port_buffer) JACK_OPTIONAL_WEAK_EXPORT;
4
5
-/*@}*/
6
+/**@}*/
7
8
#ifdef __cplusplus
9
}
10
pipewire-0.3.70.tar.gz/pipewire-jack/jack/ringbuffer.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/ringbuffer.h
Changed
12
1
2
3
typedef struct {
4
char *buf;
5
- volatile size_t write_ptr;
6
- volatile size_t read_ptr;
7
+ size_t write_ptr;
8
+ size_t read_ptr;
9
size_t size;
10
size_t size_mask;
11
int mlocked;
12
pipewire-0.3.70.tar.gz/pipewire-jack/jack/session.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/session.h
Changed
10
1
2
*
3
* @deprecated Use of JACK-Session is currently deprecated and unsupported.
4
* JACK developers recommend the use of NSM instead.
5
- * See https://github.com/linuxaudio/new-session-manager
6
+ * See https://new-session-manager.jackaudio.org/
7
* @{
8
*/
9
10
pipewire-0.3.70.tar.gz/pipewire-jack/jack/thread.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/thread.h
Changed
10
1
2
3
#endif
4
5
-/* @} */
6
+/**@}*/
7
8
#ifdef __cplusplus
9
}
10
pipewire-0.3.70.tar.gz/pipewire-jack/jack/transport.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/transport.h
Changed
10
1
2
void jack_set_transport_info (jack_client_t *client,
3
jack_transport_info_t *tinfo) JACK_OPTIONAL_WEAK_EXPORT;
4
5
-/*@}*/
6
+/**@}*/
7
8
#ifdef __cplusplus
9
}
10
pipewire-0.3.70.tar.gz/pipewire-jack/jack/types.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/types.h
Changed
49
1
2
*/
3
typedef enum {
4
5
- JackPositionBBT = 0x10, /**< Bar, Beat, Tick */
6
- JackPositionTimecode = 0x20, /**< External timecode */
7
- JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */
8
- JackAudioVideoRatio = 0x80, /**< audio frames per video frame */
9
- JackVideoFrameOffset = 0x100 /**< frame offset of first video frame */
10
+ JackPositionBBT = 0x10, /**< Bar, Beat, Tick */
11
+ JackPositionTimecode = 0x20, /**< External timecode */
12
+ JackBBTFrameOffset = 0x40, /**< Frame offset of BBT information */
13
+ JackAudioVideoRatio = 0x80, /**< audio frames per video frame */
14
+ JackVideoFrameOffset = 0x100, /**< frame offset of first video frame */
15
+ JackTickDouble = 0x200, /**< double-resolution tick */
16
17
} jack_position_bits_t;
18
19
20
#define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode)
21
#define EXTENDED_TIME_INFO
22
23
+/** transport tick_double member is available for use */
24
+#define JACK_TICK_DOUBLE
25
+
26
PRE_PACKED_STRUCTURE
27
struct _jack_position {
28
29
30
set, but the value is zero, there is
31
no video frame within this cycle. */
32
33
+ /* JACK extra transport fields */
34
+
35
+ double tick_double; /**< current tick-within-beat in double resolution.
36
+ Should be assumed zero if JackTickDouble is not set.
37
+ Since older versions of JACK do not expose this variable,
38
+ the macro JACK_TICK_DOUBLE is provided,
39
+ which can be used as build-time detection. */
40
+
41
/* For binary compatibility, new fields should be allocated from
42
* this padding area with new valid bits controlling access, so
43
* the existing structure size and offsets are preserved. */
44
- int32_t padding7;
45
+ int32_t padding5;
46
47
/* When (unique_1 == unique_2) the contents are consistent. */
48
jack_unique_t unique_2; /**< unique ID */
49
pipewire-0.3.70.tar.gz/pipewire-jack/jack/weakjack.h -> pipewire-0.3.71.tar.gz/pipewire-jack/jack/weakjack.h
Changed
9
1
2
#endif
3
#endif
4
5
-/*@}*/
6
+/**@}*/
7
8
#endif /* weakjack */
9
pipewire-0.3.70.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.71.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
201
1
2
#include <spa/debug/pod.h>
3
#include <spa/utils/json.h>
4
#include <spa/utils/string.h>
5
+#include <spa/utils/ringbuffer.h>
6
7
#include <pipewire/pipewire.h>
8
#include <pipewire/private.h>
9
10
#define MAX_MIX 1024
11
#define MAX_BUFFER_FRAMES 8192
12
13
+#define MAX_CLIENT_PORTS 768
14
+
15
#define MAX_ALIGN 16
16
#define MAX_BUFFERS 2
17
#define MAX_BUFFER_DATAS 1u
18
19
#define SELF_CONNECT_FAIL_ALL -2
20
#define SELF_CONNECT_IGNORE_ALL 2
21
22
+#define NOTIFY_BUFFER_SIZE (1u<<13)
23
+#define NOTIFY_BUFFER_MASK (NOTIFY_BUFFER_SIZE-1)
24
+
25
+struct notify {
26
+#define NOTIFY_ACTIVE_FLAG (1<<0)
27
+
28
+#define NOTIFY_TYPE_NONE ((0<<4)|NOTIFY_ACTIVE_FLAG)
29
+#define NOTIFY_TYPE_REGISTRATION ((1<<4))
30
+#define NOTIFY_TYPE_PORTREGISTRATION ((2<<4)|NOTIFY_ACTIVE_FLAG)
31
+#define NOTIFY_TYPE_CONNECT ((3<<4)|NOTIFY_ACTIVE_FLAG)
32
+#define NOTIFY_TYPE_GRAPH ((4<<4)|NOTIFY_ACTIVE_FLAG)
33
+#define NOTIFY_TYPE_BUFFER_FRAMES ((5<<4)|NOTIFY_ACTIVE_FLAG)
34
+#define NOTIFY_TYPE_SAMPLE_RATE ((6<<4)|NOTIFY_ACTIVE_FLAG)
35
+#define NOTIFY_TYPE_FREEWHEEL ((7<<4)|NOTIFY_ACTIVE_FLAG)
36
+#define NOTIFY_TYPE_SHUTDOWN ((8<<4)|NOTIFY_ACTIVE_FLAG)
37
+#define NOTIFY_TYPE_LATENCY ((9<<4)|NOTIFY_ACTIVE_FLAG)
38
+ int type;
39
+ struct object *object;
40
+ int arg1;
41
+ const char *msg;
42
+};
43
+
44
struct client;
45
struct port;
46
47
48
struct pw_proxy *proxy;
49
struct spa_hook proxy_listener;
50
struct spa_hook object_listener;
51
+ int registered;
52
unsigned int removing:1;
53
unsigned int removed:1;
54
};
55
56
57
uint32_t node_id;
58
uint32_t serial;
59
+ struct object *object;
60
+
61
struct spa_source *socket_source;
62
+ struct spa_source *notify_source;
63
+ void *notify_buffer;
64
+ struct spa_ringbuffer notify_ring;
65
66
JackThreadCallback thread_callback;
67
void *thread_arg;
68
69
70
struct spa_list free_ports;
71
struct pw_map ports2;
72
+ uint32_t n_ports;
73
74
struct spa_list links;
75
uint32_t driver_id;
76
77
unsigned int warn_mlock:1;
78
unsigned int timeowner_conditional:1;
79
unsigned int show_monitor:1;
80
+ unsigned int show_midi:1;
81
unsigned int merge_monitor:1;
82
unsigned int short_name:1;
83
unsigned int filter_name:1;
84
85
unsigned int fix_midi_events:1;
86
unsigned int global_buffer_size:1;
87
unsigned int passive_links:1;
88
+ unsigned int graph_callback_pending:1;
89
+ unsigned int pending_callbacks:1;
90
+ int frozen_callbacks;
91
char filter_char;
92
+ uint32_t max_ports;
93
+ unsigned int fill_aliases:1;
94
95
jack_position_t jack_position;
96
jack_transport_state_t jack_state;
97
};
98
99
+#define return_val_if_fail(expr, val) \
100
+({ \
101
+ if (SPA_UNLIKELY(!(expr))) { \
102
+ pw_log_warn("'%s' failed at %s:%u %s()", \
103
+ #expr , __FILE__, __LINE__, __func__); \
104
+ return (val); \
105
+ } \
106
+})
107
+
108
+#define return_if_fail(expr) \
109
+({ \
110
+ if (SPA_UNLIKELY(!(expr))) { \
111
+ pw_log_warn("'%s' failed at %s:%u %s()", \
112
+ #expr , __FILE__, __LINE__, __func__); \
113
+ return; \
114
+ } \
115
+})
116
+
117
static int do_sync(struct client *client);
118
static struct object *find_by_serial(struct client *c, uint32_t serial);
119
120
121
struct object *o;
122
uint32_t i;
123
124
+ if (c->n_ports >= c->max_ports) {
125
+ errno = ENOSPC;
126
+ return NULL;
127
+ }
128
+
129
if (spa_list_is_empty(&c->free_ports)) {
130
p = calloc(OBJECT_CHUNK, sizeof(struct port));
131
if (p == NULL)
132
133
spa_list_remove(&p->link);
134
135
o = alloc_object(c, INTERFACE_Port);
136
+ if (o == NULL)
137
+ return NULL;
138
+
139
o->id = SPA_ID_INVALID;
140
o->port.node_id = c->node_id;
141
o->port.port = p;
142
143
p->direction = direction;
144
p->emptyptr = SPA_PTR_ALIGN(p->empty, MAX_ALIGN, float);
145
p->port_id = pw_map_insert_new(&c->portsdirection, p);
146
+ c->n_ports++;
147
148
pthread_mutex_lock(&c->context.lock);
149
spa_list_append(&c->context.objects, &o->link);
150
151
return p;
152
}
153
154
-static void free_port(struct client *c, struct port *p)
155
+static void free_port(struct client *c, struct port *p, bool free)
156
{
157
struct mix *m;
158
159
spa_list_consume(m, &p->mix, port_link)
160
free_mix(c, m);
161
162
+ c->n_ports--;
163
pw_map_remove(&c->portsp->direction, p->port_id);
164
- free_object(c, p->object);
165
pw_properties_free(p->props);
166
spa_list_append(&c->free_ports, &p->link);
167
+ if (free)
168
+ free_object(c, p->object);
169
+ else
170
+ p->object->removing = true;
171
}
172
173
static struct object *find_node(struct client *c, const char *name)
174
175
*proto_ptr = 0;
176
}
177
178
-#define do_callback_expr(c,expr,callback,...) \
179
+#define do_callback_expr(c,expr,callback,do_emit,...) \
180
({ \
181
- if (c->callback && c->active) { \
182
+ if (c->callback && do_emit) { \
183
pw_thread_loop_unlock(c->context.loop); \
184
if (c->locked_process) \
185
pthread_mutex_lock(&c->rt_lock); \
186
187
pthread_mutex_unlock(&c->rt_lock); \
188
pw_thread_loop_lock(c->context.loop); \
189
} else { \
190
- if (c->active) \
191
- (expr); \
192
+ (expr); \
193
pw_log_debug("skip " #callback \
194
- " cb:%p active:%d", c->callback, \
195
- c->active); \
196
+ " cb:%p do_emit:%d", c->callback, \
197
+ do_emit); \
198
} \
199
})
200
201
pipewire-0.3.70.tar.gz/spa/include/spa/node/keys.h -> pipewire-0.3.71.tar.gz/spa/include/spa/node/keys.h
Changed
9
1
2
#define SPA_KEY_PORT_NAME "port.name" /**< a port name */
3
#define SPA_KEY_PORT_ALIAS "port.alias" /**< a port alias */
4
#define SPA_KEY_PORT_MONITOR "port.monitor" /**< this port is a monitor port */
5
+#define SPA_KEY_PORT_IGNORE_LATENCY "port.ignore-latency" /**< latency ignored by peers */
6
7
8
/**
9
pipewire-0.3.70.tar.gz/spa/include/spa/node/node.h -> pipewire-0.3.71.tar.gz/spa/include/spa/node/node.h
Changed
28
1
2
_res; \
3
})
4
5
+#define spa_node_method_fast(o,method,version,...) \
6
+({ \
7
+ int _res; \
8
+ struct spa_node *_n = o; \
9
+ spa_interface_call_fast_res(&_n->iface, \
10
+ struct spa_node_methods, _res, \
11
+ method, version, ##__VA_ARGS__); \
12
+ _res; \
13
+})
14
+
15
#define spa_node_add_listener(n,...) spa_node_method(n, add_listener, 0, __VA_ARGS__)
16
#define spa_node_set_callbacks(n,...) spa_node_method(n, set_callbacks, 0, __VA_ARGS__)
17
#define spa_node_sync(n,...) spa_node_method(n, sync, 0, __VA_ARGS__)
18
19
#define spa_node_port_set_io(n,...) spa_node_method(n, port_set_io, 0, __VA_ARGS__)
20
21
#define spa_node_port_reuse_buffer(n,...) spa_node_method(n, port_reuse_buffer, 0, __VA_ARGS__)
22
+#define spa_node_port_reuse_buffer_fast(n,...) spa_node_method_fast(n, port_reuse_buffer, 0, __VA_ARGS__)
23
#define spa_node_process(n) spa_node_method(n, process, 0)
24
+#define spa_node_process_fast(n) spa_node_method_fast(n, process, 0)
25
26
/**
27
* \}
28
pipewire-0.3.70.tar.gz/spa/include/spa/node/utils.h -> pipewire-0.3.71.tar.gz/spa/include/spa/node/utils.h
Changed
12
1
2
3
#define spa_node_call(callbacks,method,version,...) \
4
({ \
5
- int _res = -ENOTSUP; \
6
- spa_callbacks_call_res(callbacks, struct spa_node_callbacks, \
7
+ int _res; \
8
+ spa_callbacks_call_fast_res(callbacks, struct spa_node_callbacks, \
9
_res, method, version, ##__VA_ARGS__); \
10
_res; \
11
})
12
pipewire-0.3.70.tar.gz/spa/include/spa/param/latency-utils.h -> pipewire-0.3.71.tar.gz/spa/include/spa/param/latency-utils.h
Changed
10
1
2
#include <spa/param/latency.h>
3
4
static inline int
5
-spa_latency_info_compare(const struct spa_latency_info *a, struct spa_latency_info *b)
6
+spa_latency_info_compare(const struct spa_latency_info *a, const struct spa_latency_info *b)
7
{
8
if (a->min_quantum == b->min_quantum &&
9
a->max_quantum == b->max_quantum &&
10
pipewire-0.3.70.tar.gz/spa/include/spa/pod/parser.h -> pipewire-0.3.71.tar.gz/spa/include/spa/pod/parser.h
Changed
10
1
2
const struct spa_pod *pod = NULL;
3
const char *format;
4
5
- if (ftype == SPA_TYPE_Object) {
6
+ if (f && ftype == SPA_TYPE_Object) {
7
uint32_t key = va_arg(args, uint32_t);
8
const struct spa_pod_object *object;
9
10
pipewire-0.3.70.tar.gz/spa/include/spa/support/loop.h -> pipewire-0.3.71.tar.gz/spa/include/spa/support/loop.h
Changed
45
1
2
struct spa_hook_list *_l = l; \
3
struct spa_hook *_h; \
4
spa_list_for_each_reverse(_h, &_l->list, link) \
5
- spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, before, 0); \
6
+ spa_callbacks_call_fast(&_h->cb, struct spa_loop_control_hooks, before, 0); \
7
})
8
9
#define spa_loop_control_hook_after(l) \
10
11
struct spa_hook_list *_l = l; \
12
struct spa_hook *_h; \
13
spa_list_for_each(_h, &_l->list, link) \
14
- spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, after, 0); \
15
+ spa_callbacks_call_fast(&_h->cb, struct spa_loop_control_hooks, after, 0); \
16
})
17
18
/**
19
20
_res; \
21
})
22
23
+#define spa_loop_control_method_fast_r(o,method,version,...) \
24
+({ \
25
+ int _res; \
26
+ struct spa_loop_control *_o = o; \
27
+ spa_interface_call_fast_res(&_o->iface, \
28
+ struct spa_loop_control_methods, _res, \
29
+ method, version, ##__VA_ARGS__); \
30
+ _res; \
31
+})
32
+
33
#define spa_loop_control_get_fd(l) spa_loop_control_method_r(l,get_fd,0)
34
#define spa_loop_control_add_hook(l,...) spa_loop_control_method_v(l,add_hook,0,__VA_ARGS__)
35
#define spa_loop_control_enter(l) spa_loop_control_method_v(l,enter,0)
36
37
#define spa_loop_control_iterate(l,...) spa_loop_control_method_r(l,iterate,0,__VA_ARGS__)
38
#define spa_loop_control_check(l) spa_loop_control_method_r(l,check,1)
39
40
+#define spa_loop_control_iterate_fast(l,...) spa_loop_control_method_fast_r(l,iterate,0,__VA_ARGS__)
41
+
42
typedef void (*spa_source_io_func_t) (void *data, int fd, uint32_t mask);
43
typedef void (*spa_source_idle_func_t) (void *data);
44
typedef void (*spa_source_event_func_t) (void *data, uint64_t count);
45
pipewire-0.3.70.tar.gz/spa/include/spa/support/system.h -> pipewire-0.3.71.tar.gz/spa/include/spa/support/system.h
Changed
16
1
2
({ \
3
volatile int _res = -ENOTSUP; \
4
struct spa_system *_o = o; \
5
- spa_interface_call_res(&_o->iface, \
6
+ spa_interface_call_fast_res(&_o->iface, \
7
struct spa_system_methods, _res, \
8
method, version, ##__VA_ARGS__); \
9
_res; \
10
})
11
12
-
13
#define spa_system_read(s,...) spa_system_method_r(s,read,0,__VA_ARGS__)
14
#define spa_system_write(s,...) spa_system_method_r(s,write,0,__VA_ARGS__)
15
#define spa_system_ioctl(s,...) spa_system_method_r(s,ioctl,0,__VA_ARGS__)
16
pipewire-0.3.70.tar.gz/spa/include/spa/utils/hook.h -> pipewire-0.3.71.tar.gz/spa/include/spa/utils/hook.h
Changed
48
1
2
_res; \
3
})
4
5
+#define spa_callbacks_call_fast(callbacks,type,method,vers,...) \
6
+({ \
7
+ const type *_f = (const type *) (callbacks)->funcs; \
8
+ _f->method((callbacks)->data, ## __VA_ARGS__); \
9
+ true; \
10
+})
11
+
12
+
13
/**
14
* True if the \a callbacks are of version \a vers, false otherwise
15
*/
16
17
res = _f->method((callbacks)->data, ## __VA_ARGS__); \
18
res; \
19
})
20
+#define spa_callbacks_call_fast_res(callbacks,type,res,method,vers,...) \
21
+({ \
22
+ const type *_f = (const type *) (callbacks)->funcs; \
23
+ res = _f->method((callbacks)->data, ## __VA_ARGS__); \
24
+})
25
26
/**
27
* True if the \a iface's callbacks are of version \a vers, false otherwise
28
29
#define spa_interface_call(iface,method_type,method,vers,...) \
30
spa_callbacks_call(&(iface)->cb,method_type,method,vers,##__VA_ARGS__)
31
32
+#define spa_interface_call_fast(iface,method_type,method,vers,...) \
33
+ spa_callbacks_call_fast(&(iface)->cb,method_type,method,vers,##__VA_ARGS__)
34
+
35
/**
36
* Invoke method named \a method in the callbacks on the given interface object.
37
* The \a method_type defines the type of the method struct, not the interface
38
39
#define spa_interface_call_res(iface,method_type,res,method,vers,...) \
40
spa_callbacks_call_res(&(iface)->cb,method_type,res,method,vers,##__VA_ARGS__)
41
42
+#define spa_interface_call_fast_res(iface,method_type,res,method,vers,...) \
43
+ spa_callbacks_call_fast_res(&(iface)->cb,method_type,res,method,vers,##__VA_ARGS__)
44
+
45
/**
46
* \}
47
*/
48
pipewire-0.3.70.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
11
1
2
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency);
3
snprintf(period, sizeof(period), "%lu", this->period_frames);
4
itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period);
5
- snprintf(nperiods, sizeof(nperiods), "%lu", this->buffer_frames / this->period_frames);
6
+ snprintf(nperiods, sizeof(nperiods), "%lu",
7
+ this->period_frames != 0 ? this->buffer_frames / this->period_frames : 0);
8
itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods);
9
snprintf(headroom, sizeof(headroom), "%u", this->headroom);
10
itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom);
11
pipewire-0.3.70.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
11
1
2
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency);
3
snprintf(period, sizeof(period), "%lu", this->period_frames);
4
itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period);
5
- snprintf(nperiods, sizeof(nperiods), "%lu", this->buffer_frames / this->period_frames);
6
+ snprintf(nperiods, sizeof(nperiods), "%lu",
7
+ this->period_frames != 0 ? this->buffer_frames / this->period_frames : 0);
8
itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods);
9
snprintf(headroom, sizeof(headroom), "%u", this->headroom);
10
itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom);
11
pipewire-0.3.70.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
22
1
2
}
3
}
4
}
5
+ if (j > 1)
6
+ choice->body.type = SPA_CHOICE_Enum;
7
+ spa_pod_builder_pop(b, &f1);
8
+
9
if (j == 0) {
10
char buf1024;
11
int i, r, offs;
12
13
spa_log_warn(state->log, "%s: access:%s", state->props.device, buf);
14
return -ENOTSUP;
15
}
16
- if (j > 1)
17
- choice->body.type = SPA_CHOICE_Enum;
18
- spa_pod_builder_pop(b, &f1);
19
20
if ((res = add_rate(state, 1, 1, false, index & 0xffff, next, 0, params, b)) != 1)
21
return res;
22
pipewire-0.3.70.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.71.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
135
1
2
unsigned int add_listener:1;
3
unsigned int have_format:1;
4
unsigned int started:1;
5
+ unsigned int ready:1;
6
unsigned int driver:1;
7
unsigned int async:1;
8
unsigned int passthrough:1;
9
10
return res;
11
if ((res = negotiate_buffers(this)) < 0)
12
return res;
13
- this->started = true;
14
+ this->ready = true;
15
break;
16
case SPA_NODE_COMMAND_Suspend:
17
this->started = false;
18
+ this->ready = false;
19
spa_log_debug(this->log, "%p: suspending", this);
20
break;
21
case SPA_NODE_COMMAND_Pause:
22
this->started = false;
23
+ this->ready = false;
24
spa_log_debug(this->log, "%p: pausing", this);
25
break;
26
case SPA_NODE_COMMAND_Flush:
27
28
spa_log_error(this->log, "%p: can't send command %d: %s",
29
this, SPA_NODE_COMMAND_ID(command),
30
spa_strerror(res));
31
- return res;
32
}
33
34
- if (this->target != this->follower) {
35
+ if (res >= 0 && this->target != this->follower) {
36
if ((res = spa_node_send_command(this->follower, command)) < 0) {
37
spa_log_error(this->log, "%p: can't send command %d: %s",
38
this, SPA_NODE_COMMAND_ID(command),
39
spa_strerror(res));
40
- return res;
41
}
42
}
43
switch (SPA_NODE_COMMAND_ID(command)) {
44
case SPA_NODE_COMMAND_Start:
45
- spa_log_debug(this->log, "%p: started", this);
46
+ if (res < 0) {
47
+ spa_log_debug(this->log, "%p: start failed", this);
48
+ this->ready = false;
49
+ configure_format(this, 0, NULL);
50
+ } else {
51
+ this->started = true;
52
+ spa_log_debug(this->log, "%p: started", this);
53
+ }
54
break;
55
case SPA_NODE_COMMAND_Suspend:
56
configure_format(this, 0, NULL);
57
58
59
spa_log_trace_fp(this->log, "%p: ready %d", this, status);
60
61
- if (!this->started) {
62
+ if (!this->ready) {
63
spa_log_info(this->log, "%p: ready stopped node", this);
64
return -EIO;
65
}
66
67
if (this->direction == SPA_DIRECTION_OUTPUT) {
68
int retry = 8;
69
while (retry--) {
70
- status = spa_node_process(this->convert);
71
+ status = spa_node_process_fast(this->convert);
72
if (status & SPA_STATUS_HAVE_DATA)
73
break;
74
75
if (status & SPA_STATUS_NEED_DATA) {
76
- status = spa_node_process(this->follower);
77
+ status = spa_node_process_fast(this->follower);
78
if (!(status & SPA_STATUS_HAVE_DATA))
79
break;
80
}
81
82
if (this->target == this->follower) {
83
if (this->io_position)
84
this->io_rate_match.size = this->io_position->clock.duration;
85
- return spa_node_process(this->follower);
86
+ return spa_node_process_fast(this->follower);
87
}
88
89
if (this->direction == SPA_DIRECTION_INPUT) {
90
91
* First we run the converter to process the input for the follower
92
* then if it produced data, we run the follower. */
93
while (retry--) {
94
- status = spa_node_process(this->convert);
95
+ status = spa_node_process_fast(this->convert);
96
/* schedule the follower when the converter needed
97
* a recycled buffer */
98
if (status == -EPIPE || status == 0)
99
100
if (status & (SPA_STATUS_HAVE_DATA | SPA_STATUS_DRAINED)) {
101
/* as long as the converter produced something or
102
* is drained, process the follower. */
103
- fstatus = spa_node_process(this->follower);
104
+ fstatus = spa_node_process_fast(this->follower);
105
if (fstatus < 0) {
106
status = fstatus;
107
break;
108
109
/* output node (source). First run the converter to make
110
* sure we push out any queued data. Then when it needs
111
* more data, schedule the follower. */
112
- status = spa_node_process(this->convert);
113
+ status = spa_node_process_fast(this->convert);
114
if (status == 0)
115
status = SPA_STATUS_NEED_DATA;
116
else if (status < 0)
117
118
if (status & SPA_STATUS_NEED_DATA) {
119
/* the converter needs more data, schedule the
120
* follower */
121
- fstatus = spa_node_process(this->follower);
122
+ fstatus = spa_node_process_fast(this->follower);
123
if (fstatus < 0) {
124
status = fstatus;
125
break;
126
127
spa_node_call_xrun(&this->callbacks, 0, 0, NULL);
128
129
} else {
130
- status = spa_node_process(this->follower);
131
+ status = spa_node_process_fast(this->follower);
132
}
133
spa_log_trace_fp(this->log, "%p: process status:%d", this, status);
134
135
pipewire-0.3.70.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.71.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
114
1
2
unsigned int ramp_volume:1;
3
unsigned int drained:1;
4
unsigned int rate_adjust:1;
5
+ unsigned int port_ignore_latency:1;
6
7
uint32_t empty_size;
8
float *empty;
9
10
if (full)
11
port->info.change_mask = port->info_all;
12
if (port->info.change_mask) {
13
- struct spa_dict_item items3;
14
+ struct spa_dict_item items4;
15
uint32_t n_items = 0;
16
17
if (PORT_IS_DSP(this, port->direction, port->id)) {
18
19
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNEL, port->position);
20
if (port->is_monitor)
21
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_MONITOR, "true");
22
+ if (this->port_ignore_latency)
23
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_IGNORE_LATENCY, "true");
24
} else if (PORT_IS_CONTROL(this, port->direction, port->id)) {
25
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "control");
26
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi");
27
28
out->format.info.raw.channels,
29
out->format.info.raw.rate);
30
31
- if (this->props.resample_disabled &&
32
+ if (this->props.resample_disabled && !this->resample_peaks &&
33
in->format.info.raw.rate != out->format.info.raw.rate)
34
return -EPERM;
35
36
37
if (!in->have_format || !out->have_format)
38
return -EINVAL;
39
40
- rate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE;
41
+ rate = this->io_position ? this->io_position->clock.target_rate.denom : DEFAULT_RATE;
42
43
/* in DSP mode we always convert to the DSP rate */
44
if (in->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp)
45
46
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
47
} else {
48
uint32_t rate = this->io_position ?
49
- this->io_position->clock.rate.denom : DEFAULT_RATE;
50
+ this->io_position->clock.target_rate.denom : DEFAULT_RATE;
51
52
*param = spa_pod_builder_add_object(builder,
53
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
54
55
/* collect the other port rate */
56
dir = &this->dirSPA_DIRECTION_REVERSE(direction);
57
if (dir->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp)
58
- orate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE;
59
+ orate = this->io_position ? this->io_position->clock.target_rate.denom : DEFAULT_RATE;
60
else
61
orate = dir->format.info.raw.rate;
62
63
64
}
65
}
66
67
+ resample_passthrough = resample_is_passthrough(this);
68
+
69
/* calculate how many samples we are going to produce. */
70
if (this->direction == SPA_DIRECTION_INPUT) {
71
/* in split mode we need to output exactly the size of the
72
* duration so we don't try to flush early */
73
max_out = quant_samples;
74
+ if (!in_avail || this->drained) {
75
+ n_out = max_out - SPA_MIN(max_out, this->out_offset);
76
+ /* no input, ask for more, update rate-match first */
77
+ resample_update_rate_match(this, resample_passthrough, n_out, 0);
78
+ spa_log_trace_fp(this->log, "%p: no input drained:%d", this, this->drained);
79
+ res |= this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA;
80
+ return res;
81
+ }
82
flush_out = false;
83
} else {
84
/* in merge mode we consume one duration of samples and
85
86
/* we only need to output the remaining samples */
87
n_out = max_out - SPA_MIN(max_out, this->out_offset);
88
89
- resample_passthrough = resample_is_passthrough(this);
90
-
91
/* calculate how many samples we are going to consume. */
92
if (this->direction == SPA_DIRECTION_INPUT) {
93
- if (!in_avail || this->drained) {
94
- /* no input, ask for more, update rate-match first */
95
- resample_update_rate_match(this, resample_passthrough, n_out, 0);
96
- spa_log_trace_fp(this->log, "%p: no input drained:%d", this, this->drained);
97
- res |= this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA;
98
- return res;
99
- }
100
- /* else figure out how much input samples we need to consume */
101
+ /* figure out how much input samples we need to consume */
102
n_samples = SPA_MIN(n_samples,
103
resample_get_in_size(this, resample_passthrough, n_out));
104
} else {
105
106
if (s != NULL)
107
this->props.n_channels = parse_position(this->props.channel_map, s, strlen(s));
108
}
109
+ else if (spa_streq(k, SPA_KEY_PORT_IGNORE_LATENCY))
110
+ this->port_ignore_latency = spa_atob(s);
111
else
112
audioconvert_set_param(this, k, s);
113
}
114
pipewire-0.3.70.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.71.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
33
1
2
#define DEFAULT_CHANNELS 2
3
4
#define MAX_BUFFERS 64
5
-#define MAX_PORTS 128
6
+#define MAX_PORTS 512
7
#define MAX_CHANNELS 64
8
#define MAX_ALIGN MIX_OPS_MAX_ALIGN
9
10
11
struct port *in_portsMAX_PORTS;
12
struct port out_ports1;
13
14
+ struct buffer *mix_buffersMAX_PORTS;
15
+ const void *mix_datasMAX_PORTS;
16
+
17
int n_formats;
18
struct spa_audio_info format;
19
20
21
outio->buffer_id = SPA_ID_INVALID;
22
}
23
24
- buffers = alloca(MAX_PORTS * sizeof(struct buffer *));
25
- datas = alloca(MAX_PORTS * sizeof(void *));
26
- n_buffers = 0;
27
+ buffers = this->mix_buffers;
28
+ datas = this->mix_datas;
29
+ n_buffers = 0;
30
31
maxsize = UINT32_MAX;
32
33
pipewire-0.3.70.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.71.tar.gz/spa/plugins/audiomixer/mixer-dsp.c
Changed
31
1
2
static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.mixer-dsp");
3
4
#define MAX_BUFFERS 64
5
-#define MAX_PORTS 128
6
+#define MAX_PORTS 512
7
#define MAX_ALIGN MIX_OPS_MAX_ALIGN
8
9
#define PORT_DEFAULT_VOLUME 1.0
10
11
struct port *in_portsMAX_PORTS;
12
struct port out_ports1;
13
14
+ struct buffer *mix_buffersMAX_PORTS;
15
+ const void *mix_datasMAX_PORTS;
16
+
17
int n_formats;
18
struct spa_audio_info format;
19
uint32_t stride;
20
21
outio->buffer_id = SPA_ID_INVALID;
22
}
23
24
- buffers = alloca(MAX_PORTS * sizeof(struct buffer *));
25
- datas = alloca(MAX_PORTS * sizeof(void *));
26
+ buffers = this->mix_buffers;
27
+ datas = this->mix_datas;
28
n_buffers = 0;
29
30
maxsize = UINT32_MAX;
31
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/a2dp-codec-aac.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/a2dp-codec-aac.c
Changed
16
1
2
spa_pod_builder_int(b, f->value);
3
}
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
if (SPA_FLAG_IS_SET(conf.channels, AAC_CHANNELS_1 | AAC_CHANNELS_2)) {
15
spa_pod_builder_add(b,
16
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c
Changed
17
1
2
spa_pod_builder_int(b, 16000);
3
spa_pod_builder_int(b, 16000);
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
if (SPA_FLAG_IS_SET(conf.channel_mode, APTX_CHANNEL_MODE_MONO | APTX_CHANNEL_MODE_STEREO)) {
15
spa_pod_builder_add(b,
16
SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(2, 1, 2),
17
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/a2dp-codec-faststream.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/a2dp-codec-faststream.c
Changed
15
1
2
spa_pod_builder_int(b, 44100);
3
spa_pod_builder_int(b, 44100);
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
+ if (i == 0)
11
+ return -EINVAL;
12
13
position0 = SPA_AUDIO_CHANNEL_FL;
14
position1 = SPA_AUDIO_CHANNEL_FR;
15
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/a2dp-codec-ldac.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/a2dp-codec-ldac.c
Changed
17
1
2
spa_pod_builder_int(b, 96000);
3
spa_pod_builder_int(b, 96000);
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
if (conf.channel_mode & LDACBT_CHANNEL_MODE_MONO &&
15
conf.channel_mode & (LDACBT_CHANNEL_MODE_STEREO |
16
LDACBT_CHANNEL_MODE_DUAL_CHANNEL)) {
17
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c
Changed
30
1
2
{
3
const char *interface;
4
DBusMessageIter iter, array, dict, data;
5
- const char *agent_codec_key = "AgentCodec";
6
const char *agent_codec;
7
DBusMessage *r = NULL;
8
9
10
return DBUS_HANDLER_RESULT_NEED_MEMORY;
11
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
12
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
13
- dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &agent_codec_key);
14
+ dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &(const char *){ "AgentCodec" });
15
dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "s", &data);
16
- dbus_message_iter_append_basic(&data, DBUS_TYPE_BOOLEAN, &agent_codec);
17
+ dbus_message_iter_append_basic(&data, DBUS_TYPE_STRING, &agent_codec);
18
dbus_message_iter_close_container(&dict, &data);
19
dbus_message_iter_close_container(&array, &dict);
20
dbus_message_iter_close_container(&iter, &array);
21
22
23
case DBUS_TYPE_BOOLEAN:
24
{
25
- bool value;
26
+ dbus_bool_t value;
27
dbus_message_iter_get_basic(&value_i, &value);
28
if (spa_streq(key, "Connected"))
29
endpoint->connected = value;
30
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
56
1
2
3
static int codec_switch_start_timer(struct rfcomm *rfcomm, int timeout_msec);
4
5
+static void process_xevent_indicator(struct rfcomm *rfcomm, unsigned int level, unsigned int nlevels)
6
+{
7
+ struct impl *backend = rfcomm->backend;
8
+ uint8_t perc;
9
+
10
+ spa_log_debug(backend->log, "AT+XEVENT level:%u nlevels:%u", level, nlevels);
11
+
12
+ if (nlevels <= 1)
13
+ return;
14
+
15
+ /* 0 <= level < nlevels */
16
+ perc = SPA_MIN(level, nlevels - 1) * 100 / (nlevels - 1);
17
+ spa_bt_device_report_battery_level(rfcomm->device, perc);
18
+}
19
+
20
static void process_iphoneaccev_indicator(struct rfcomm *rfcomm, unsigned int key, unsigned int value)
21
{
22
struct impl *backend = rfcomm->backend;
23
24
unsigned int indicator;
25
unsigned int indicator_value;
26
unsigned int value;
27
+ unsigned int xevent_level;
28
+ unsigned int xevent_nlevels;
29
int xapl_vendor;
30
int xapl_product;
31
int xapl_features;
32
33
rfcomm_send_reply(rfcomm, "+XAPL=iPhone,%u", SPA_BT_HFP_HF_XAPL_FEATURE_BATTERY_REPORTING);
34
}
35
rfcomm_send_reply(rfcomm, "OK");
36
+ } else if (spa_strstartswith(buf, "AT+XEVENT=USER-AGENT")) {
37
+ rfcomm_send_reply(rfcomm, "OK");
38
+ } else if (sscanf(buf, "AT+XEVENT=BATTERY,%u,%u,%*u,%*u", &xevent_level, &xevent_nlevels) == 2) {
39
+ process_xevent_indicator(rfcomm, xevent_level, xevent_nlevels);
40
+ rfcomm_send_reply(rfcomm, "OK");
41
+ } else if (sscanf(buf, "AT+XEVENT=BATTERY,%u", &xevent_level) == 1) {
42
+ process_xevent_indicator(rfcomm, xevent_level + 1, 11);
43
+ rfcomm_send_reply(rfcomm, "OK");
44
} else if (sscanf(buf, "AT+IPHONEACCEV=%u%n", &count, &r) == 1) {
45
if (count < 1 || count > 100)
46
return false;
47
48
sco_close(backend);
49
50
if (backend->modemmanager) {
51
- mm_unregister(backend);
52
+ mm_unregister(backend->modemmanager);
53
backend->modemmanager = NULL;
54
}
55
56
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c
Changed
194
1
2
3
#include <spa/param/audio/format.h>
4
#include <spa/param/audio/format-utils.h>
5
+#include <spa/utils/string.h>
6
7
#include <lc3.h>
8
9
10
struct pac_data {
11
const uint8_t *data;
12
size_t size;
13
+ uint32_t locations;
14
};
15
16
typedef struct {
17
18
uint8_t n_blks;
19
} bap_lc3_t;
20
21
+static const struct {
22
+ uint32_t bit;
23
+ enum spa_audio_channel channel;
24
+} channel_bits = {
25
+ { LC3_CONFIG_CHNL_FL, SPA_AUDIO_CHANNEL_FL },
26
+ { LC3_CONFIG_CHNL_FR, SPA_AUDIO_CHANNEL_FR },
27
+ { LC3_CONFIG_CHNL_FC, SPA_AUDIO_CHANNEL_FC },
28
+ { LC3_CONFIG_CHNL_LFE, SPA_AUDIO_CHANNEL_LFE },
29
+ { LC3_CONFIG_CHNL_BL, SPA_AUDIO_CHANNEL_RL },
30
+ { LC3_CONFIG_CHNL_BR, SPA_AUDIO_CHANNEL_RR },
31
+ { LC3_CONFIG_CHNL_FLC, SPA_AUDIO_CHANNEL_FLC },
32
+ { LC3_CONFIG_CHNL_FRC, SPA_AUDIO_CHANNEL_FRC },
33
+ { LC3_CONFIG_CHNL_BC, SPA_AUDIO_CHANNEL_BC },
34
+ { LC3_CONFIG_CHNL_LFE2, SPA_AUDIO_CHANNEL_LFE2 },
35
+ { LC3_CONFIG_CHNL_SL, SPA_AUDIO_CHANNEL_SL },
36
+ { LC3_CONFIG_CHNL_SR, SPA_AUDIO_CHANNEL_SR },
37
+ { LC3_CONFIG_CHNL_TFL, SPA_AUDIO_CHANNEL_TFL },
38
+ { LC3_CONFIG_CHNL_TFR, SPA_AUDIO_CHANNEL_TFR },
39
+ { LC3_CONFIG_CHNL_TFC, SPA_AUDIO_CHANNEL_TFC },
40
+ { LC3_CONFIG_CHNL_TC, SPA_AUDIO_CHANNEL_TC },
41
+ { LC3_CONFIG_CHNL_TBL, SPA_AUDIO_CHANNEL_TRL },
42
+ { LC3_CONFIG_CHNL_TBR, SPA_AUDIO_CHANNEL_TRR },
43
+ { LC3_CONFIG_CHNL_TSL, SPA_AUDIO_CHANNEL_TSL },
44
+ { LC3_CONFIG_CHNL_TSR, SPA_AUDIO_CHANNEL_TSR },
45
+ { LC3_CONFIG_CHNL_TBC, SPA_AUDIO_CHANNEL_TRC },
46
+ { LC3_CONFIG_CHNL_BFC, SPA_AUDIO_CHANNEL_BC },
47
+ { LC3_CONFIG_CHNL_BFL, SPA_AUDIO_CHANNEL_BLC },
48
+ { LC3_CONFIG_CHNL_BFR, SPA_AUDIO_CHANNEL_BRC },
49
+ { LC3_CONFIG_CHNL_FLW, SPA_AUDIO_CHANNEL_FLW },
50
+ { LC3_CONFIG_CHNL_FRW, SPA_AUDIO_CHANNEL_FRW },
51
+ { LC3_CONFIG_CHNL_LS, SPA_AUDIO_CHANNEL_SL }, /* is it the right mapping? */
52
+ { LC3_CONFIG_CHNL_RS, SPA_AUDIO_CHANNEL_SR }, /* is it the right mapping? */
53
+};
54
+
55
static int write_ltv(uint8_t *dest, uint8_t type, void* value, size_t len)
56
{
57
struct ltv *ltv = (struct ltv *)dest;
58
59
return num;
60
}
61
62
+static int select_channels(uint8_t channels, uint32_t locations, uint32_t *mapping)
63
+{
64
+ unsigned int i, num;
65
+
66
+ if (channels & LC3_CHAN_2)
67
+ num = 2;
68
+ else if (channels & LC3_CHAN_1)
69
+ num = 1;
70
+ else
71
+ return -1;
72
+
73
+ if (!locations) {
74
+ *mapping = 0; /* mono (omit Audio_Channel_Allocation) */
75
+ return 0;
76
+ }
77
+
78
+ /* XXX: select some channels, but upper level should tell us what */
79
+ *mapping = 0;
80
+ for (i = 0; i < SPA_N_ELEMENTS(channel_bits); ++i) {
81
+ if (locations & channel_bitsi.bit) {
82
+ *mapping |= channel_bitsi.bit;
83
+ --num;
84
+ if (num == 0)
85
+ break;
86
+ }
87
+ }
88
+
89
+ return 0;
90
+}
91
+
92
static bool select_config(bap_lc3_t *conf, const struct pac_data *pac)
93
{
94
const uint8_t *data = pac->data;
95
96
spa_return_val_if_fail(ltv->len == 2, false);
97
{
98
uint8_t channels = ltv->value0;
99
- /* XXX: we hardcode mono or stereo stream */
100
- if (channels & LC3_CHAN_2)
101
- conf->channels = LC3_CONFIG_CHNL_FR | LC3_CONFIG_CHNL_FL;
102
- else if (channels & LC3_CHAN_1)
103
- conf->channels = 0; /* mono (omit Audio_Channel_Allocation) */
104
- else
105
+
106
+ if (select_channels(channels, pac->locations, &conf->channels) < 0)
107
return false;
108
}
109
break;
110
111
int npacs;
112
bap_lc3_t conf;
113
uint8_t *data = config;
114
+ uint32_t locations = 0;
115
+ int i;
116
117
if (caps == NULL)
118
return -EINVAL;
119
120
+ if (settings) {
121
+ for (i = 0; i < (int)settings->n_items; ++i)
122
+ if (spa_streq(settings->itemsi.key, "bluez5.bap.locations"))
123
+ sscanf(settings->itemsi.value, "%"PRIu32, &locations);
124
+ }
125
+
126
/* Select best conf from those possible */
127
npacs = parse_bluez_pacs(caps, caps_size, pacs);
128
if (npacs < 0)
129
130
else if (npacs == 0)
131
return -EINVAL;
132
133
+ for (i = 0; i < npacs; ++i)
134
+ pacsi.locations = locations;
135
+
136
qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp);
137
138
if (!select_config(&conf, &pacs0))
139
140
int res1, res2;
141
142
/* Order selected configurations by preference */
143
- res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1);
144
- res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2);
145
+ res1 = codec->select_config(codec, 0, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1);
146
+ res2 = codec->select_config(codec, 0, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2);
147
148
return conf_cmp(&conf1, res1, &conf2, res2);
149
}
150
151
position0 = SPA_AUDIO_CHANNEL_MONO;
152
n_positions = 1;
153
} else {
154
-#define CHANNEL_2_SPACHANNEL(channel,spa_channel) if (channels & channel) positionn_positions++ = spa_channel;
155
-
156
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FL, SPA_AUDIO_CHANNEL_FL);
157
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FR, SPA_AUDIO_CHANNEL_FR);
158
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FC, SPA_AUDIO_CHANNEL_FC);
159
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_LFE, SPA_AUDIO_CHANNEL_LFE);
160
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_BL, SPA_AUDIO_CHANNEL_RL);
161
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_BR, SPA_AUDIO_CHANNEL_RR);
162
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FLC, SPA_AUDIO_CHANNEL_FLC);
163
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FRC, SPA_AUDIO_CHANNEL_FRC);
164
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_BC, SPA_AUDIO_CHANNEL_BC);
165
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_LFE2, SPA_AUDIO_CHANNEL_LFE2);
166
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_SL, SPA_AUDIO_CHANNEL_SL);
167
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_SR, SPA_AUDIO_CHANNEL_SR);
168
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TFL, SPA_AUDIO_CHANNEL_TFL);
169
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TFR, SPA_AUDIO_CHANNEL_TFR);
170
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TFC, SPA_AUDIO_CHANNEL_TFC);
171
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TC, SPA_AUDIO_CHANNEL_TC);
172
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TBL, SPA_AUDIO_CHANNEL_TRL);
173
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TBR, SPA_AUDIO_CHANNEL_TRR);
174
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TSL, SPA_AUDIO_CHANNEL_TSL);
175
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TSR, SPA_AUDIO_CHANNEL_TSR);
176
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_TBC, SPA_AUDIO_CHANNEL_TRC);
177
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_BFC, SPA_AUDIO_CHANNEL_BC);
178
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_BFL, SPA_AUDIO_CHANNEL_BLC);
179
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_BFR, SPA_AUDIO_CHANNEL_BRC);
180
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FLW, SPA_AUDIO_CHANNEL_FLW);
181
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_FRW, SPA_AUDIO_CHANNEL_FRW);
182
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_LS, SPA_AUDIO_CHANNEL_LLFE); /* is it the right mapping? */
183
- CHANNEL_2_SPACHANNEL(LC3_CONFIG_CHNL_RS, SPA_AUDIO_CHANNEL_RLFE); /* is it the right mapping? */
184
-
185
-#undef CHANNEL_2_SPACHANNEL
186
+ unsigned int i;
187
+
188
+ for (i = 0; i < SPA_N_ELEMENTS(channel_bits); ++i)
189
+ if (channels & channel_bitsi.bit)
190
+ positionn_positions++ = channel_bitsi.channel;
191
}
192
193
if (n_positions != n_channels)
194
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/bluez-hardware.conf -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/bluez-hardware.conf
Changed
9
1
2
{ name = "SoundCore 2", no-features = sbc-xq }, # #pipewire-2291
3
{ name = "Tribit MAXSound Plus", no-features = hw-volume }, # #pipewire-1592
4
{ name = "Urbanista Stockholm Plus", no-features = msbc-alt1, msbc-alt1-rtl },
5
+ { name = "WorkTunes Connect", no-features = hw-volume }, # 3M WorkTunes Connect
6
7
{ address = "~^44:5e:cd:", no-features = faststream, a2dp-duplex }, # #pipewire-1756
8
9
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
201
1
2
#include "iso-io.h"
3
#include "defs.h"
4
5
-#include "bap-codec-caps.h"
6
-
7
static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5");
8
#undef SPA_LOG_TOPIC_DEFAULT
9
#define SPA_LOG_TOPIC_DEFAULT &log_topic
10
11
const struct media_codec *codec;
12
bool sink;
13
const char *err_msg = "Unknown error";
14
+ struct spa_dict settings;
15
+ struct spa_dict_item setting_itemsSPA_N_ELEMENTS(monitor->global_setting_items) + 1;
16
+ int i;
17
18
const char *endpoint_path = NULL;
19
uint8_t capsA2DP_MAX_CAPS_SIZE;
20
uint8_t configA2DP_MAX_CAPS_SIZE;
21
+ char locations64 = {0};
22
int caps_size = 0;
23
int conf_size;
24
DBusMessageIter dict;
25
26
endpoint_qos.preferred_delay_min = v;
27
else if (spa_streq(key, "PreferredMaximumDelay"))
28
endpoint_qos.preferred_delay_max = v;
29
+ else if (spa_streq(key, "Location"))
30
+ spa_scnprintf(locations, sizeof(locations), "%"PRIu32, v);
31
else
32
spa_log_info(monitor->log, "Unknown property %s", key);
33
} else {
34
35
ep->acceptor = true;
36
}
37
38
- /* TODO: determine which device the SelectConfiguration() call is associated
39
- * with; it's known here based on the remote endpoint.
40
- */
41
- conf_size = codec->select_config(codec, 0, caps, caps_size, &monitor->default_audio_info, NULL, config);
42
+ for (i = 0; i < (int)monitor->global_settings.n_items; ++i)
43
+ setting_itemsi = monitor->global_settings.itemsi;
44
+ setting_itemsi = SPA_DICT_ITEM_INIT("bluez5.bap.locations", locations);
45
+ settings = SPA_DICT_INIT(setting_items, monitor->global_settings.n_items + 1);
46
+
47
+ conf_size = codec->select_config(codec, 0, caps, caps_size, &monitor->default_audio_info, &settings, config);
48
if (conf_size < 0) {
49
spa_log_error(monitor->log, "can't select config: %d (%s)",
50
conf_size, spa_strerror(conf_size));
51
52
53
if (transport->acquire_call) {
54
dbus_pending_call_cancel(transport->acquire_call);
55
+ dbus_pending_call_unref(transport->acquire_call);
56
transport->acquire_call = NULL;
57
}
58
59
+ if (transport->volume_call) {
60
+ dbus_pending_call_cancel(transport->volume_call);
61
+ dbus_pending_call_unref(transport->volume_call);
62
+ transport->volume_call = NULL;
63
+ }
64
+
65
if (transport->fd >= 0) {
66
spa_bt_player_set_state(transport->device->adapter->dummy_player, SPA_BT_PLAYER_STOPPED);
67
68
69
else
70
transport->bap_cis = value;
71
}
72
- else if (spa_streq(key, "Location")) {
73
- uint32_t value;
74
-
75
- if (type != DBUS_TYPE_UINT32)
76
- goto next;
77
- dbus_message_iter_get_basic(&it1, &value);
78
-
79
- spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
80
- transport->bap_location = value;
81
- }
82
next:
83
dbus_message_iter_next(props_iter);
84
}
85
return 0;
86
}
87
88
-static int transport_set_property_volume(struct spa_bt_transport *transport, uint16_t value)
89
+static void transport_set_property_volume_reply(DBusPendingCall *pending, void *user_data)
90
+{
91
+ struct spa_bt_transport *transport = user_data;
92
+ struct spa_bt_monitor *monitor = transport->monitor;
93
+ DBusError err = DBUS_ERROR_INIT;
94
+ DBusMessage *r;
95
+
96
+ r = dbus_pending_call_steal_reply(pending);
97
+
98
+ spa_assert(transport->volume_call == pending);
99
+ dbus_pending_call_unref(pending);
100
+ transport->volume_call = NULL;
101
+
102
+ if (dbus_set_error_from_message(&err, r)) {
103
+ spa_log_info(monitor->log, "transport %p: set volume failed for transport %s: %s",
104
+ transport, transport->path, err.message);
105
+ dbus_error_free(&err);
106
+ } else {
107
+ spa_log_debug(monitor->log, "transport %p: set volume complete",
108
+ transport);
109
+ }
110
+
111
+ dbus_message_unref(r);
112
+}
113
+
114
+static void transport_set_property_volume(struct spa_bt_transport *transport, uint16_t value)
115
{
116
struct spa_bt_monitor *monitor = transport->monitor;
117
- DBusMessage *m, *r;
118
+ DBusMessage *m;
119
DBusMessageIter it2;
120
DBusError err;
121
const char *interface = BLUEZ_MEDIA_TRANSPORT_INTERFACE;
122
const char *name = "Volume";
123
int res = 0;
124
+ dbus_bool_t ret;
125
+
126
+ if (transport->volume_call) {
127
+ dbus_pending_call_cancel(transport->volume_call);
128
+ dbus_pending_call_unref(transport->volume_call);
129
+ transport->volume_call = NULL;
130
+ }
131
132
m = dbus_message_new_method_call(BLUEZ_SERVICE,
133
transport->path,
134
DBUS_INTERFACE_PROPERTIES,
135
"Set");
136
- if (m == NULL)
137
- return -ENOMEM;
138
+ if (m == NULL) {
139
+ res = -ENOMEM;
140
+ goto fail;
141
+ }
142
143
dbus_message_iter_init_append(m, &it0);
144
dbus_message_iter_append_basic(&it0, DBUS_TYPE_STRING, &interface);
145
146
147
dbus_error_init(&err);
148
149
- r = dbus_connection_send_with_reply_and_block(monitor->conn, m, -1, &err);
150
-
151
+ ret = dbus_connection_send_with_reply(monitor->conn, m, &transport->volume_call, -1);
152
dbus_message_unref(m);
153
154
- if (r == NULL) {
155
- spa_log_error(monitor->log, "set volume %u failed for transport %s (%s)",
156
- value, transport->path, err.message);
157
- dbus_error_free(&err);
158
- return -EIO;
159
+ if (!ret || !transport->volume_call) {
160
+ res = -EIO;
161
+ goto fail;
162
}
163
164
- if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR)
165
+ ret = dbus_pending_call_set_notify(transport->volume_call,
166
+ transport_set_property_volume_reply, transport, NULL);
167
+ if (!ret) {
168
res = -EIO;
169
+ goto fail;
170
+ }
171
172
- dbus_message_unref(r);
173
-
174
- spa_log_debug(monitor->log, "transport %p: set volume to %d", transport, value);
175
+ spa_log_debug(monitor->log, "transport %p: setting volume to %d", transport, value);
176
+ return;
177
178
- return res;
179
+fail:
180
+ spa_log_debug(monitor->log, "transport %p: failed to set volume %d: %s",
181
+ transport, value, spa_strerror(res));
182
}
183
184
static int transport_set_volume(void *data, int id, float volume)
185
186
187
if (transport->acquire_call) {
188
dbus_pending_call_cancel(transport->acquire_call);
189
+ dbus_pending_call_unref(transport->acquire_call);
190
transport->acquire_call = NULL;
191
}
192
193
194
return spa_bt_backend_supports_codec(monitor->backend, device, codec);
195
}
196
197
-static void bap_update_codec_location(struct spa_bt_transport *t)
198
-{
199
- uint8_t *data = t->configuration;
200
- size_t size = t->configuration_len;
201
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/dbus-monitor.h -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/dbus-monitor.h
Changed
7
1
2
3
void dbus_monitor_clear(struct dbus_monitor *monitor);
4
5
-#endif DBUS_MONITOR_H_
6
+#endif // DBUS_MONITOR_H_
7
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/defs.h
Changed
17
1
2
unsigned int latency_us;
3
uint8_t bap_cig;
4
uint8_t bap_cis;
5
- uint32_t bap_location;
6
uint32_t bap_interval;
7
8
struct spa_bt_iso_io *iso_io;
9
10
struct spa_source volume_timer;
11
struct spa_source release_timer;
12
DBusPendingCall *acquire_call;
13
+ DBusPendingCall *volume_call;
14
15
struct spa_hook_list listener_list;
16
struct spa_callbacks impl;
17
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/media-source.c
Changed
137
1
2
unsigned int is_input:1;
3
unsigned int is_duplex:1;
4
unsigned int is_internal:1;
5
- unsigned int use_duplex_source:1;
6
7
unsigned int node_latency;
8
9
10
uint8_t buffer_read4096;
11
struct timespec now;
12
uint64_t sample_count;
13
-
14
- int duplex_timerfd;
15
- uint64_t duplex_timeout;
16
};
17
18
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0)
19
20
spa_loop_remove_source(this->data_loop, &this->source);
21
}
22
23
-static int set_duplex_timeout(struct impl *this, uint64_t timeout)
24
-{
25
- struct itimerspec ts;
26
- ts.it_value.tv_sec = timeout / SPA_NSEC_PER_SEC;
27
- ts.it_value.tv_nsec = timeout % SPA_NSEC_PER_SEC;
28
- ts.it_interval.tv_sec = 0;
29
- ts.it_interval.tv_nsec = 0;
30
- return spa_system_timerfd_settime(this->data_system,
31
- this->duplex_timerfd, 0, &ts, NULL);
32
-}
33
-
34
-static void media_on_duplex_timeout(struct spa_source *source)
35
-{
36
- struct impl *this = source->data;
37
- uint64_t exp;
38
- int res;
39
-
40
- if ((res = spa_system_timerfd_read(this->data_system, this->duplex_timerfd, &exp)) < 0) {
41
- if (res != -EAGAIN)
42
- spa_log_warn(this->log, "error reading timerfd: %s", spa_strerror(res));
43
- return;
44
- }
45
-
46
- set_duplex_timeout(this, this->duplex_timeout);
47
-
48
- media_on_ready_read(source);
49
-}
50
-
51
static int setup_matching(struct impl *this)
52
{
53
struct port *port = &this->port;
54
55
56
this->source.data = this;
57
58
- if (!this->use_duplex_source) {
59
- this->source.fd = this->fd;
60
- this->source.func = media_on_ready_read;
61
- this->source.mask = SPA_IO_IN;
62
- this->source.rmask = 0;
63
- spa_loop_add_source(this->data_loop, &this->source);
64
- } else {
65
- /*
66
- * XXX: For an unknown reason (on Linux 5.13.10), the socket when working with
67
- * XXX: "duplex" stream sometimes stops waking up from the poll, even though
68
- * XXX: you can recv() from the socket with no problem.
69
- * XXX:
70
- * XXX: The reason for this should be found and fixed.
71
- * XXX: To work around this, for now we just do the stupid thing and poll
72
- * XXX: on a timer, chosen so that it's fast enough for the aptX-LL codec
73
- * XXX: we currently support (which sends mSBC data), and also for Opus
74
- * XXX: forward stream.
75
- */
76
- this->source.fd = this->duplex_timerfd;
77
- this->source.func = media_on_duplex_timeout;
78
- this->source.mask = SPA_IO_IN;
79
- this->source.rmask = 0;
80
- spa_loop_add_source(this->data_loop, &this->source);
81
-
82
- this->duplex_timeout = SPA_NSEC_PER_MSEC * 25/10;
83
- set_duplex_timeout(this, this->duplex_timeout);
84
- }
85
+ this->source.fd = this->fd;
86
+ this->source.func = media_on_ready_read;
87
+ this->source.mask = SPA_IO_IN;
88
+ this->source.rmask = 0;
89
+ if ((res = spa_loop_add_source(this->data_loop, &this->source)) < 0)
90
+ spa_log_error(this->log, "%p: failed to add poll source: %s", this,
91
+ spa_strerror(res));
92
93
this->sample_count = 0;
94
95
96
97
this->transport_started = false;
98
99
- set_duplex_timeout(this, 0);
100
-
101
if (this->source.loop)
102
spa_loop_remove_source(this->data_loop, &this->source);
103
104
105
if (this->transport)
106
spa_hook_remove(&this->transport_listener);
107
spa_system_close(this->data_system, this->timerfd);
108
- if (this->duplex_timerfd >= 0) {
109
- spa_system_close(this->data_system, this->duplex_timerfd);
110
- this->duplex_timerfd = -1;
111
- }
112
spa_bt_decode_buffer_clear(&port->buffer);
113
return 0;
114
}
115
116
this->codec = this->codec->duplex_codec;
117
this->is_input = true;
118
}
119
- this->use_duplex_source = this->is_duplex || (this->codec->duplex_codec != NULL);
120
121
if (this->codec->bap)
122
this->is_input = this->transport->bap_initiator;
123
124
this->timerfd = spa_system_timerfd_create(this->data_system,
125
CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
126
127
- if (this->use_duplex_source) {
128
- this->duplex_timerfd = spa_system_timerfd_create(this->data_system,
129
- CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
130
- } else {
131
- this->duplex_timerfd = -1;
132
- }
133
-
134
this->node_latency = 512;
135
136
set_latency(this, false);
137
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/modemmanager.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/modemmanager.c
Changed
201
1
2
};
3
4
struct impl {
5
- struct spa_bt_monitor *monitor;
6
-
7
struct spa_log *log;
8
DBusConnection *conn;
9
10
11
static bool mm_dbus_connection_send_with_reply(struct impl *this, DBusMessage *m, DBusPendingCall **pending_return,
12
DBusPendingCallNotifyFunction function, void *user_data)
13
{
14
- dbus_bool_t dbus_ret;
15
-
16
spa_assert(*pending_return == NULL);
17
18
- dbus_ret = dbus_connection_send_with_reply(this->conn, m, pending_return, -1);
19
- if (!dbus_ret || *pending_return == NULL) {
20
+ DBusPendingCall *pending_call;
21
+ bool ret = dbus_connection_send_with_reply(this->conn, m, &pending_call, -1);
22
+ if (!ret) {
23
spa_log_debug(this->log, "dbus call failure");
24
- return false;
25
+ goto out;
26
}
27
28
- dbus_ret = dbus_pending_call_set_notify(*pending_return, function, user_data, NULL);
29
- if (!dbus_ret) {
30
+ spa_assert(pending_call);
31
+
32
+ ret = dbus_pending_call_set_notify(pending_call, function, user_data, NULL);
33
+ if (!ret) {
34
spa_log_debug(this->log, "dbus set notify failure");
35
- dbus_pending_call_cancel(*pending_return);
36
- dbus_pending_call_unref(*pending_return);
37
- *pending_return = NULL;
38
- return false;
39
+ dbus_pending_call_cancel(pending_call);
40
+ dbus_pending_call_unref(pending_call);
41
+ goto out;
42
}
43
44
- return true;
45
+ *pending_return = pending_call;
46
+
47
+out:
48
+ dbus_message_unref(m);
49
+
50
+ return ret;
51
}
52
53
static int mm_state_to_clcc(struct impl *this, MMCallState state)
54
55
MMCallState state;
56
57
spa_assert(call->pending == pending);
58
- dbus_pending_call_unref(pending);
59
call->pending = NULL;
60
61
r = dbus_pending_call_steal_reply(pending);
62
+ dbus_pending_call_unref(pending);
63
if (r == NULL)
64
return;
65
66
67
DBusMessageIter i, array_i;
68
69
spa_assert(this->pending == pending);
70
- dbus_pending_call_unref(pending);
71
this->pending = NULL;
72
73
r = dbus_pending_call_steal_reply(pending);
74
+ dbus_pending_call_unref(pending);
75
if (r == NULL)
76
return;
77
78
79
} else if (dbus_message_is_signal(m, DBUS_INTERFACE_OBJECTMANAGER, DBUS_SIGNAL_INTERFACES_ADDED)) {
80
DBusMessageIter arg_i;
81
82
- spa_log_warn(this->log, "sender: %s", dbus_message_get_sender(m));
83
-
84
if (!dbus_message_iter_init(m, &arg_i) || !spa_streq(dbus_message_get_signature(m), "oa{sa{sv}}")) {
85
spa_log_error(this->log, "Invalid signature found in InterfacesAdded");
86
goto finish;
87
88
dbus_message_append_args(m, DBUS_TYPE_STRING, &mm_call_interface, DBUS_TYPE_INVALID);
89
if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_properties_reply, call_object)) {
90
spa_log_error(this->log, "dbus call failure");
91
- dbus_message_unref(m);
92
goto finish;
93
}
94
} else if (dbus_message_is_signal(m, MM_DBUS_INTERFACE_MODEM_VOICE, MM_MODEM_VOICE_SIGNAL_CALLDELETED)) {
95
96
return -EIO;
97
}
98
99
-static bool is_dbus_service_available(struct impl *this, const char *service)
100
-{
101
- DBusMessage *m, *r;
102
- DBusError err;
103
- bool success = false;
104
-
105
- m = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
106
- "org.freedesktop.DBus", "NameHasOwner");
107
- if (m == NULL)
108
- return false;
109
- dbus_message_append_args(m, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID);
110
-
111
- dbus_error_init(&err);
112
- r = dbus_connection_send_with_reply_and_block(this->conn, m, -1, &err);
113
- dbus_message_unref(m);
114
- m = NULL;
115
-
116
- if (r == NULL) {
117
- spa_log_info(this->log, "NameHasOwner failed for %s", service);
118
- dbus_error_free(&err);
119
- goto finish;
120
- }
121
-
122
- if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
123
- spa_log_error(this->log, "NameHasOwner() returned error: %s", dbus_message_get_error_name(r));
124
- goto finish;
125
- }
126
-
127
- if (!dbus_message_get_args(r, &err,
128
- DBUS_TYPE_BOOLEAN, &success,
129
- DBUS_TYPE_INVALID)) {
130
- spa_log_error(this->log, "Failed to parse NameHasOwner() reply: %s", err.message);
131
- dbus_error_free(&err);
132
- goto finish;
133
- }
134
-
135
-finish:
136
- if (r)
137
- dbus_message_unref(r);
138
-
139
- return success;
140
-}
141
-
142
bool mm_is_available(void *modemmanager)
143
{
144
struct impl *this = modemmanager;
145
146
free(data);
147
148
spa_assert(call->pending == pending);
149
- dbus_pending_call_unref(pending);
150
call->pending = NULL;
151
152
r = dbus_pending_call_steal_reply(pending);
153
+ dbus_pending_call_unref(pending);
154
if (r == NULL)
155
return;
156
157
158
free(data);
159
160
spa_assert(this->voice_pending == pending);
161
- dbus_pending_call_unref(pending);
162
this->voice_pending = NULL;
163
164
r = dbus_pending_call_steal_reply(pending);
165
+ dbus_pending_call_unref(pending);
166
if (r == NULL)
167
return;
168
169
170
}
171
if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_simple_reply, data)) {
172
spa_log_error(this->log, "dbus call failure");
173
- dbus_message_unref(m);
174
if (error)
175
*error = CMEE_AG_FAILURE;
176
return false;
177
178
}
179
if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_simple_reply, data)) {
180
spa_log_error(this->log, "dbus call failure");
181
- dbus_message_unref(m);
182
if (error)
183
*error = CMEE_AG_FAILURE;
184
return false;
185
186
dbus_message_iter_close_container(&iter, &dict);
187
if (!mm_dbus_connection_send_with_reply(this, m, &this->voice_pending, mm_get_call_create_reply, data)) {
188
spa_log_error(this->log, "dbus call failure");
189
- dbus_message_unref(m);
190
if (error)
191
*error = CMEE_AG_FAILURE;
192
return false;
193
194
dbus_message_append_args(m, DBUS_TYPE_STRING, &dtmf, DBUS_TYPE_INVALID);
195
if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_simple_reply, data)) {
196
spa_log_error(this->log, "dbus call failure");
197
- dbus_message_unref(m);
198
if (error)
199
*error = CMEE_AG_FAILURE;
200
return false;
201
pipewire-0.3.70.tar.gz/spa/plugins/bluez5/upower.c -> pipewire-0.3.71.tar.gz/spa/plugins/bluez5/upower.c
Changed
112
1
2
DBusMessageIter i, variant_i;
3
4
r = dbus_pending_call_steal_reply(pending);
5
+ dbus_pending_call_unref(pending);
6
if (r == NULL)
7
return;
8
9
10
return -EIO;
11
}
12
13
-static bool is_dbus_service_available(struct impl *this, const char *service)
14
-{
15
- DBusMessage *m, *r;
16
- DBusError err;
17
- bool success = false;
18
-
19
- m = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
20
- "org.freedesktop.DBus", "NameHasOwner");
21
- if (m == NULL)
22
- return false;
23
- dbus_message_append_args(m, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID);
24
-
25
- dbus_error_init(&err);
26
- r = dbus_connection_send_with_reply_and_block(this->conn, m, -1, &err);
27
- dbus_message_unref(m);
28
- m = NULL;
29
-
30
- if (r == NULL) {
31
- spa_log_info(this->log, "NameHasOwner failed for %s", service);
32
- dbus_error_free(&err);
33
- goto finish;
34
- }
35
-
36
- if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
37
- spa_log_error(this->log, "NameHasOwner() returned error: %s", dbus_message_get_error_name(r));
38
- goto finish;
39
- }
40
-
41
- if (!dbus_message_get_args(r, &err,
42
- DBUS_TYPE_BOOLEAN, &success,
43
- DBUS_TYPE_INVALID)) {
44
- spa_log_error(this->log, "Failed to parse NameHasOwner() reply: %s", err.message);
45
- dbus_error_free(&err);
46
- goto finish;
47
- }
48
-
49
-finish:
50
- if (r)
51
- dbus_message_unref(r);
52
-
53
- return success;
54
-}
55
-
56
void *upower_register(struct spa_log *log,
57
void *dbus_connection,
58
void (*set_battery_level)(unsigned int level, void *user_data),
59
60
this->log = log;
61
this->conn = dbus_connection;
62
this->set_battery_level = set_battery_level;
63
- this->user_data = user_data;
64
+ this->user_data = user_data;
65
66
if (add_filters(this) < 0) {
67
goto fail4;
68
}
69
70
- if (is_dbus_service_available(this, UPOWER_SERVICE)) {
71
- DBusMessage *m;
72
- DBusPendingCall *call;
73
- static const char* upower_device_interface = UPOWER_DEVICE_INTERFACE;
74
- static const char* percentage_property = "Percentage";
75
-
76
- m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get");
77
- if (m == NULL)
78
- goto fail4;
79
- dbus_message_append_args(m, DBUS_TYPE_STRING, &upower_device_interface,
80
- DBUS_TYPE_STRING, &percentage_property, DBUS_TYPE_INVALID);
81
- dbus_connection_send_with_reply(this->conn, m, &call, -1);
82
- dbus_pending_call_set_notify(call, upower_get_percentage_properties_reply, this, NULL);
83
- dbus_message_unref(m);
84
- }
85
+ DBusMessage *m;
86
+ DBusPendingCall *call;
87
88
- return this;
89
+ m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get");
90
+ if (m == NULL)
91
+ goto fail4;
92
+
93
+ dbus_message_append_args(m,
94
+ DBUS_TYPE_STRING, &(const char *){ UPOWER_DEVICE_INTERFACE },
95
+ DBUS_TYPE_STRING, &(const char *){ "Percentage" },
96
+ DBUS_TYPE_INVALID);
97
+ dbus_message_set_auto_start(m, false);
98
+ dbus_connection_send_with_reply(this->conn, m, &call, -1);
99
+ dbus_pending_call_set_notify(call, upower_get_percentage_properties_reply, this, NULL);
100
+ dbus_message_unref(m);
101
+
102
+ return this;
103
104
fail4:
105
- free(this);
106
- return NULL;
107
+ free(this);
108
+ return NULL;
109
}
110
111
void upower_unregister(void *data)
112
pipewire-0.3.70.tar.gz/spa/plugins/control/mixer.c -> pipewire-0.3.71.tar.gz/spa/plugins/control/mixer.c
Changed
33
1
2
#define NAME "control-mixer"
3
4
#define MAX_BUFFERS 64
5
-#define MAX_PORTS 128
6
+#define MAX_PORTS 512
7
8
struct buffer {
9
uint32_t id;
10
11
struct port *in_portsMAX_PORTS;
12
struct port out_ports1;
13
14
+ struct spa_pod_control *mix_ctrlMAX_PORTS;
15
+ struct spa_pod_sequence *mix_seqMAX_PORTS;
16
+
17
int n_formats;
18
19
unsigned int have_format:1;
20
21
return -EPIPE;
22
}
23
24
- ctrl = alloca(MAX_PORTS * sizeof(struct spa_pod_control *));
25
- seq = alloca(MAX_PORTS * sizeof(struct spa_pod_sequence *));
26
- n_seq = 0;
27
+ ctrl = this->mix_ctrl;
28
+ seq = this->mix_seq;
29
+ n_seq = 0;
30
31
/* collect all sequence pod on input ports */
32
for (i = 0; i < this->last_port; i++) {
33
pipewire-0.3.70.tar.gz/spa/plugins/jack/jack-client.c -> pipewire-0.3.71.tar.gz/spa/plugins/jack/jack-client.c
Changed
37
1
2
3
client->buffer_size = nframes;
4
5
+ spa_log_trace_fp(client->log, "frames %u", nframes);
6
+
7
spa_jack_client_emit_process(client);
8
9
return 0;
10
11
{
12
struct spa_jack_client *client = arg;
13
14
+ spa_log_warn(client->log, "%p", client);
15
+
16
spa_jack_client_emit_shutdown(client);
17
18
spa_hook_list_init(&client->listener_list);
19
20
21
spa_hook_list_init(&client->listener_list);
22
23
+ spa_log_info(client->log, "%p: %s", client, client_name);
24
+
25
jack_set_process_callback(client->client, jack_process, client);
26
jack_on_shutdown(client->client, jack_shutdown, client);
27
client->frame_rate = jack_get_sample_rate(client->client);
28
29
if (client->client == NULL)
30
return 0;
31
32
+ spa_log_info(client->log, "%p:", client);
33
+
34
spa_jack_client_emit_destroy(client);
35
36
if (jack_client_close(client->client) != 0)
37
pipewire-0.3.70.tar.gz/spa/plugins/jack/jack-device.c -> pipewire-0.3.71.tar.gz/spa/plugins/jack/jack-device.c
Changed
9
1
2
this = (struct impl *) handle;
3
4
this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
5
+ this->client.log = this->log;
6
7
this->device.iface = SPA_INTERFACE_INIT(
8
SPA_TYPE_INTERFACE_Device,
9
pipewire-0.3.70.tar.gz/spa/plugins/jack/jack-sink.c -> pipewire-0.3.71.tar.gz/spa/plugins/jack/jack-sink.c
Changed
65
1
2
struct spa_node node;
3
4
struct spa_log *log;
5
- struct spa_loop *data_loop;
6
7
uint64_t info_all;
8
struct spa_node_info info;
9
10
return 0;
11
}
12
13
+static inline bool is_following(struct impl *impl)
14
+{
15
+ return impl->position && impl->clock && impl->position->clock.id != impl->clock->id;
16
+}
17
+
18
static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
19
{
20
struct impl *this = object;
21
22
if (full)
23
this->info.change_mask = this->info_all;
24
if (this->info.change_mask) {
25
- struct spa_dict_item items5;
26
+ struct spa_dict_item items8;
27
char latency64;
28
snprintf(latency, sizeof(latency), "%d/%d",
29
this->client->buffer_size, this->client->frame_rate);
30
items0 = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Sink");
31
- items1 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_NAME, "JACK System");
32
+ items1 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_NAME, "JACK Sink");
33
items2 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
34
items3 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_PAUSE_ON_IDLE, "false");
35
- items4 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_LATENCY, latency);
36
+ items4 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_ALWAYS_PROCESS, "true");
37
+ items5 = SPA_DICT_ITEM_INIT("priority.driver", "30001");
38
+ items6 = SPA_DICT_ITEM_INIT("node.group", "jack-group");
39
+ items7 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_LATENCY, latency);
40
this->info.props = &SPA_DICT_INIT_ARRAY(items);
41
spa_node_emit_info(&this->hooks, &this->info);
42
this->info.change_mask = old;
43
44
{
45
struct impl *this = data;
46
47
+ if (is_following(this))
48
+ return;
49
+
50
if (this->clock) {
51
struct spa_io_clock *c = this->clock;
52
c->nsec = this->client->current_usecs * SPA_NSEC_PER_USEC;
53
54
spa_memcpy(dst, src->data, n_frames * port->stride);
55
56
io->status = SPA_STATUS_NEED_DATA;
57
-
58
- res |= SPA_STATUS_NEED_DATA;
59
}
60
- return res;
61
+ return res | SPA_STATUS_NEED_DATA;
62
}
63
64
static const struct spa_node_methods impl_node = {
65
pipewire-0.3.70.tar.gz/spa/plugins/jack/jack-source.c -> pipewire-0.3.71.tar.gz/spa/plugins/jack/jack-source.c
Changed
67
1
2
struct spa_node node;
3
4
struct spa_log *log;
5
- struct spa_loop *data_loop;
6
7
uint64_t info_all;
8
struct spa_node_info info;
9
10
if (full)
11
this->info.change_mask = this->info_all;
12
if (this->info.change_mask) {
13
- struct spa_dict_item items5;
14
+ struct spa_dict_item items8;
15
char latency64;
16
snprintf(latency, sizeof(latency), "%d/%d",
17
this->client->buffer_size, this->client->frame_rate);
18
items0 = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Source");
19
- items1 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_NAME, "JACK System");
20
+ items1 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_NAME, "JACK Source");
21
items2 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
22
items3 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_PAUSE_ON_IDLE, "false");
23
- items4 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_LATENCY, latency);
24
+ items4 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_ALWAYS_PROCESS, "true");
25
+ items5 = SPA_DICT_ITEM_INIT("priority.driver", "30000");
26
+ items6 = SPA_DICT_ITEM_INIT("node.group", "jack-group");
27
+ items7 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_LATENCY, latency);
28
this->info.props = &SPA_DICT_INIT_ARRAY(items);
29
spa_node_emit_info(&this->hooks, &this->info);
30
this->info.change_mask = old;
31
32
return 0;
33
}
34
35
+static inline bool is_following(struct impl *impl)
36
+{
37
+ return impl->position && impl->clock && impl->position->clock.id != impl->clock->id;
38
+}
39
+
40
static void client_process(void *data)
41
{
42
struct impl *this = data;
43
int res;
44
45
+ if (is_following(this))
46
+ return;
47
+
48
+ spa_log_trace_fp(this->log, "%p, process", this);
49
+
50
res = spa_node_process(&this->node);
51
52
- if (res != SPA_STATUS_OK)
53
- spa_node_call_ready(&this->callbacks, res);
54
+ spa_node_call_ready(&this->callbacks, res);
55
}
56
57
static const struct spa_jack_client_events client_events = {
58
59
60
res |= SPA_STATUS_HAVE_DATA;
61
}
62
- return res;
63
+ return res | SPA_STATUS_HAVE_DATA;
64
}
65
66
static const struct spa_node_methods impl_node = {
67
pipewire-0.3.70.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.71.tar.gz/spa/plugins/support/loop.c
Changed
128
1
2
void *data)
3
{
4
struct impl *impl = object;
5
+ spa_return_if_fail(SPA_CALLBACK_CHECK(hooks, before, 0));
6
+ spa_return_if_fail(SPA_CALLBACK_CHECK(hooks, after, 0));
7
spa_hook_list_append(&impl->hooks_list, hook, hooks, data);
8
}
9
10
11
spa_return_if_fail(pthread_equal(impl->thread, thread_id));
12
impl->enter_count++;
13
}
14
- spa_log_trace(impl->log, "%p: enter %p", impl, (void *) impl->thread);
15
+ spa_log_trace_fp(impl->log, "%p: enter %p", impl, (void *) impl->thread);
16
}
17
18
static void loop_leave(void *object)
19
20
spa_return_if_fail(impl->enter_count > 0);
21
spa_return_if_fail(pthread_equal(impl->thread, thread_id));
22
23
- spa_log_trace(impl->log, "%p: leave %p", impl, (void *) impl->thread);
24
+ spa_log_trace_fp(impl->log, "%p: leave %p", impl, (void *) impl->thread);
25
26
if (--impl->enter_count == 0) {
27
impl->thread = 0;
28
29
}
30
}
31
32
-static int loop_iterate(void *object, int timeout)
33
+static int loop_iterate_cancel(void *object, int timeout)
34
{
35
struct impl *impl = object;
36
struct spa_poll_event epMAX_EP, *e;
37
38
return nfds;
39
}
40
41
+static int loop_iterate(void *object, int timeout)
42
+{
43
+ struct impl *impl = object;
44
+ struct spa_poll_event epMAX_EP, *e;
45
+ int i, nfds;
46
+
47
+ impl->polling = true;
48
+ spa_loop_control_hook_before(&impl->hooks_list);
49
+
50
+ nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
51
+
52
+ spa_loop_control_hook_after(&impl->hooks_list);
53
+ impl->polling = false;
54
+
55
+ /* first we set all the rmasks, then call the callbacks. The reason is that
56
+ * some callback might also want to look at other sources it manages and
57
+ * can then reset the rmask to suppress the callback */
58
+ for (i = 0; i < nfds; i++) {
59
+ struct spa_source *s = epi.data;
60
+
61
+ s->rmask = epi.events;
62
+ /* already active in another iteration of the loop,
63
+ * remove it from that iteration */
64
+ if (SPA_UNLIKELY(e = s->priv))
65
+ e->data = NULL;
66
+ s->priv = &epi;
67
+ }
68
+
69
+ if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list)))
70
+ process_destroy(impl);
71
+
72
+ for (i = 0; i < nfds; i++) {
73
+ struct spa_source *s = epi.data;
74
+ if (SPA_LIKELY(s && s->rmask))
75
+ s->func(s);
76
+ }
77
+ for (i = 0; i < nfds; i++) {
78
+ struct spa_source *s = epi.data;
79
+ if (SPA_LIKELY(s)) {
80
+ s->rmask = 0;
81
+ s->priv = NULL;
82
+ }
83
+ }
84
+ return nfds;
85
+}
86
+
87
static void source_io_func(struct spa_source *source)
88
{
89
struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
90
91
.invoke = loop_invoke,
92
};
93
94
+static const struct spa_loop_control_methods impl_loop_control_cancel = {
95
+ SPA_VERSION_LOOP_CONTROL_METHODS,
96
+ .get_fd = loop_get_fd,
97
+ .add_hook = loop_add_hook,
98
+ .enter = loop_enter,
99
+ .leave = loop_leave,
100
+ .iterate = loop_iterate_cancel,
101
+ .check = loop_check,
102
+};
103
+
104
static const struct spa_loop_control_methods impl_loop_control = {
105
SPA_VERSION_LOOP_CONTROL_METHODS,
106
.get_fd = loop_get_fd,
107
108
uint32_t n_support)
109
{
110
struct impl *impl;
111
+ const char *str;
112
int res;
113
114
spa_return_val_if_fail(factory != NULL, -EINVAL);
115
116
SPA_VERSION_LOOP_UTILS,
117
&impl_loop_utils, impl);
118
119
+ if (info) {
120
+ if ((str = spa_dict_lookup(info, "loop.cancel")) != NULL &&
121
+ spa_atob(str))
122
+ impl->control.iface.cb.funcs = &impl_loop_control_cancel;
123
+ }
124
+
125
impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
126
spa_log_topic_init(impl->log, &log_topic);
127
impl->system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System);
128
pipewire-0.3.70.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.71.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
46
1
2
uint32_t posSPA_AUDIO_MAX_CHANNELS;
3
char clock_name64;
4
unsigned int debug:1;
5
+ unsigned int driver:1;
6
};
7
8
static void reset_props(struct props *props)
9
10
props->n_pos = 0;
11
strncpy(props->clock_name, DEFAULT_CLOCK_NAME, sizeof(props->clock_name));
12
props->debug = false;
13
+ props->driver = true;
14
}
15
16
#define DEFAULT_CHANNELS 2
17
18
return 0;
19
}
20
21
-static const struct spa_dict_item node_info_items = {
22
- { SPA_KEY_NODE_DRIVER, "true" },
23
-};
24
25
static void emit_node_info(struct impl *this, bool full)
26
{
27
28
if (full)
29
this->info.change_mask = this->info_all;
30
if (this->info.change_mask) {
31
+ const struct spa_dict_item node_info_items = {
32
+ { SPA_KEY_NODE_DRIVER, this->props.driver ? "true" : "false" },
33
+ };
34
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
35
spa_node_emit_info(&this->hooks, &this->info);
36
this->info.change_mask = old;
37
38
this->props.channels = atoi(s);
39
} else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) {
40
this->props.rate = atoi(s);
41
+ } else if (spa_streq(k, SPA_KEY_NODE_DRIVER)) {
42
+ this->props.driver = spa_atob(s);
43
} else if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) {
44
parse_position(this, s, strlen(s));
45
} else if (spa_streq(k, "clock.name")) {
46
pipewire-0.3.70.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.71.tar.gz/src/daemon/jack.conf.in
Changed
18
1
2
#node.force-quantum = 0
3
#jack.show-monitor = true
4
#jack.merge-monitor = true
5
+ #jack.show-midi = true
6
#jack.short-name = false
7
#jack.filter-name = false
8
#jack.filter-char = " "
9
10
#jack.default-as-system = false
11
#jack.fix-midi-events = true
12
#jack.global-buffer-size = false
13
+ #jack.max-client-ports = 768
14
+ #jack.fill-aliases = false
15
}
16
17
# client specific properties
18
pipewire-0.3.70.tar.gz/src/daemon/pipewire-aes67.conf.in -> pipewire-0.3.71.tar.gz/src/daemon/pipewire-aes67.conf.in
Changed
39
1
2
{ name = libpipewire-module-protocol-native }
3
{ name = libpipewire-module-client-node }
4
{ name = libpipewire-module-adapter }
5
- { name = libpipewire-module-rtp-source
6
+ { name = libpipewire-module-rtp-sap
7
args = {
8
+ local.ifname = eth0
9
sap.ip = 239.255.255.255
10
sap.port = 9875
11
- sess.latency.msec = 10
12
- local.ifname = eth0
13
- stream.props = {
14
- media.class = "Audio/Source"
15
- node.virtual = false
16
- device.api = aes67
17
- }
18
+
19
+ stream.rules =
20
+ {
21
+ matches =
22
+ {
23
+ rtp.session = "~.*"
24
+ }
25
+
26
+ actions = {
27
+ create-stream = {
28
+ node.virtual = false
29
+ media.class = "Audio/Source"
30
+ device.api = aes67
31
+ sess.latency.msec = 10
32
+ }
33
+ }
34
+ }
35
+
36
}
37
}
38
39
pipewire-0.3.70.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.71.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
9
1
2
# client.access = "restricted" # permissions for clients
3
#}
4
5
+ #server.dbus-name = "org.pulseaudio.Server"
6
#pulse.min.req = 128/48000 # 2.7ms
7
#pulse.default.req = 960/48000 # 20 milliseconds
8
#pulse.min.frag = 128/48000 # 2.7ms
9
pipewire-0.3.70.tar.gz/src/modules/meson.build -> pipewire-0.3.71.tar.gz/src/modules/meson.build
Changed
52
1
2
'module-example-source.c',
3
'module-fallback-sink.c',
4
'module-filter-chain.c',
5
+ 'module-jack-tunnel.c',
6
+ 'module-jackdbus-detect.c',
7
'module-link-factory.c',
8
'module-loopback.c',
9
'module-metadata.c',
10
11
dependencies : mathlib, dl_lib, pipewire_dep, audioconvert_dep,
12
)
13
14
+build_module_jack_tunnel = jack_dep.found()
15
+if build_module_jack_tunnel
16
+ pipewire_module_jack_tunnel = shared_library('pipewire-module-jack-tunnel',
17
+ 'module-jack-tunnel.c' ,
18
+ include_directories : configinc,
19
+ install : true,
20
+ install_dir : modules_install_dir,
21
+ install_rpath: modules_install_dir,
22
+ dependencies : mathlib, dl_lib, pipewire_dep,
23
+ )
24
+ build_module_jackdbus_detect = dbus_dep.found()
25
+ if build_module_jackdbus_detect
26
+ pipewire_module_jack_tunnel = shared_library('pipewire-module-jackdbus-detect',
27
+ 'module-jackdbus-detect.c' ,
28
+ include_directories : configinc,
29
+ install : true,
30
+ install_dir : modules_install_dir,
31
+ install_rpath: modules_install_dir,
32
+ dependencies : mathlib, dl_lib, pipewire_dep, dbus_dep,
33
+ )
34
+ endif
35
+endif
36
+
37
+summary({'jack-tunnel': build_module_jack_tunnel}, bool_yn: true, section: 'Optional Modules')
38
+
39
+
40
+
41
pipewire_module_profiler = shared_library('pipewire-module-profiler',
42
'module-profiler.c',
43
'module-profiler/protocol-native.c', ,
44
45
'module-protocol-pulse/modules/module-always-sink.c',
46
'module-protocol-pulse/modules/module-combine-sink.c',
47
'module-protocol-pulse/modules/module-echo-cancel.c',
48
+ 'module-protocol-pulse/modules/module-jackdbus-detect.c',
49
'module-protocol-pulse/modules/module-ladspa-sink.c',
50
'module-protocol-pulse/modules/module-ladspa-source.c',
51
'module-protocol-pulse/modules/module-loopback.c',
52
pipewire-0.3.70.tar.gz/src/modules/module-access.c -> pipewire-0.3.71.tar.gz/src/modules/module-access.c
Changed
138
1
2
#include <sys/stat.h>
3
#include <fcntl.h>
4
#include <unistd.h>
5
+#include <limits.h>
6
7
#include "config.h"
8
9
10
struct spa_hook module_listener;
11
};
12
13
-static int check_cmdline(struct pw_impl_client *client, int pid, const char *str)
14
+static int get_exe_name(int pid, char *buf, size_t buf_size)
15
{
16
- char path2048, key1024;
17
- ssize_t len;
18
- int fd, res;
19
- struct spa_json it2;
20
+ char path256;
21
+ struct stat s1, s2;
22
+ int res;
23
+
24
+ /*
25
+ * Find executable name, checking it is an existing file
26
+ * (in the current namespace).
27
+ */
28
+
29
+#if defined(__linux__)
30
+ spa_scnprintf(path, sizeof(path), "/proc/%u/exe", pid);
31
+#elif defined(__FreeBSD__) || defined(__MidnightBSD__)
32
+ spa_scnprintf(path, sizeof(path), "/proc/%u/file", pid);
33
+#else
34
+ return -ENOTSUP;
35
+#endif
36
37
- sprintf(path, "/proc/%u/cmdline", pid);
38
+ res = readlink(path, buf, buf_size);
39
+ if (res < 0)
40
+ return -errno;
41
+ if ((size_t)res >= buf_size)
42
+ return -E2BIG;
43
+ bufres = '\0';
44
45
- fd = open(path, O_RDONLY);
46
- if (fd < 0) {
47
- res = -errno;
48
- goto exit;
49
- }
50
- if ((len = read(fd, path, sizeof(path)-1)) < 0) {
51
- res = -errno;
52
- goto exit_close;
53
- }
54
- pathlen = '\0';
55
+ /* Check the file exists (= not deleted, and is in current namespace) */
56
+ if (stat(path, &s1) != 0 || stat(buf, &s2) != 0)
57
+ return -errno;
58
+ if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
59
+ return -ENXIO;
60
+
61
+ return 0;
62
+}
63
+
64
+static int check_exe(struct pw_impl_client *client, const char *path, const char *str)
65
+{
66
+ char key1024;
67
+ int res;
68
+ struct spa_json it2;
69
70
spa_json_init(&it0, str, strlen(str));
71
if ((res = spa_json_enter_array(&it0, &it1)) <= 0)
72
- goto exit_close;
73
+ return res;
74
75
while (spa_json_get_string(&it1, key, sizeof(key)) > 0) {
76
- if (spa_streq(path, key)) {
77
- res = 1;
78
- goto exit_close;
79
- }
80
+ if (spa_streq(path, key))
81
+ return 1;
82
}
83
- res = 0;
84
-exit_close:
85
- close(fd);
86
-exit:
87
- return res;
88
+
89
+ return 0;
90
}
91
92
static void
93
94
struct impl *impl = data;
95
struct pw_permission permissions1;
96
struct spa_dict_item items2;
97
+ char exe_pathPATH_MAX;
98
const struct pw_properties *props;
99
const char *str, *access;
100
char *flatpak_app_id = NULL;
101
102
goto granted;
103
} else {
104
pw_log_info("client %p has trusted pid %d", client, pid);
105
+ if ((res = get_exe_name(pid, exe_path, sizeof(exe_path))) >= 0) {
106
+ pw_log_info("client %p has trusted exe path '%s'", client, exe_path);
107
+ } else {
108
+ pw_log_info("client %p has no trusted exe path: %s",
109
+ client, spa_strerror(res));
110
+ exe_path0 = '\0';
111
+ }
112
}
113
114
if (impl->properties && (str = pw_properties_get(impl->properties, "access.allowed")) != NULL) {
115
- res = check_cmdline(client, pid, str);
116
+ res = check_exe(client, exe_path, str);
117
if (res < 0) {
118
pw_log_warn("%p: client %p allowed check failed: %s",
119
impl, client, spa_strerror(res));
120
121
}
122
123
if (impl->properties && (str = pw_properties_get(impl->properties, "access.rejected")) != NULL) {
124
- res = check_cmdline(client, pid, str);
125
+ res = check_exe(client, exe_path, str);
126
if (res < 0) {
127
pw_log_warn("%p: client %p rejected check failed: %s",
128
impl, client, spa_strerror(res));
129
130
}
131
132
if (impl->properties && (str = pw_properties_get(impl->properties, "access.restricted")) != NULL) {
133
- res = check_cmdline(client, pid, str);
134
+ res = check_exe(client, exe_path, str);
135
if (res < 0) {
136
pw_log_warn("%p: client %p restricted check failed: %s",
137
impl, client, spa_strerror(res));
138
pipewire-0.3.70.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.71.tar.gz/src/modules/module-client-node/client-node.c
Changed
201
1
2
#define MAX_BUFFERS 64
3
#define MAX_METAS 16u
4
#define MAX_DATAS 64u
5
-#define MAX_AREAS 2048
6
+#define AREA_SIZE (4096u / sizeof(struct spa_io_buffers))
7
+#define MAX_AREAS 32
8
9
-#define CHECK_FREE_PORT(this,d,p) (p <= pw_map_get_size(&this->portsd) && !CHECK_PORT(this,d,p))
10
-#define CHECK_PORT(this,d,p) (pw_map_lookup(&this->portsd, p) != NULL)
11
-#define GET_PORT(this,d,p) (pw_map_lookup(&this->portsd, p))
12
+#define CHECK_FREE_PORT(impl,d,p) (p <= pw_map_get_size(&impl->portsd) && !CHECK_PORT(impl,d,p))
13
+#define CHECK_PORT(impl,d,p) (pw_map_lookup(&impl->portsd, p) != NULL)
14
+#define GET_PORT(impl,d,p) (pw_map_lookup(&impl->portsd, p))
15
16
-#define CHECK_PORT_BUFFER(this,b,p) (b < p->n_buffers)
17
+#define CHECK_PORT_BUFFER(impl,b,p) (b < p->n_buffers)
18
19
struct buffer {
20
struct spa_buffer *outbuf;
21
22
23
struct port {
24
struct pw_impl_port *port;
25
- struct node *node;
26
struct impl *impl;
27
28
enum spa_direction direction;
29
30
struct pw_array mix;
31
};
32
33
-struct node {
34
- struct spa_node node;
35
+struct impl {
36
+ struct pw_impl_client_node this;
37
38
- struct impl *impl;
39
+ struct pw_context *context;
40
+
41
+ struct spa_node node;
42
43
struct spa_log *log;
44
struct spa_loop *data_loop;
45
46
struct pw_impl_client *client;
47
48
struct spa_source data_source;
49
- int writefd;
50
51
struct pw_map ports2;
52
53
struct port dummy;
54
55
struct params params;
56
-};
57
-
58
-struct impl {
59
- struct pw_impl_client_node this;
60
-
61
- struct pw_context *context;
62
-
63
- struct node node;
64
65
struct pw_map io_map;
66
- struct pw_memblock *io_areas;
67
+ struct pw_array io_areas;
68
69
struct pw_memblock *activation;
70
71
72
73
uint32_t bind_node_version;
74
uint32_t bind_node_id;
75
-
76
- int fds2;
77
- int other_fds2;
78
};
79
80
#define pw_client_node_resource(r,m,v,...) \
81
82
return mix;
83
}
84
85
-static void clear_data(struct node *this, struct spa_data *d)
86
+static void clear_data(struct impl *impl, struct spa_data *d)
87
{
88
- struct impl *impl = this->impl;
89
-
90
switch (d->type) {
91
case SPA_DATA_MemId:
92
{
93
94
struct pw_memblock *m;
95
96
id = SPA_PTR_TO_UINT32(d->data);
97
- m = pw_mempool_find_id(this->client->pool, id);
98
+ m = pw_mempool_find_id(impl->client->pool, id);
99
if (m) {
100
pw_log_debug("%p: mem %d", impl, m->id);
101
pw_memblock_unref(m);
102
103
}
104
}
105
106
-static int clear_buffers(struct node *this, struct mix *mix)
107
+static int clear_buffers(struct impl *impl, struct mix *mix)
108
{
109
uint32_t i, j;
110
111
for (i = 0; i < mix->n_buffers; i++) {
112
struct buffer *b = &mix->buffersi;
113
114
- spa_log_debug(this->log, "%p: clear buffer %d", this, i);
115
+ spa_log_debug(impl->log, "%p: clear buffer %d", impl, i);
116
117
for (j = 0; j < b->buffer.n_datas; j++) {
118
struct spa_data *d = &b->datasj;
119
- clear_data(this, d);
120
+ clear_data(impl, d);
121
}
122
pw_memblock_unref(b->mem);
123
}
124
125
return 0;
126
}
127
128
-static void mix_clear(struct node *this, struct mix *mix)
129
+static void mix_clear(struct impl *impl, struct mix *mix)
130
{
131
struct port *port = mix->port;
132
133
if (!mix->valid)
134
return;
135
- do_port_use_buffers(this->impl, port->direction, port->id,
136
+ do_port_use_buffers(impl, port->direction, port->id,
137
mix->id, 0, NULL, 0);
138
mix->valid = false;
139
}
140
141
uint32_t id, uint32_t start, uint32_t num,
142
const struct spa_pod *filter)
143
{
144
- struct node *this = object;
145
+ struct impl *impl = object;
146
uint8_t buffer1024;
147
struct spa_pod_dynamic_builder b;
148
struct spa_result_node_params result;
149
uint32_t count = 0;
150
bool found = false;
151
152
- spa_return_val_if_fail(this != NULL, -EINVAL);
153
+ spa_return_val_if_fail(impl != NULL, -EINVAL);
154
spa_return_val_if_fail(num != 0, -EINVAL);
155
156
result.id = id;
157
158
struct spa_pod *param;
159
160
result.index = result.next++;
161
- if (result.index >= this->params.n_params)
162
+ if (result.index >= impl->params.n_params)
163
break;
164
165
- param = this->params.paramsresult.index;
166
+ param = impl->params.paramsresult.index;
167
168
if (param == NULL || !spa_pod_is_object_id(param, id))
169
continue;
170
171
172
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
173
if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
174
- pw_log_debug("%p: %d param %u", this, seq, result.index);
175
- spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
176
+ pw_log_debug("%p: %d param %u", impl, seq, result.index);
177
+ spa_node_emit_result(&impl->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
178
count++;
179
}
180
spa_pod_dynamic_builder_clean(&b);
181
182
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
183
const struct spa_pod *param)
184
{
185
- struct node *this = object;
186
+ struct impl *impl = object;
187
188
- spa_return_val_if_fail(this != NULL, -EINVAL);
189
+ spa_return_val_if_fail(impl != NULL, -EINVAL);
190
191
- if (this->resource == NULL)
192
+ if (impl->resource == NULL)
193
return param == NULL ? 0 : -EIO;
194
195
- return pw_client_node_resource_set_param(this->resource, id, flags, param);
196
+ return pw_client_node_resource_set_param(impl->resource, id, flags, param);
197
}
198
199
static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
200
{
201
pipewire-0.3.70.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.71.tar.gz/src/modules/module-client-node/remote-node.c
Changed
201
1
2
3
struct node_data {
4
struct pw_context *context;
5
+ struct pw_loop *data_loop;
6
+ struct spa_system *data_system;
7
8
struct pw_mempool *pool;
9
10
11
struct spa_hook proxy_client_node_listener;
12
13
struct spa_list links;
14
+
15
+ struct spa_io_clock *clock;
16
+ struct spa_io_position *position;
17
};
18
19
struct link {
20
21
struct pw_memmap *map;
22
struct pw_node_target target;
23
uint32_t node_id;
24
- int signalfd;
25
};
26
27
/** \endcond */
28
29
30
static void clear_link(struct node_data *data, struct link *link)
31
{
32
- struct pw_context *context = data->context;
33
pw_log_debug("link %p", link);
34
- pw_loop_invoke(context->data_loop,
35
+ pw_loop_invoke(data->data_loop,
36
do_deactivate_link, SPA_ID_INVALID, NULL, 0, true, link);
37
pw_memmap_free(link->map);
38
- spa_system_close(context->data_system, link->signalfd);
39
+ spa_system_close(link->target.system, link->target.fd);
40
spa_list_remove(&link->link);
41
free(link);
42
}
43
44
pw_memmap_free(data->activation);
45
data->node->rt.activation = data->node->activation->map->ptr;
46
47
- spa_system_close(data->context->data_system, data->rtwritefd);
48
+ spa_system_close(data->data_system, data->rtwritefd);
49
data->have_transport = false;
50
}
51
52
53
{
54
if (mix->active) {
55
pw_log_debug("node %p: mix %p deactivate", data, mix);
56
- pw_loop_invoke(data->context->data_loop,
57
+ pw_loop_invoke(data->data_loop,
58
do_deactivate_mix, SPA_ID_INVALID, NULL, 0, true, mix);
59
mix->active = false;
60
}
61
62
{
63
if (!mix->active) {
64
pw_log_debug("node %p: mix %p activate", data, mix);
65
- pw_loop_invoke(data->context->data_loop,
66
+ pw_loop_invoke(data->data_loop,
67
do_activate_mix, SPA_ID_INVALID, NULL, 0, false, mix);
68
mix->active = true;
69
}
70
71
int readfd, int writefd, uint32_t mem_id, uint32_t offset, uint32_t size)
72
{
73
struct node_data *data = _data;
74
+ struct pw_impl_node *node = data->node;
75
struct pw_proxy *proxy = (struct pw_proxy*)data->client_node;
76
77
clean_transport(data);
78
79
return -errno;
80
}
81
82
- data->node->rt.activation = data->activation->ptr;
83
+ node->rt.activation = data->activation->ptr;
84
85
pw_log_debug("remote-node %p: fds:%d %d node:%u activation:%p",
86
proxy, readfd, writefd, data->remote_id, data->activation->ptr);
87
88
data->rtwritefd = writefd;
89
- spa_system_close(data->context->data_system, data->node->source.fd);
90
- data->node->source.fd = readfd;
91
+ spa_system_close(data->data_system, node->source.fd);
92
+ node->source.fd = readfd;
93
94
data->have_transport = true;
95
96
- if (data->node->active)
97
+ if (node->active)
98
pw_client_node_set_active(data->client_node, true);
99
100
return 0;
101
102
pw_log_debug("node %p: set io %s %p", proxy,
103
spa_debug_type_find_name(spa_type_io, id), ptr);
104
105
+ switch(id) {
106
+ case SPA_IO_Clock:
107
+ data->clock = size >= sizeof(*data->clock) ? ptr : NULL;
108
+ break;
109
+ case SPA_IO_Position:
110
+ data->position = size >= sizeof(*data->position) ? ptr : NULL;
111
+ break;
112
+ }
113
+ data->node->driving = data->clock && data->position &&
114
+ data->position->clock.id == data->clock->id;
115
+
116
res = spa_node_set_io(data->node->node, id, ptr, size);
117
118
pw_memmap_free(old);
119
120
121
static int client_node_event(void *data, const struct spa_event *event)
122
{
123
- pw_log_warn("unhandled node event %d", SPA_EVENT_TYPE(event));
124
+ uint32_t id = SPA_NODE_EVENT_ID(event);
125
+ pw_log_warn("unhandled node event %d (%s)", id,
126
+ spa_debug_type_find_name(spa_type_node_event_id, id));
127
return -ENOTSUP;
128
}
129
130
131
struct node_data *data = _data;
132
struct pw_proxy *proxy = (struct pw_proxy*)data->client_node;
133
int res;
134
+ uint32_t id = SPA_NODE_COMMAND_ID(command);
135
136
- switch (SPA_NODE_COMMAND_ID(command)) {
137
- case SPA_NODE_COMMAND_Pause:
138
- pw_log_debug("node %p: pause", proxy);
139
+ pw_log_debug("%p: got command %d (%s)", proxy, id,
140
+ spa_debug_type_find_name(spa_type_node_command_id, id));
141
142
+ switch (id) {
143
+ case SPA_NODE_COMMAND_Pause:
144
if ((res = pw_impl_node_set_state(data->node, PW_NODE_STATE_IDLE)) < 0) {
145
pw_log_warn("node %p: pause failed", proxy);
146
pw_proxy_error(proxy, res, "pause failed");
147
148
149
break;
150
case SPA_NODE_COMMAND_Start:
151
- pw_log_debug("node %p: start", proxy);
152
-
153
if ((res = pw_impl_node_set_state(data->node, PW_NODE_STATE_RUNNING)) < 0) {
154
pw_log_warn("node %p: start failed", proxy);
155
pw_proxy_error(proxy, res, "start failed");
156
157
break;
158
159
case SPA_NODE_COMMAND_Suspend:
160
- pw_log_debug("node %p: suspend", proxy);
161
if ((res = pw_impl_node_set_state(data->node, PW_NODE_STATE_SUSPENDED)) < 0) {
162
pw_log_warn("node %p: suspend failed", proxy);
163
pw_proxy_error(proxy, res, "suspend failed");
164
165
res = pw_impl_node_send_command(data->node, command);
166
break;
167
default:
168
- pw_log_warn("unhandled node command %d", SPA_NODE_COMMAND_ID(command));
169
+ pw_log_warn("unhandled node command %d (%s)", id,
170
+ spa_debug_type_find_name(spa_type_node_command_id, id));
171
res = -ENOTSUP;
172
- pw_proxy_errorf(proxy, res, "command %d not supported", SPA_NODE_COMMAND_ID(command));
173
+ pw_proxy_errorf(proxy, res, "command %d (%s) not supported", id,
174
+ spa_debug_type_find_name(spa_type_node_command_id, id));
175
}
176
return res;
177
}
178
179
return res;
180
}
181
182
-static int link_signal_func(void *user_data)
183
-{
184
- struct link *link = user_data;
185
- struct spa_system *data_system = link->data->context->data_system;
186
-
187
- pw_log_trace_fp("link %p: signal %p", link, link->target.activation);
188
- if (SPA_UNLIKELY(spa_system_eventfd_write(data_system, link->signalfd, 1) < 0))
189
- pw_log_warn("link %p: write failed %m", link);
190
-
191
- return 0;
192
-}
193
-
194
static int
195
do_activate_link(struct spa_loop *loop,
196
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
197
198
if (data->remote_id == node_id) {
199
pw_log_debug("node %p: our activation %u: %u %u %u", node, node_id,
200
memid, offset, size);
201
pipewire-0.3.70.tar.gz/src/modules/module-combine-stream.c -> pipewire-0.3.71.tar.gz/src/modules/module-combine-stream.c
Changed
201
1
2
#include <spa/pod/builder.h>
3
#include <spa/param/audio/format-utils.h>
4
#include <spa/param/audio/raw.h>
5
+#include <spa/param/latency-utils.h>
6
7
#include <pipewire/impl.h>
8
#include <pipewire/i18n.h>
9
10
* - `node.name`: a unique name for the stream
11
* - `node.description`: a human readable name for the stream
12
* - `combine.mode` = capture | playback | sink | source, default sink
13
+ * - `combine.latency-compensate`: use delay buffers to match stream latencies
14
* - `combine.props = {}`: properties to be passed to the sink/source
15
* - `stream.props = {}`: properties to be passed to the streams
16
* - `stream.rules = {}`: rules for matching streams, use create-stream actions
17
18
* combine.mode = sink
19
* node.name = "combine_sink"
20
* node.description = "My Combine Sink"
21
+ * combine.latency-compensate = false
22
* combine.props = {
23
* audio.position = FL FR
24
* }
25
26
* combine.mode = sink
27
* node.name = "combine_sink_5_1"
28
* node.description = "My 5.1 Combine Sink"
29
+ * combine.latency-compensate = false
30
* combine.props = {
31
* audio.position = FL FR FC LFE SL SR
32
* }
33
34
"( stream.props=<properties> ) " \
35
"( stream.rules=<properties> ) "
36
37
+#define DELAYBUF_MAX_SIZE (20 * sizeof(float) * 96000)
38
+
39
40
static const struct spa_dict_item module_props = {
41
{ PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
42
43
44
struct impl {
45
struct pw_context *context;
46
+ struct pw_loop *main_loop;
47
struct pw_data_loop *data_loop;
48
49
struct pw_properties *props;
50
51
struct pw_registry *registry;
52
struct spa_hook registry_listener;
53
54
+ struct spa_source *update_delay_event;
55
+
56
struct pw_properties *combine_props;
57
struct pw_stream *combine;
58
struct spa_hook combine_listener;
59
60
61
struct pw_properties *stream_props;
62
63
+ struct spa_latency_info latency;
64
+
65
+ int64_t latency_offset;
66
+
67
struct spa_audio_info_raw info;
68
69
unsigned int do_disconnect:1;
70
+ unsigned int latency_compensate:1;
71
72
struct spa_list streams;
73
uint32_t n_streams;
74
};
75
76
+struct ringbuffer {
77
+ void *buf;
78
+ uint32_t idx;
79
+ uint32_t size;
80
+};
81
+
82
struct stream {
83
uint32_t id;
84
85
86
struct spa_hook stream_listener;
87
struct pw_stream_events stream_events;
88
89
+ struct spa_latency_info latency;
90
+
91
struct spa_audio_info_raw info;
92
uint32_t remapSPA_AUDIO_MAX_CHANNELS;
93
+ uint32_t rate;
94
+
95
+ void *delaybuf;
96
+ struct ringbuffer delaySPA_AUDIO_MAX_CHANNELS;
97
+
98
+ int64_t delay_nsec; /* for main loop */
99
+ int64_t data_delay_nsec; /* for data loop */
100
101
unsigned int ready:1;
102
unsigned int added:1;
103
+ unsigned int have_latency:1;
104
};
105
106
static uint32_t channel_from_name(const char *name)
107
108
parse_position(info, DEFAULT_POSITION, strlen(DEFAULT_POSITION));
109
}
110
111
+static void ringbuffer_init(struct ringbuffer *r, void *buf, uint32_t size)
112
+{
113
+ r->buf = buf;
114
+ r->idx = 0;
115
+ r->size = size;
116
+}
117
+
118
+static void ringbuffer_memcpy(struct ringbuffer *r, void *dst, void *src, uint32_t size)
119
+{
120
+ uint32_t avail;
121
+
122
+ avail = SPA_MIN(size, r->size);
123
+
124
+ /* buf to dst */
125
+ if (dst && avail > 0) {
126
+ spa_ringbuffer_read_data(NULL, r->buf, r->size, r->idx, dst, avail);
127
+ dst = SPA_PTROFF(dst, avail, void);
128
+ }
129
+
130
+ /* src to dst */
131
+ if (size > avail) {
132
+ if (dst)
133
+ memcpy(dst, src, size - avail);
134
+ src = SPA_PTROFF(src, size - avail, void);
135
+ }
136
+
137
+ /* src to buf */
138
+ if (avail > 0) {
139
+ spa_ringbuffer_write_data(NULL, r->buf, r->size, r->idx, src, avail);
140
+ r->idx = (r->idx + avail) % r->size;
141
+ }
142
+}
143
+
144
+static void ringbuffer_copy(struct ringbuffer *dst, struct ringbuffer *src)
145
+{
146
+ uint32_t l0, l1;
147
+
148
+ if (dst->size == 0 || src->size == 0)
149
+ return;
150
+
151
+ l0 = src->size - src->idx;
152
+ l1 = src->idx;
153
+
154
+ ringbuffer_memcpy(dst, NULL, SPA_PTROFF(src->buf, src->idx, void), l0);
155
+ ringbuffer_memcpy(dst, NULL, src->buf, l1);
156
+}
157
+
158
static struct stream *find_stream(struct impl *impl, uint32_t id)
159
{
160
struct stream *s;
161
162
return NULL;
163
}
164
165
+static enum pw_direction get_combine_direction(struct impl *impl)
166
+{
167
+ if (impl->mode == MODE_SINK || impl->mode == MODE_CAPTURE)
168
+ return PW_DIRECTION_INPUT;
169
+ else
170
+ return PW_DIRECTION_OUTPUT;
171
+}
172
+
173
+static void apply_latency_offset(struct spa_latency_info *latency, int64_t offset)
174
+{
175
+ latency->min_ns += SPA_MAX(offset, -(int64_t)latency->min_ns);
176
+ latency->max_ns += SPA_MAX(offset, -(int64_t)latency->max_ns);
177
+}
178
+
179
+static int64_t get_stream_delay(struct stream *s)
180
+{
181
+ struct pw_time t;
182
+
183
+ if (pw_stream_get_time_n(s->stream, &t, sizeof(t)) < 0 ||
184
+ t.rate.denom == 0)
185
+ return INT64_MIN;
186
+
187
+ return t.delay * SPA_NSEC_PER_SEC * t.rate.num / t.rate.denom;
188
+}
189
+
190
+static void update_latency(struct impl *impl)
191
+{
192
+ struct spa_latency_info latency;
193
+ struct stream *s;
194
+
195
+ if (impl->combine == NULL)
196
+ return;
197
+
198
+ if (!impl->latency_compensate) {
199
+ spa_latency_info_combine_start(&latency, get_combine_direction(impl));
200
+
201
pipewire-0.3.70.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.71.tar.gz/src/modules/module-echo-cancel.c
Changed
30
1
2
{
3
struct spa_pod_parser prs;
4
struct spa_pod_frame f;
5
- int changed = 0;
6
7
spa_pod_parser_pod(&prs, params);
8
if (spa_pod_parser_push_struct(&prs, &f) < 0)
9
10
if (spa_streq(name, "debug.aec.wav-path")) {
11
spa_scnprintf(impl->wav_path,
12
sizeof(impl->wav_path), "%s", value);
13
- changed++;
14
}
15
}
16
spa_audio_aec_set_params(impl->aec, params);
17
18
19
res = spa_audio_aec_init(impl->aec, &aec_props->dict, &info);
20
21
- impl->rec_info.channels = info.channels;
22
- impl->out_info.channels = info.channels;
23
- impl->play_info.channels = info.channels;
24
+ impl->rec_info = info;
25
+ impl->out_info = info;
26
+ impl->play_info = info;
27
}
28
29
pw_properties_free(aec_props);
30
pipewire-0.3.70.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.71.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
53
1
2
#ifdef HAVE_SNDFILE
3
#include <sndfile.h>
4
#endif
5
+#include <unistd.h>
6
7
#include <spa/utils/json.h>
8
#include <spa/utils/result.h>
9
10
11
int diff = INT_MAX;
12
uint32_t best = 0, i;
13
+ float *samples = NULL;
14
15
for (i = 0; i < MAX_RATES && filenamesi && filenamesi0; i++) {
16
fsi = sf_open(filenamesi, SFM_READ, &infosi);
17
- if (!fsi)
18
+ if (fsi == NULL)
19
continue;
20
21
if (labs((long)infosi.samplerate - (long)*rate) < diff) {
22
23
pw_log_debug("new closest match: %d", infosi.samplerate);
24
}
25
}
26
-
27
- pw_log_debug("loading %s", filenamesbest);
28
- float *samples = read_samples_from_sf(fsbest, infosbest, gain, delay,
29
- offset, length, channel, rate, n_samples);
30
-
31
+ if (fsbest != NULL) {
32
+ pw_log_info("loading best rate:%u %s", infosbest.samplerate, filenamesbest);
33
+ samples = read_samples_from_sf(fsbest, infosbest, gain, delay,
34
+ offset, length, channel, rate, n_samples);
35
+ } else {
36
+ char bufPATH_MAX;
37
+ pw_log_error("Can't open any sample file (CWD %s):",
38
+ getcwd(buf, sizeof(buf)));
39
+ for (i = 0; i < MAX_RATES && filenamesi && filenamesi0; i++) {
40
+ fsi = sf_open(filenamesi, SFM_READ, &infosi);
41
+ if (fsi == NULL)
42
+ pw_log_error(" failed file %s: %s", filenamesi, sf_strerror(fsi));
43
+ else
44
+ pw_log_warn(" unexpectedly opened file %s", filenamesi);
45
+ }
46
+ }
47
for (i = 0; i < MAX_RATES; i++)
48
- if (fsi)
49
+ if (fsi != NULL)
50
sf_close(fsi);
51
52
return samples;
53
pipewire-0.3.71.tar.gz/src/modules/module-jack-tunnel
Added
2
1
+(directory)
2
pipewire-0.3.71.tar.gz/src/modules/module-jack-tunnel.c
Added
201
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <string.h>
7
+#include <stdio.h>
8
+#include <errno.h>
9
+#include <sys/types.h>
10
+#include <sys/stat.h>
11
+#include <fcntl.h>
12
+#include <unistd.h>
13
+#include <stdlib.h>
14
+#include <signal.h>
15
+#include <limits.h>
16
+#include <math.h>
17
+
18
+#include "config.h"
19
+
20
+#include <spa/utils/result.h>
21
+#include <spa/utils/string.h>
22
+#include <spa/utils/json.h>
23
+#include <spa/debug/types.h>
24
+#include <spa/pod/builder.h>
25
+#include <spa/param/audio/format-utils.h>
26
+#include <spa/param/latency-utils.h>
27
+#include <spa/param/audio/raw.h>
28
+
29
+#include <pipewire/impl.h>
30
+#include <pipewire/i18n.h>
31
+#include <pipewire/private.h>
32
+
33
+#include "module-jack-tunnel/weakjack.h"
34
+
35
+/** \page page_module_jack_tunnel PipeWire Module: JACK Tunnel
36
+ *
37
+ * The jack-tunnel module provides a source or sink that tunnels all audio to
38
+ * a JACK server.
39
+ *
40
+ * This module is usually used together with \ref page_module_jackdbus_detect that will
41
+ * automatically load the tunnel with the right parameters based on dbus
42
+ * information.
43
+ *
44
+ * ## Module Options
45
+ *
46
+ * - `jack.library`: the libjack to load, by default libjack.so.0 is searched in
47
+ * JACK_PATH directories and then some standard library paths.
48
+ * Can be an absolute path.
49
+ * - `jack.server`: the name of the JACK server to tunnel to.
50
+ * - `jack.client-name`: the name of the JACK client.
51
+ * - `jack.connect`: if jack ports should be connected automatically. Can also be
52
+ * placed per stream.
53
+ * - `tunnel.mode`: the tunnel mode, sink|source|duplex, default duplex
54
+ * - `midi.ports`: the number of midi ports. Can also be added to the stream props.
55
+ * - `source.props`: Extra properties for the source filter.
56
+ * - `sink.props`: Extra properties for the sink filter.
57
+ *
58
+ * ## General options
59
+ *
60
+ * Options with well-known behavior.
61
+ *
62
+ * - \ref PW_KEY_REMOTE_NAME
63
+ * - \ref PW_KEY_AUDIO_CHANNELS
64
+ * - \ref SPA_KEY_AUDIO_POSITION
65
+ * - \ref PW_KEY_NODE_NAME
66
+ * - \ref PW_KEY_NODE_DESCRIPTION
67
+ * - \ref PW_KEY_NODE_GROUP
68
+ * - \ref PW_KEY_NODE_VIRTUAL
69
+ * - \ref PW_KEY_MEDIA_CLASS
70
+ * - \ref PW_KEY_TARGET_OBJECT to specify the remote node.name or serial.id to link to
71
+ *
72
+ * ## Example configuration of a duplex sink/source
73
+ *
74
+ *\code{.unparsed}
75
+ * context.modules =
76
+ * { name = libpipewire-module-jack-tunnel
77
+ * args = {
78
+ * #jack.library = libjack.so.0
79
+ * #jack.server = null
80
+ * #jack.client-name = PipeWire
81
+ * #jack.connect = true
82
+ * #tunnel.mode = duplex
83
+ * #midi.ports = 0
84
+ * #audio.channels = 2
85
+ * #audio.position = FL FR
86
+ * source.props = {
87
+ * # extra sink properties
88
+ * }
89
+ * sink.props = {
90
+ * # extra sink properties
91
+ * }
92
+ * }
93
+ * }
94
+ *
95
+ *\endcode
96
+ */
97
+
98
+#define NAME "jack-tunnel"
99
+
100
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
101
+#define PW_LOG_TOPIC_DEFAULT mod_topic
102
+
103
+#define MAX_PORTS 128
104
+
105
+#define DEFAULT_CLIENT_NAME "PipeWire"
106
+#define DEFAULT_CHANNELS 2
107
+#define DEFAULT_POSITION " FL FR "
108
+#define DEFAULT_MIDI_PORTS 1
109
+
110
+#define MODULE_USAGE "( remote.name=<remote> " \
111
+ "( jack.library=<jack library path> ) " \
112
+ "( jack.server=<server name> ) " \
113
+ "( jack.client-name=<name of the JACK client> " \
114
+ "( jack.connect=<bool, autoconnect ports> " \
115
+ "( tunnel.mode=<sink|source|duplex> " \
116
+ "( midi.ports=<number of midi ports> " \
117
+ "( audio.channels=<number of channels> " \
118
+ "( audio.position=<channel map> " \
119
+ "( source.props=<properties> ) " \
120
+ "( sink.props=<properties> ) "
121
+
122
+
123
+static const struct spa_dict_item module_props = {
124
+ { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
125
+ { PW_KEY_MODULE_DESCRIPTION, "Create a JACK tunnel" },
126
+ { PW_KEY_MODULE_USAGE, MODULE_USAGE },
127
+ { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
128
+};
129
+
130
+static struct weakjack jack;
131
+
132
+struct port {
133
+ jack_port_t *jack_port;
134
+
135
+ enum spa_direction direction;
136
+ struct spa_latency_info latency2;
137
+ bool latency_changed2;
138
+ unsigned int is_midi:1;
139
+};
140
+
141
+struct volume {
142
+ bool mute;
143
+ uint32_t n_volumes;
144
+ float volumesSPA_AUDIO_MAX_CHANNELS;
145
+};
146
+
147
+struct stream {
148
+ struct impl *impl;
149
+
150
+ enum spa_direction direction;
151
+ struct pw_properties *props;
152
+ struct pw_filter *filter;
153
+ struct spa_hook listener;
154
+ struct spa_audio_info_raw info;
155
+ uint32_t n_midi;
156
+ uint32_t n_ports;
157
+ struct port *portsMAX_PORTS;
158
+ struct volume volume;
159
+
160
+ unsigned int running:1;
161
+ unsigned int connect:1;
162
+};
163
+
164
+struct impl {
165
+ struct pw_context *context;
166
+ struct pw_loop *main_loop;
167
+ struct spa_system *system;
168
+
169
+#define MODE_SINK (1<<0)
170
+#define MODE_SOURCE (1<<1)
171
+#define MODE_DUPLEX (MODE_SINK|MODE_SOURCE)
172
+ uint32_t mode;
173
+ struct pw_properties *props;
174
+
175
+ struct pw_impl_module *module;
176
+
177
+ struct spa_hook module_listener;
178
+
179
+ struct pw_core *core;
180
+ struct spa_hook core_proxy_listener;
181
+ struct spa_hook core_listener;
182
+
183
+ struct spa_io_position *position;
184
+
185
+ struct stream source;
186
+ struct stream sink;
187
+
188
+ uint32_t samplerate;
189
+
190
+ jack_client_t *client;
191
+ jack_nframes_t frame_time;
192
+
193
+ uint32_t pw_xrun;
194
+ uint32_t jack_xrun;
195
+
196
+ unsigned int do_disconnect:1;
197
+ unsigned int done:1;
198
+ unsigned int new_xrun:1;
199
+ unsigned int fix_midi:1;
200
+};
201
pipewire-0.3.71.tar.gz/src/modules/module-jack-tunnel/weakjack.h
Added
197
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#ifndef PIPEWIRE_WEAK_JACK_H
7
+#define PIPEWIRE_WEAK_JACK_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+#include "config.h"
14
+
15
+#include <dlfcn.h>
16
+
17
+#include <jack/jack.h>
18
+#include <jack/transport.h>
19
+#include <jack/midiport.h>
20
+
21
+struct weakjack {
22
+ jack_nframes_t (*cycle_wait) (jack_client_t* client);
23
+ void (*cycle_signal) (jack_client_t* client, int status);
24
+
25
+ jack_nframes_t (*frame_time) (const jack_client_t *);
26
+ int (*get_cycle_times) (const jack_client_t *client,
27
+ jack_nframes_t *current_frames,
28
+ jack_time_t *current_usecs,
29
+ jack_time_t *next_usecs,
30
+ float *period_usecs);
31
+ jack_transport_state_t (*transport_query) (const jack_client_t *client,
32
+ jack_position_t *pos);
33
+
34
+ jack_client_t * (*client_open) (const char *client_name,
35
+ jack_options_t options,
36
+ jack_status_t *status, ...);
37
+ int (*client_close) (jack_client_t *client);
38
+
39
+
40
+ int (*activate) (jack_client_t *client);
41
+ int (*deactivate) (jack_client_t *client);
42
+
43
+ jack_nframes_t (*get_sample_rate) (jack_client_t *);
44
+
45
+ int (*recompute_total_latencies) (jack_client_t *client);
46
+
47
+ jack_port_t * (*port_register) (jack_client_t *client,
48
+ const char *port_name,
49
+ const char *port_type,
50
+ unsigned long flags,
51
+ unsigned long buffer_size);
52
+ int (*port_unregister) (jack_client_t *client, jack_port_t *port);
53
+ void * (*port_get_buffer) (jack_port_t *port, jack_nframes_t);
54
+ const char * (*port_name) (const jack_port_t *port);
55
+
56
+ void (*port_get_latency_range) (jack_port_t *port,
57
+ jack_latency_callback_mode_t mode,
58
+ jack_latency_range_t *range);
59
+ void (*port_set_latency_range) (jack_port_t *port,
60
+ jack_latency_callback_mode_t mode,
61
+ jack_latency_range_t *range);
62
+
63
+
64
+ int (*connect) (jack_client_t *client,
65
+ const char *source_port,
66
+ const char *destination_port);
67
+ int (*disconnect) (jack_client_t *client,
68
+ const char *source_port,
69
+ const char *destination_port);
70
+
71
+ const char ** (*get_ports) (jack_client_t *client,
72
+ const char *port_name_pattern,
73
+ const char *type_name_pattern,
74
+ unsigned long flags);
75
+ void (*free) (void* ptr);
76
+
77
+ int (*set_process_thread) (jack_client_t* client,
78
+ JackThreadCallback thread_callback, void *arg);
79
+ int (*set_xrun_callback) (jack_client_t *client,
80
+ JackXRunCallback xrun_callback, void *arg);
81
+ void (*on_info_shutdown) (jack_client_t *client,
82
+ JackInfoShutdownCallback shutdown_callback, void *arg);
83
+ int (*set_latency_callback) (jack_client_t *client,
84
+ JackLatencyCallback latency_callback, void *arg);
85
+
86
+ void (*midi_clear_buffer) (void *port_buffer);
87
+ int (*midi_event_write) (void *port_buffer,
88
+ jack_nframes_t time,
89
+ const jack_midi_data_t *data,
90
+ size_t data_size);
91
+ uint32_t (*midi_get_event_count) (void* port_buffer);
92
+ int (*midi_event_get) (jack_midi_event_t *event, void *port_buffer,
93
+ uint32_t event_index);
94
+
95
+};
96
+
97
+
98
+static inline int weakjack_load_by_path(struct weakjack *jack, const char *path)
99
+{
100
+ void *hnd;
101
+
102
+ hnd = dlopen(path, RTLD_NOW);
103
+ if (hnd == NULL)
104
+ return -errno;
105
+
106
+ pw_log_info("opened libjack: %s", path);
107
+
108
+#define LOAD_SYM(name) ({ \
109
+ if ((jack->name = dlsym(hnd, "jack_"#name )) == NULL) \
110
+ return -ENOSYS; \
111
+})
112
+ spa_zero(*jack);
113
+ LOAD_SYM(cycle_wait);
114
+ LOAD_SYM(cycle_signal);
115
+ LOAD_SYM(frame_time);
116
+ LOAD_SYM(get_cycle_times);
117
+ LOAD_SYM(transport_query);
118
+
119
+ LOAD_SYM(client_open);
120
+ LOAD_SYM(client_close);
121
+
122
+ LOAD_SYM(activate);
123
+ LOAD_SYM(deactivate);
124
+
125
+ LOAD_SYM(get_sample_rate);
126
+
127
+ LOAD_SYM(recompute_total_latencies);
128
+
129
+ LOAD_SYM(port_register);
130
+ LOAD_SYM(port_unregister);
131
+ LOAD_SYM(port_get_buffer);
132
+ LOAD_SYM(port_name);
133
+
134
+ LOAD_SYM(port_get_latency_range);
135
+ LOAD_SYM(port_set_latency_range);
136
+
137
+ LOAD_SYM(connect);
138
+ LOAD_SYM(disconnect);
139
+
140
+ LOAD_SYM(get_ports);
141
+ LOAD_SYM(free);
142
+
143
+ LOAD_SYM(set_process_thread);
144
+ LOAD_SYM(set_xrun_callback);
145
+ LOAD_SYM(on_info_shutdown);
146
+ LOAD_SYM(set_latency_callback);
147
+
148
+ LOAD_SYM(midi_clear_buffer);
149
+ LOAD_SYM(midi_event_write);
150
+ LOAD_SYM(midi_get_event_count);
151
+ LOAD_SYM(midi_event_get);
152
+#undef LOAD_SYM
153
+
154
+ return 0;
155
+}
156
+
157
+static inline int weakjack_load(struct weakjack *jack, const char *lib)
158
+{
159
+ int res = -ENOENT;
160
+
161
+ if (lib0 != '/') {
162
+ const char *search_dirs, *p, *state = NULL;
163
+ char pathPATH_MAX;
164
+ size_t len;
165
+
166
+ search_dirs = getenv("LIBJACK_PATH");
167
+ if (!search_dirs)
168
+ search_dirs = PREFIX "/lib64/:" PREFIX "/lib/:"
169
+ "/usr/lib64/:/usr/lib/:" LIBDIR;
170
+
171
+ while ((p = pw_split_walk(search_dirs, ":", &len, &state))) {
172
+ int pathlen;
173
+
174
+ if (len >= sizeof(path)) {
175
+ res = -ENAMETOOLONG;
176
+ continue;
177
+ }
178
+ pathlen = snprintf(path, sizeof(path), "%.*s/%s", (int) len, p, lib);
179
+ if (pathlen < 0 || (size_t) pathlen >= sizeof(path)) {
180
+ res = -ENAMETOOLONG;
181
+ continue;
182
+ }
183
+ if ((res = weakjack_load_by_path(jack, path)) == 0)
184
+ break;
185
+ }
186
+ } else {
187
+ res = weakjack_load_by_path(jack, lib);
188
+ }
189
+ return res;
190
+}
191
+
192
+#ifdef __cplusplus
193
+}
194
+#endif
195
+
196
+#endif /* PIPEWIRE_WEAK_JACK_H */
197
pipewire-0.3.71.tar.gz/src/modules/module-jackdbus-detect.c
Added
201
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2016 Wim Taymans <wim.taymans@gmail.com> */
4
+/* SPDX-FileCopyrightText: Copyright © 2019 Red Hat Inc. */
5
+/* SPDX-License-Identifier: MIT */
6
+
7
+#include <string.h>
8
+#include <stdio.h>
9
+#include <errno.h>
10
+#include <sys/types.h>
11
+#include <sys/stat.h>
12
+#include <fcntl.h>
13
+#include <unistd.h>
14
+
15
+#include "config.h"
16
+
17
+#include <dbus/dbus.h>
18
+
19
+#include <spa/utils/string.h>
20
+#include <spa/utils/result.h>
21
+#include <spa/support/dbus.h>
22
+
23
+#include "pipewire/context.h"
24
+#include "pipewire/impl-client.h"
25
+#include "pipewire/log.h"
26
+#include "pipewire/module.h"
27
+#include "pipewire/utils.h"
28
+
29
+/** \page page_module_jackdbus_detect PipeWire Module: JACK DBus detect
30
+ *
31
+ * Automaticall creates a sink/source when a jackdbus server is started
32
+ * and connect to JACK.
33
+ *
34
+ * ## Module Options
35
+ *
36
+ * There are no module-specific options, all arguments are passed to
37
+ * \ref page_module_jack_tunnel.
38
+ *
39
+ * ## Example configuration
40
+ *\code{.unparsed}
41
+ * context.modules =
42
+ * { name = libpipewire-jackdbus-detect
43
+ * args {
44
+ * #jack.server = null
45
+ * #tunnel.mode = duplex
46
+ * #audio.channels = 2
47
+ * #audio.position = FL FR
48
+ * source.props = {
49
+ * # extra sink properties
50
+ * }
51
+ * sink.props = {
52
+ * # extra sink properties
53
+ * }
54
+ * }
55
+ * }
56
+ *
57
+ *\endcode
58
+ *
59
+ */
60
+
61
+#define NAME "jackdbus-detect"
62
+
63
+#define JACK_SERVICE_NAME "org.jackaudio.service"
64
+#define JACK_INTERFACE_NAME "org.jackaudio.JackControl"
65
+#define JACK_INTERFACE_PATH "/org/jackaudio/Controller"
66
+
67
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
68
+#define PW_LOG_TOPIC_DEFAULT mod_topic
69
+
70
+struct impl {
71
+ struct pw_context *context;
72
+ struct pw_properties *properties;
73
+
74
+ struct spa_dbus_connection *conn;
75
+ DBusConnection *bus;
76
+
77
+ struct spa_hook module_listener;
78
+
79
+ DBusPendingCall *pending_call;
80
+ bool is_started;
81
+
82
+ struct pw_impl_module *jack_tunnel;
83
+ struct spa_hook tunnel_listener;
84
+};
85
+
86
+static void tunnelmodule_destroy(void *data)
87
+{
88
+ struct impl *impl = data;
89
+ spa_hook_remove(&impl->tunnel_listener);
90
+ impl->jack_tunnel = NULL;
91
+}
92
+
93
+static const struct pw_impl_module_events tunnelmodule_events = {
94
+ PW_VERSION_IMPL_MODULE_EVENTS,
95
+ .destroy = tunnelmodule_destroy,
96
+};
97
+
98
+static int load_jack_tunnel(struct impl *impl)
99
+{
100
+ FILE *f;
101
+ char *args;
102
+ size_t size;
103
+ int res = 0;
104
+
105
+ if ((f = open_memstream(&args, &size)) == NULL) {
106
+ res = -errno;
107
+ pw_log_error("Can't open memstream: %m");
108
+ goto done;
109
+ }
110
+
111
+ fprintf(f, "{");
112
+ if (impl->properties != NULL)
113
+ pw_properties_serialize_dict(f, &impl->properties->dict, 0);
114
+ fprintf(f, " }");
115
+ fclose(f);
116
+
117
+ pw_log_info("loading module args:'%s'", args);
118
+ impl->jack_tunnel = pw_context_load_module(impl->context,
119
+ "libpipewire-module-jack-tunnel",
120
+ args, NULL);
121
+ free(args);
122
+
123
+ if (impl->jack_tunnel == NULL) {
124
+ res = -errno;
125
+ pw_log_error("Can't create tunnel: %m");
126
+ goto done;
127
+ }
128
+
129
+ pw_impl_module_add_listener(impl->jack_tunnel,
130
+ &impl->tunnel_listener, &tunnelmodule_events, impl);
131
+done:
132
+ return res;
133
+}
134
+
135
+static void unload_jack_tunnel(struct impl *impl)
136
+{
137
+ if (impl->jack_tunnel) {
138
+ pw_impl_module_destroy(impl->jack_tunnel);
139
+ impl->jack_tunnel = NULL;
140
+ }
141
+}
142
+static void set_started(struct impl *impl, bool started)
143
+{
144
+ if (impl->is_started != started) {
145
+ pw_log_info("New state %d", started);
146
+ impl->is_started = started;
147
+ if (started)
148
+ load_jack_tunnel(impl);
149
+ else
150
+ unload_jack_tunnel(impl);
151
+ }
152
+}
153
+
154
+static void impl_free(struct impl *impl)
155
+{
156
+ set_started(impl, false);
157
+
158
+ if (impl->bus)
159
+ dbus_connection_unref(impl->bus);
160
+ spa_dbus_connection_destroy(impl->conn);
161
+
162
+ pw_properties_free(impl->properties);
163
+
164
+ free(impl);
165
+}
166
+
167
+static void module_destroy(void *data)
168
+{
169
+ struct impl *impl = data;
170
+ spa_hook_remove(&impl->module_listener);
171
+ impl_free(impl);
172
+}
173
+
174
+static const struct pw_impl_module_events module_events = {
175
+ PW_VERSION_IMPL_MODULE_EVENTS,
176
+ .destroy = module_destroy,
177
+};
178
+
179
+static void set_pending_call(struct impl *impl, DBusPendingCall *pending)
180
+{
181
+ if (impl->pending_call != NULL) {
182
+ dbus_pending_call_cancel(impl->pending_call);
183
+ dbus_pending_call_unref(impl->pending_call);
184
+ }
185
+ impl->pending_call = pending;
186
+}
187
+
188
+static void on_is_started_received(DBusPendingCall *pending,
189
+ void *user_data)
190
+{
191
+ struct impl *impl = user_data;
192
+ DBusMessage *m;
193
+ DBusError error;
194
+ dbus_bool_t started = false;
195
+
196
+ m = dbus_pending_call_steal_reply(pending);
197
+ dbus_pending_call_unref(pending);
198
+ impl->pending_call = NULL;
199
+
200
+ dbus_error_init(&error);
201
pipewire-0.3.70.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.71.tar.gz/src/modules/module-pipe-tunnel.c
Changed
33
1
2
* - `stream.props`: Extra properties for the local stream.
3
*
4
* When `tunnel.mode` is `capture`, a capture stream on the default source is
5
- * created. Samples read from the pipe will be the contents of the captured source.
6
+ * created. The samples captured from the source will be written to the pipe.
7
*
8
- * When `tunnel.mode` is `sink`, a sink node is created. Samples read from the
9
- * pipe will be the samples played on the sink.
10
+ * When `tunnel.mode` is `sink`, a sink node is created. Samples played on the
11
+ * sink will be written to the pipe.
12
*
13
* When `tunnel.mode` is `playback`, a playback stream on the default sink is
14
- * created. Samples written to the pipe will be played on the sink.
15
+ * created. The samples read from the pipe will be played on the sink.
16
*
17
- * When `tunnel.mode` is `source`, a source node is created. Samples written to
18
- * the pipe will be made available to streams connected to the source.
19
+ * When `tunnel.mode` is `source`, a source node is created. Samples read from
20
+ * the the pipe will be made available on the source.
21
*
22
* When `pipe.filename` is not given, a default fifo in `/tmp/fifo_input` or
23
* `/tmp/fifo_output` will be created that can be written and read respectively,
24
25
26
#define NAME "pipe-tunnel"
27
28
-#define DEFAULT_CAPTURE_FILENAME "/tmp/fifo_input"
29
+#define DEFAULT_CAPTURE_FILENAME "/tmp/fifo_input"
30
#define DEFAULT_PLAYBACK_FILENAME "/tmp/fifo_output"
31
32
#define DEFAULT_FORMAT "S16"
33
pipewire-0.3.70.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.71.tar.gz/src/modules/module-profiler.c
Changed
36
1
2
struct pw_context *context;
3
struct pw_properties *properties;
4
5
+ struct pw_loop *data_loop;
6
+
7
struct spa_hook context_listener;
8
struct spa_hook module_listener;
9
10
11
static void stop_listener(struct impl *impl)
12
{
13
if (impl->listening) {
14
- pw_loop_invoke(impl->context->data_loop,
15
+ pw_loop_invoke(impl->data_loop,
16
do_stop, SPA_ID_INVALID, NULL, 0, true, impl);
17
impl->listening = false;
18
}
19
20
21
if (++impl->busy == 1) {
22
pw_log_info("%p: starting profiler", impl);
23
- pw_loop_invoke(impl->context->data_loop,
24
+ pw_loop_invoke(impl->data_loop,
25
do_start, SPA_ID_INVALID, NULL, 0, false, impl);
26
impl->listening = true;
27
}
28
29
30
impl->context = context;
31
impl->properties = props;
32
+ impl->data_loop = pw_context_get_data_loop(impl->context)->loop;
33
34
spa_ringbuffer_init(&impl->buffer);
35
36
pipewire-0.3.70.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-native.c
Changed
20
1
2
{
3
struct spa_pod *pod;
4
pw_logt_debug(mod_topic_connection,
5
- "%s: id:%d op:%d size:%d seq:%d", prefix,
6
- msg->id, msg->opcode, msg->size, msg->seq);
7
+ "%s: id:%d op:%d size:%d seq:%d fds:%d", prefix,
8
+ msg->id, msg->opcode, msg->size, msg->seq, msg->n_fds);
9
10
if ((pod = get_first_pod_from_data(msg->data, msg->size, 0)) != NULL)
11
spa_debug_pod(0, NULL, pod);
12
13
break;
14
15
if (client->core_resource == NULL) {
16
+ pw_log_debug("%p: no core resource", client);
17
res = -EPROTO;
18
goto error;
19
}
20
pipewire-0.3.70.tar.gz/src/modules/module-protocol-native/connection.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-native/connection.c
Changed
51
1
2
return -errno;
3
4
cmsgs_truncated:
5
+ pw_log_debug("connection %p: cmsg truncated", conn);
6
close_all_fds(&msg, CMSG_FIRSTHDR(&msg));
7
return -EPROTO;
8
9
too_many_fds:
10
+ pw_log_debug("connection %p: too many fds", conn);
11
close_all_fds(&msg, cmsg);
12
return -EPROTO;
13
}
14
15
static void clear_buffer(struct buffer *buf, bool fds)
16
{
17
uint32_t i;
18
+
19
+ pw_log_debug("clear fds:%d", fds);
20
if (fds) {
21
for (i = 0; i < buf->n_fds; i++) {
22
pw_log_debug("%p: close fd:%d", buf, buf->fdsi);
23
close(buf->fdsi);
24
}
25
+ buf->n_fds = 0;
26
+ buf->fds_offset = 0;
27
+ } else {
28
+ buf->n_fds -= SPA_MIN(buf->fds_offset, buf->n_fds);
29
+ memmove(buf->fds, &buf->fdsbuf->fds_offset, buf->n_fds * sizeof(int));
30
+ buf->fds_offset = 0;
31
}
32
- buf->n_fds = 0;
33
buf->buffer_size = 0;
34
buf->offset = 0;
35
- buf->fds_offset = 0;
36
}
37
38
/** Prepare connection for calling from reentered context.
39
40
41
if (mod_topic_connection->level >= SPA_LOG_LEVEL_DEBUG) {
42
pw_logt_debug(mod_topic_connection,
43
- ">>>>>>>>> out: id:%d op:%d size:%d seq:%d",
44
- buf->msg.id, buf->msg.opcode, size, buf->msg.seq);
45
+ ">>>>>>>>> out: id:%d op:%d size:%d seq:%d fds:%d",
46
+ buf->msg.id, buf->msg.opcode, size, buf->msg.seq,
47
+ buf->msg.n_fds);
48
spa_debug_pod(0, NULL, SPA_PTROFF(p, impl->hdr_size, struct spa_pod));
49
pw_logt_debug(mod_topic_connection,
50
">>>>>>>>> out: done");
51
pipewire-0.3.70.tar.gz/src/modules/module-protocol-native/v0/protocol-native.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-native/v0/protocol-native.c
Changed
58
1
2
static int remap_from_v2(uint32_t type, void *body, uint32_t size, struct pw_impl_client *client,
3
struct spa_pod_builder *builder)
4
{
5
- int res;
6
+ int res = 0;
7
8
switch (type) {
9
case SPA_TYPE_Id:
10
11
if (b->value.type == SPA_TYPE_Id) {
12
uint32_t id;
13
if ((res = spa_pod_get_id(&b->value, &id)) < 0)
14
- return res;
15
+ goto done;
16
+
17
spa_pod_builder_id(builder, pw_protocol_native0_type_from_v2(client, id));
18
SPA_POD_PROP_ALTERNATIVE_FOREACH0(b, size, alt)
19
if ((res = remap_from_v2(b->value.type, alt, b->value.size, client, builder)) < 0)
20
- return res;
21
+ break;
22
} else {
23
spa_pod_builder_raw(builder, &b->value, size - sizeof(struct spa_pod));
24
}
25
-
26
+done:
27
spa_pod_builder_pop(builder, &f);
28
-
29
break;
30
}
31
case SPA_TYPE_Object:
32
33
SPA_POD_BODY(p),
34
p->size,
35
client, builder)) < 0)
36
- return res;
37
+ break;
38
}
39
spa_pod_builder_pop(builder, &f);
40
break;
41
42
spa_pod_builder_push_struct(builder, &f);
43
SPA_POD_FOREACH(b, size, p)
44
if ((res = remap_from_v2(p->type, SPA_POD_BODY(p), p->size, client, builder)) < 0)
45
- return res;
46
+ break;
47
spa_pod_builder_pop(builder, &f);
48
break;
49
}
50
default:
51
break;
52
}
53
- return 0;
54
+ return res;
55
}
56
57
static int remap_to_v2(struct pw_impl_client *client, const struct spa_type_info *info,
58
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
126
1
2
free(s);
3
}
4
5
-int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, struct spa_audio_info_raw *info)
6
+int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props,
7
+ const char *key_format, const char *key_rate,
8
+ const char *key_channels, const char *key_channel_map,
9
+ struct spa_audio_info_raw *info)
10
{
11
const char *str;
12
uint32_t i;
13
14
- /* We don't use any incoming format setting and use our native format */
15
- spa_zero(*info);
16
- info->flags = SPA_AUDIO_FLAG_UNPOSITIONED;
17
- info->format = SPA_AUDIO_FORMAT_F32P;
18
-
19
- if ((str = pw_properties_get(props, "channels")) != NULL) {
20
+ if (key_format && (str = pw_properties_get(props, key_format)) != NULL) {
21
+ info->format = format_paname2id(str, strlen(str));
22
+ if (info->format == SPA_AUDIO_FORMAT_UNKNOWN) {
23
+ pw_log_error("invalid %s '%s'", key_format, str);
24
+ return -EINVAL;
25
+ }
26
+ pw_properties_set(props, key_format, NULL);
27
+ }
28
+ if (key_channels && (str = pw_properties_get(props, key_channels)) != NULL) {
29
info->channels = pw_properties_parse_int(str);
30
if (info->channels == 0 || info->channels > SPA_AUDIO_MAX_CHANNELS) {
31
- pw_log_error("invalid channels '%s'", str);
32
+ pw_log_error("invalid %s '%s'", key_channels, str);
33
return -EINVAL;
34
}
35
- pw_properties_set(props, "channels", NULL);
36
+ pw_properties_set(props, key_channels, NULL);
37
}
38
- if ((str = pw_properties_get(props, "channel_map")) != NULL) {
39
+ if (key_channel_map && (str = pw_properties_get(props, key_channel_map)) != NULL) {
40
struct channel_map map;
41
42
channel_map_parse(str, &map);
43
if (map.channels == 0 || map.channels > SPA_AUDIO_MAX_CHANNELS) {
44
- pw_log_error("invalid channel_map '%s'", str);
45
+ pw_log_error("invalid %s '%s'", key_channel_map, str);
46
return -EINVAL;
47
}
48
if (info->channels == 0)
49
info->channels = map.channels;
50
if (info->channels != map.channels) {
51
- pw_log_error("Mismatched channel map");
52
+ pw_log_error("Mismatched %s and %s (%d vs %d)",
53
+ key_channels, key_channel_map,
54
+ info->channels, map.channels);
55
return -EINVAL;
56
}
57
channel_map_to_positions(&map, info->position);
58
- info->flags &= ~SPA_AUDIO_FLAG_UNPOSITIONED;
59
- pw_properties_set(props, "channel_map", NULL);
60
+ pw_properties_set(props, key_channel_map, NULL);
61
} else {
62
if (info->channels == 0)
63
info->channels = impl->defs.sample_spec.channels;
64
65
for (i = 0; i < info->channels; i++)
66
info->positioni = SPA_AUDIO_CHANNEL_UNKNOWN;
67
}
68
- if (info->position0 != SPA_AUDIO_CHANNEL_UNKNOWN)
69
- info->flags &= ~SPA_AUDIO_FLAG_UNPOSITIONED;
70
+ if (info->position0 == SPA_AUDIO_CHANNEL_UNKNOWN)
71
+ info->flags |= SPA_AUDIO_FLAG_UNPOSITIONED;
72
}
73
-
74
- if ((str = pw_properties_get(props, "rate")) != NULL) {
75
+ if (key_rate && (str = pw_properties_get(props, key_rate)) != NULL) {
76
info->rate = pw_properties_parse_int(str);
77
- pw_properties_set(props, "rate", NULL);
78
- } else {
79
- info->rate = 0;
80
+ pw_properties_set(props, key_rate, NULL);
81
}
82
return 0;
83
}
84
85
+int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, struct spa_audio_info_raw *info)
86
+{
87
+ /* We don't use any incoming format setting and use our native format */
88
+ spa_zero(*info);
89
+ info->format = SPA_AUDIO_FORMAT_F32P;
90
+ return module_args_to_audioinfo_keys(impl, props,
91
+ NULL, "rate", "channels", "channel_map", info);
92
+}
93
+
94
bool module_args_parse_bool(const char *v)
95
{
96
if (spa_streq(v, "1") || !strcasecmp(v, "y") || !strcasecmp(v, "t") ||
97
98
return false;
99
}
100
101
+void audioinfo_to_properties(struct spa_audio_info_raw *info, struct pw_properties *props)
102
+{
103
+ uint32_t i;
104
+
105
+ if (info->format)
106
+ pw_properties_setf(props, SPA_KEY_AUDIO_FORMAT, "%s",
107
+ format_id2name(info->format));
108
+ if (info->rate)
109
+ pw_properties_setf(props, SPA_KEY_AUDIO_RATE, "%u", info->rate);
110
+ if (info->channels) {
111
+ char *s, *p;
112
+
113
+ pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
114
+
115
+ p = s = alloca(info->channels * 8);
116
+ for (i = 0; i < info->channels; i++)
117
+ p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ", ",
118
+ channel_id2name(info->positioni));
119
+ pw_properties_setf(props, SPA_KEY_AUDIO_POSITION, " %s ", s);
120
+ }
121
+}
122
+
123
static const struct module_info *find_module_info(const char *name)
124
{
125
extern const struct module_info __start_pw_mod_pulse_modules;
126
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/module.h
Changed
14
1
2
void module_args_add_props(struct pw_properties *props, const char *str);
3
int module_args_to_audioinfo(struct impl *impl, struct pw_properties *props, struct spa_audio_info_raw *info);
4
bool module_args_parse_bool(const char *str);
5
+int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props,
6
+ const char *key_format, const char *key_rate,
7
+ const char *key_channels, const char *key_channel_map,
8
+ struct spa_audio_info_raw *info);
9
+
10
+void audioinfo_to_properties(struct spa_audio_info_raw *info, struct pw_properties *props);
11
+
12
13
#endif
14
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c
Changed
171
1
2
"rate=<sample rate> "
3
"channels=<number of channels> "
4
"channel_map=<channel map> "
5
- "remix=<remix channels> " },
6
+ "remix=<remix channels> "
7
+ "latency_compensate=<bool> " },
8
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
9
};
10
11
12
struct pw_impl_module *mod;
13
struct spa_hook mod_listener;
14
15
- char *sink_name;
16
char **sink_names;
17
+ struct pw_properties *props;
18
struct pw_properties *combine_props;
19
+ struct pw_properties *stream_props;
20
21
struct spa_source *sinks_timeout;
22
23
struct spa_audio_info_raw info;
24
25
unsigned int sinks_pending;
26
- unsigned int remix:1;
27
unsigned int load_emitted:1;
28
unsigned int start_error:1;
29
};
30
31
if (data->core == NULL)
32
return -errno;
33
34
+ pw_properties_setf(data->combine_props, "pulse.module.id", "%u",
35
+ module->index);
36
+ pw_properties_setf(data->stream_props, "pulse.module.id", "%u",
37
+ module->index);
38
+
39
if ((f = open_memstream(&args, &size)) == NULL)
40
return -errno;
41
42
fprintf(f, "{");
43
- fprintf(f, " node.name = %s", data->sink_name);
44
- fprintf(f, " node.description = %s", data->sink_name);
45
- if (data->info.rate != 0)
46
- fprintf(f, " audio.rate = %u", data->info.rate);
47
- if (data->info.channels != 0) {
48
- fprintf(f, " audio.channels = %u", data->info.channels);
49
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
50
- fprintf(f, " audio.position = ");
51
- for (i = 0; i < data->info.channels; i++)
52
- fprintf(f, "%s%s", i == 0 ? "" : ",",
53
- channel_id2name(data->info.positioni));
54
- fprintf(f, " ");
55
- }
56
- }
57
+ pw_properties_serialize_dict(f, &data->props->dict, 0);
58
fprintf(f, " combine.props = {");
59
- fprintf(f, " pulse.module.id = %u", module->index);
60
pw_properties_serialize_dict(f, &data->combine_props->dict, 0);
61
fprintf(f, " } stream.props = {");
62
- if (!data->remix)
63
- fprintf(f, " "PW_KEY_STREAM_DONT_REMIX" = true");
64
- fprintf(f, " pulse.module.id = %u", module->index);
65
+ pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
66
fprintf(f, " } stream.rules = ");
67
if (data->sink_names == NULL) {
68
fprintf(f, " { matches = { media.class = \"Audio/Sink\" } ");
69
70
pw_core_disconnect(d->core);
71
}
72
pw_free_strv(d->sink_names);
73
- free(d->sink_name);
74
+ pw_properties_free(d->stream_props);
75
pw_properties_free(d->combine_props);
76
+ pw_properties_free(d->props);
77
return 0;
78
}
79
80
81
{
82
struct module_combine_sink_data * const d = module->user_data;
83
struct pw_properties * const props = module->props;
84
- struct pw_properties *combine_props = NULL;
85
+ struct pw_properties *combine_props = NULL, *global_props = NULL, *stream_props = NULL;
86
const char *str;
87
- char *sink_name = NULL, **sink_names = NULL;
88
+ char **sink_names = NULL;
89
struct spa_audio_info_raw info = { 0 };
90
int res;
91
int num_sinks = 0;
92
93
PW_LOG_TOPIC_INIT(mod_topic);
94
95
+ global_props = pw_properties_new(NULL, NULL);
96
combine_props = pw_properties_new(NULL, NULL);
97
+ stream_props = pw_properties_new(NULL, NULL);
98
+ if (global_props == NULL || combine_props == NULL || stream_props == NULL) {
99
+ res = -ENOMEM;
100
+ goto out;
101
+ }
102
103
if ((str = pw_properties_get(props, "sink_name")) != NULL) {
104
- sink_name = strdup(str);
105
+ pw_properties_set(global_props, PW_KEY_NODE_NAME, str);
106
+ pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, str);
107
pw_properties_set(props, "sink_name", NULL);
108
} else {
109
- sink_name = strdup("combined");
110
+ str = "combined";
111
+ pw_properties_set(global_props, PW_KEY_NODE_NAME, str);
112
+ pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, str);
113
}
114
115
- if ((str = pw_properties_get(module->props, "sink_properties")) != NULL)
116
+ if ((str = pw_properties_get(props, "sink_properties")) != NULL)
117
module_args_add_props(combine_props, str);
118
119
if ((str = pw_properties_get(props, "slaves")) != NULL) {
120
sink_names = pw_split_strv(str, ",", MAX_SINKS, &num_sinks);
121
pw_properties_set(props, "slaves", NULL);
122
}
123
- d->remix = true;
124
if ((str = pw_properties_get(props, "remix")) != NULL) {
125
- d->remix = pw_properties_parse_bool(str);
126
+ pw_properties_set(stream_props, PW_KEY_STREAM_DONT_REMIX,
127
+ module_args_parse_bool(str) ? "false" : "true");
128
pw_properties_set(props, "remix", NULL);
129
}
130
131
+ if ((str = pw_properties_get(props, "latency_compensate")) != NULL) {
132
+ pw_properties_set(global_props, "combine.latency-compensate",
133
+ module_args_parse_bool(str) ? "true" : "false");
134
+ pw_properties_set(props, "latency_compensate", NULL);
135
+ }
136
+
137
if ((str = pw_properties_get(props, "adjust_time")) != NULL) {
138
pw_log_info("The `adjust_time` modarg is ignored");
139
pw_properties_set(props, "adjust_time", NULL);
140
141
pw_properties_set(props, "resample_method", NULL);
142
}
143
144
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
145
+ if (module_args_to_audioinfo_keys(module->impl, props,
146
+ NULL, "rate", "channels", "channel_map", &info) < 0) {
147
res = -EINVAL;
148
goto out;
149
}
150
+ audioinfo_to_properties(&info, global_props);
151
152
d->module = module;
153
d->info = info;
154
- d->sink_name = sink_name;
155
d->sink_names = sink_names;
156
d->sinks_pending = (sink_names == NULL) ? 0 : num_sinks;
157
+ d->stream_props = stream_props;
158
d->combine_props = combine_props;
159
+ d->props = global_props;
160
161
return 0;
162
out:
163
- free(sink_name);
164
pw_free_strv(sink_names);
165
+ pw_properties_free(stream_props);
166
pw_properties_free(combine_props);
167
+ pw_properties_free(global_props);
168
169
return res;
170
}
171
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c
Changed
111
1
2
struct pw_impl_module *mod;
3
struct spa_hook mod_listener;
4
5
+ struct pw_properties *global_props;
6
struct pw_properties *props;
7
struct pw_properties *capture_props;
8
struct pw_properties *source_props;
9
10
11
static int module_echo_cancel_load(struct module *module)
12
{
13
- struct pw_properties * const props = module->props;
14
struct module_echo_cancel_data *data = module->user_data;
15
- const char *method;
16
FILE *f;
17
char *args;
18
size_t size;
19
- uint32_t i;
20
21
if ((f = open_memstream(&args, &size)) == NULL)
22
return -errno;
23
24
fprintf(f, "{");
25
- if ((method = pw_properties_get(props, "aec_method")) == NULL)
26
- method = "webrtc";
27
-
28
- fprintf(f, " library.name = \"aec/libspa-aec-%s\"", method);
29
-
30
+ pw_properties_serialize_dict(f, &data->global_props->dict, 0);
31
fprintf(f, " aec.args = {");
32
pw_properties_serialize_dict(f, &data->props->dict, 0);
33
fprintf(f, " }");
34
- if (data->info.rate != 0)
35
- fprintf(f, " audio.rate = %u", data->info.rate);
36
- if (data->info.channels != 0) {
37
- fprintf(f, " audio.channels = %u", data->info.channels);
38
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
39
- fprintf(f, " audio.position = ");
40
- for (i = 0; i < data->info.channels; i++)
41
- fprintf(f, "%s%s", i == 0 ? "" : ",",
42
- channel_id2name(data->info.positioni));
43
- fprintf(f, " ");
44
- }
45
- }
46
fprintf(f, " capture.props = {");
47
pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
48
fprintf(f, " } source.props = {");
49
50
d->mod = NULL;
51
}
52
53
+ pw_properties_free(d->global_props);
54
pw_properties_free(d->props);
55
pw_properties_free(d->capture_props);
56
pw_properties_free(d->source_props);
57
58
struct pw_properties * const props = module->props;
59
struct pw_properties *aec_props = NULL, *sink_props = NULL, *source_props = NULL;
60
struct pw_properties *playback_props = NULL, *capture_props = NULL;
61
+ struct pw_properties *global_props = NULL;
62
const char *str, *method;
63
struct spa_audio_info_raw info = { 0 };
64
int res;
65
66
PW_LOG_TOPIC_INIT(mod_topic);
67
68
+ global_props = pw_properties_new(NULL, NULL);
69
aec_props = pw_properties_new(NULL, NULL);
70
capture_props = pw_properties_new(NULL, NULL);
71
source_props = pw_properties_new(NULL, NULL);
72
sink_props = pw_properties_new(NULL, NULL);
73
playback_props = pw_properties_new(NULL, NULL);
74
- if (!aec_props || !source_props || !sink_props || !capture_props || !playback_props) {
75
+ if (!global_props || !aec_props || !source_props || !sink_props || !capture_props || !playback_props) {
76
res = -EINVAL;
77
goto out;
78
}
79
80
+ if ((str = pw_properties_get(props, "aec_method")) == NULL)
81
+ str = "webrtc";
82
+ pw_properties_setf(global_props, "library.name", "aec/libspa-aec-%s", str);
83
+
84
if ((str = pw_properties_get(props, "source_name")) != NULL) {
85
pw_properties_set(source_props, PW_KEY_NODE_NAME, str);
86
pw_properties_set(props, "source_name", NULL);
87
88
res = -EINVAL;
89
goto out;
90
}
91
+ audioinfo_to_properties(&info, global_props);
92
93
if ((str = pw_properties_get(props, "source_properties")) != NULL) {
94
module_args_add_props(source_props, str);
95
96
}
97
98
d->module = module;
99
+ d->global_props = global_props;
100
d->props = aec_props;
101
d->capture_props = capture_props;
102
d->source_props = source_props;
103
104
105
return 0;
106
out:
107
+ pw_properties_free(global_props);
108
pw_properties_free(aec_props);
109
pw_properties_free(playback_props);
110
pw_properties_free(sink_props);
111
pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-jackdbus-detect.c
Added
201
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <spa/utils/hook.h>
7
+#include <pipewire/pipewire.h>
8
+
9
+#include "../defs.h"
10
+#include "../module.h"
11
+
12
+#define NAME "jackdbus-detect"
13
+
14
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
15
+#define PW_LOG_TOPIC_DEFAULT mod_topic
16
+
17
+
18
+struct module_jackdbus_detect_data {
19
+ struct module *module;
20
+
21
+ struct spa_hook mod_listener;
22
+ struct pw_impl_module *mod;
23
+
24
+ struct pw_properties *props;
25
+ struct pw_properties *sink_props;
26
+ struct pw_properties *source_props;
27
+};
28
+
29
+static void module_destroy(void *data)
30
+{
31
+ struct module_jackdbus_detect_data *d = data;
32
+ spa_hook_remove(&d->mod_listener);
33
+ d->mod = NULL;
34
+ module_schedule_unload(d->module);
35
+}
36
+
37
+static const struct pw_impl_module_events module_events = {
38
+ PW_VERSION_IMPL_MODULE_EVENTS,
39
+ .destroy = module_destroy
40
+};
41
+
42
+static int module_jackdbus_detect_load(struct module *module)
43
+{
44
+ struct module_jackdbus_detect_data *data = module->user_data;
45
+ FILE *f;
46
+ char *args;
47
+ size_t size;
48
+
49
+ pw_properties_setf(data->sink_props, "pulse.module.id",
50
+ "%u", module->index);
51
+ pw_properties_setf(data->source_props, "pulse.module.id",
52
+ "%u", module->index);
53
+
54
+ if ((f = open_memstream(&args, &size)) == NULL)
55
+ return -errno;
56
+
57
+ fprintf(f, "{");
58
+ pw_properties_serialize_dict(f, &data->props->dict, 0);
59
+ fprintf(f, " source.props = {");
60
+ pw_properties_serialize_dict(f, &data->source_props->dict, 0);
61
+ fprintf(f, " } sink.props = {");
62
+ pw_properties_serialize_dict(f, &data->sink_props->dict, 0);
63
+ fprintf(f, " } }");
64
+ fclose(f);
65
+
66
+ data->mod = pw_context_load_module(module->impl->context,
67
+ "libpipewire-module-jackdbus-detect",
68
+ args, NULL);
69
+ free(args);
70
+
71
+ if (data->mod == NULL)
72
+ return -errno;
73
+
74
+ pw_impl_module_add_listener(data->mod,
75
+ &data->mod_listener,
76
+ &module_events, data);
77
+
78
+ return 0;
79
+}
80
+
81
+static int module_jackdbus_detect_unload(struct module *module)
82
+{
83
+ struct module_jackdbus_detect_data *d = module->user_data;
84
+
85
+ if (d->mod) {
86
+ spa_hook_remove(&d->mod_listener);
87
+ pw_impl_module_destroy(d->mod);
88
+ d->mod = NULL;
89
+ }
90
+
91
+ return 0;
92
+}
93
+
94
+static const struct spa_dict_item module_jackdbus_detect_info = {
95
+ { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.con>" },
96
+ { PW_KEY_MODULE_DESCRIPTION, "Creates a JACK client when jackdbus is started" },
97
+ { PW_KEY_MODULE_USAGE,
98
+ "channels=<number of channels> "
99
+ "sink_name=<name for the sink> "
100
+ "sink_properties=<properties for the sink> "
101
+ "sink_client_name=<jack client name> "
102
+ "sink_channels=<number of channels> "
103
+ "sink_channel_map=<channel map> "
104
+ "source_name=<name for the source> "
105
+ "source_properties=<properties for the source> "
106
+ "source_client_name=<jack client name> "
107
+ "source_channels=<number of channels> "
108
+ "source_channel_map=<channel map> "
109
+ "connect=<connect ports?>" },
110
+ { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
111
+};
112
+
113
+static int module_jackdbus_detect_prepare(struct module * const module)
114
+{
115
+ struct module_jackdbus_detect_data * const data = module->user_data;
116
+ struct pw_properties * const props = module->props;
117
+ struct pw_properties *jack_props = NULL, *sink_props = NULL, *source_props = NULL;
118
+ struct spa_audio_info_raw info;
119
+ const char *str;
120
+ int res;
121
+
122
+ PW_LOG_TOPIC_INIT(mod_topic);
123
+
124
+ jack_props = pw_properties_new(NULL, NULL);
125
+ sink_props = pw_properties_new(NULL, NULL);
126
+ source_props = pw_properties_new(NULL, NULL);
127
+ if (jack_props == NULL || sink_props == NULL || source_props == NULL) {
128
+ res = -ENOMEM;
129
+ goto out;
130
+ }
131
+
132
+ if ((str = pw_properties_get(props, "channels")) != NULL) {
133
+ pw_properties_set(jack_props, PW_KEY_AUDIO_CHANNELS, str);
134
+ pw_properties_set(props, "channels", NULL);
135
+ }
136
+ if ((str = pw_properties_get(props, "connect")) != NULL) {
137
+ pw_properties_set(jack_props, "jack.connect",
138
+ module_args_parse_bool(str) ? "true" : "false");
139
+ }
140
+
141
+ if ((str = pw_properties_get(props, "sink_name")) != NULL) {
142
+ pw_properties_set(sink_props, PW_KEY_NODE_NAME, str);
143
+ pw_properties_set(props, "sink_name", NULL);
144
+ } else {
145
+ pw_properties_set(sink_props, PW_KEY_NODE_NAME, "jack_out");
146
+ }
147
+ if ((str = pw_properties_get(props, "sink_client_name")) != NULL) {
148
+ pw_properties_set(jack_props, "jack.client-name", str);
149
+ pw_properties_set(props, "sink_client_name", NULL);
150
+ }
151
+
152
+ spa_zero(info);
153
+ if ((res = module_args_to_audioinfo_keys(module->impl, props, NULL, NULL,
154
+ "sink_channels", "sink_channel_map", &info)) < 0) {
155
+ return res;
156
+ } else {
157
+ audioinfo_to_properties(&info, sink_props);
158
+ }
159
+ if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
160
+ module_args_add_props(sink_props, str);
161
+ pw_properties_set(props, "sink_properties", NULL);
162
+ }
163
+
164
+ if ((str = pw_properties_get(props, "source_name")) != NULL) {
165
+ pw_properties_set(source_props, PW_KEY_NODE_NAME, str);
166
+ pw_properties_set(props, "source_name", NULL);
167
+ } else {
168
+ pw_properties_set(source_props, PW_KEY_NODE_NAME, "jack_in");
169
+ }
170
+ if ((str = pw_properties_get(props, "source_client_name")) != NULL) {
171
+ pw_properties_set(jack_props, "jack.client-name", str);
172
+ pw_properties_set(props, "source_client_name", NULL);
173
+ }
174
+ spa_zero(info);
175
+ if ((res = module_args_to_audioinfo_keys(module->impl, props, NULL, NULL,
176
+ "source_channels", "source_channel_map", &info)) < 0) {
177
+ return res;
178
+ } else {
179
+ audioinfo_to_properties(&info, source_props);
180
+ }
181
+ if ((str = pw_properties_get(props, "source_properties")) != NULL) {
182
+ module_args_add_props(source_props, str);
183
+ pw_properties_set(props, "source_properties", NULL);
184
+ }
185
+
186
+ data->module = module;
187
+ data->props = jack_props;
188
+ data->sink_props = sink_props;
189
+ data->source_props = source_props;
190
+
191
+ return 0;
192
+out:
193
+ pw_properties_free(jack_props);
194
+ pw_properties_free(sink_props);
195
+ pw_properties_free(source_props);
196
+ return res;
197
+}
198
+
199
+DEFINE_MODULE_INFO(module_jackdbus_detect) = {
200
+ .name = "module-jackdbus-detect",
201
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c
Changed
40
1
2
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
3
};
4
5
-static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
6
-{
7
- char *s, *p;
8
- uint32_t i;
9
-
10
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
11
- p = s = alloca(info->channels * 8);
12
- for (i = 0; i < info->channels; i++)
13
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
14
- channel_id2name(info->positioni));
15
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
16
-}
17
-
18
static int module_ladspa_sink_prepare(struct module * const module)
19
{
20
struct module_ladspa_sink_data * const d = module->user_data;
21
22
pw_properties_set(props, "master", NULL);
23
}
24
25
- if (module_args_to_audioinfo(module->impl, props, &capture_info) < 0) {
26
+ if (module_args_to_audioinfo_keys(module->impl, props,
27
+ NULL, NULL, "channels", "channel_map", &capture_info) < 0) {
28
res = -EINVAL;
29
goto out;
30
}
31
playback_info = capture_info;
32
33
- position_to_props(&capture_info, capture_props);
34
- position_to_props(&playback_info, playback_props);
35
+ audioinfo_to_properties(&capture_info, capture_props);
36
+ audioinfo_to_properties(&playback_info, playback_props);
37
38
if (pw_properties_get(playback_props, PW_KEY_NODE_PASSIVE) == NULL)
39
pw_properties_set(playback_props, PW_KEY_NODE_PASSIVE, "true");
40
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c
Changed
40
1
2
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
3
};
4
5
-static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
6
-{
7
- char *s, *p;
8
- uint32_t i;
9
-
10
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
11
- p = s = alloca(info->channels * 8);
12
- for (i = 0; i < info->channels; i++)
13
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
14
- channel_id2name(info->positioni));
15
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
16
-}
17
-
18
static int module_ladspa_source_prepare(struct module * const module)
19
{
20
struct module_ladspa_source_data * const d = module->user_data;
21
22
pw_properties_set(props, "master", NULL);
23
}
24
25
- if (module_args_to_audioinfo(module->impl, props, &playback_info) < 0) {
26
+ if (module_args_to_audioinfo_keys(module->impl, props,
27
+ NULL, NULL, "channels", "channel_map", &playback_info) < 0) {
28
res = -EINVAL;
29
goto out;
30
}
31
capture_info = playback_info;
32
33
- position_to_props(&capture_info, capture_props);
34
- position_to_props(&playback_info, playback_props);
35
+ audioinfo_to_properties(&capture_info, capture_props);
36
+ audioinfo_to_properties(&playback_info, playback_props);
37
38
if (pw_properties_get(capture_props, PW_KEY_NODE_PASSIVE) == NULL)
39
pw_properties_set(capture_props, PW_KEY_NODE_PASSIVE, "true");
40
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c
Changed
119
1
2
struct pw_impl_module *mod;
3
struct spa_hook mod_listener;
4
5
+ struct pw_properties *global_props;
6
struct pw_properties *capture_props;
7
struct pw_properties *playback_props;
8
-
9
- struct spa_audio_info_raw info;
10
- uint32_t latency_msec;
11
};
12
13
static void module_destroy(void *data)
14
15
struct module_loopback_data *data = module->user_data;
16
FILE *f;
17
char *args;
18
- size_t size, i;
19
- char val256;
20
+ size_t size;
21
22
pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
23
pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
24
25
return -errno;
26
27
fprintf(f, "{");
28
- if (data->info.channels != 0) {
29
- fprintf(f, " audio.channels = %u", data->info.channels);
30
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
31
- fprintf(f, " audio.position = ");
32
- for (i = 0; i < data->info.channels; i++)
33
- fprintf(f, "%s%s", i == 0 ? "" : ",",
34
- channel_id2name(data->info.positioni));
35
- fprintf(f, " ");
36
- }
37
- }
38
- if (data->latency_msec != 0)
39
- fprintf(f, " target.delay.sec = %s",
40
- spa_json_format_float(val, sizeof(val),
41
- data->latency_msec / 1000.0f));
42
+ pw_properties_serialize_dict(f, &data->global_props->dict, 0);
43
fprintf(f, " capture.props = {");
44
pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
45
fprintf(f, " } playback.props = {");
46
47
48
pw_properties_free(d->capture_props);
49
pw_properties_free(d->playback_props);
50
+ pw_properties_free(d->global_props);
51
52
return 0;
53
}
54
55
{
56
struct module_loopback_data * const d = module->user_data;
57
struct pw_properties * const props = module->props;
58
- struct pw_properties *playback_props = NULL, *capture_props = NULL;
59
+ struct pw_properties *global_props = NULL, *playback_props = NULL, *capture_props = NULL;
60
const char *str;
61
struct spa_audio_info_raw info = { 0 };
62
int res;
63
64
PW_LOG_TOPIC_INIT(mod_topic);
65
66
+ global_props = pw_properties_new(NULL, NULL);
67
capture_props = pw_properties_new(NULL, NULL);
68
playback_props = pw_properties_new(NULL, NULL);
69
- if (!capture_props || !playback_props) {
70
+ if (!global_props || !capture_props || !playback_props) {
71
res = -EINVAL;
72
goto out;
73
}
74
75
pw_properties_set(props, "sink", NULL);
76
}
77
78
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
79
+ if (module_args_to_audioinfo_keys(module->impl, props,
80
+ NULL, NULL, "channels", "channel_map", &info) < 0) {
81
res = -EINVAL;
82
goto out;
83
}
84
+ audioinfo_to_properties(&info, global_props);
85
86
if ((str = pw_properties_get(props, "source_dont_move")) != NULL) {
87
pw_properties_set(capture_props, PW_KEY_NODE_DONT_RECONNECT, str);
88
89
pw_properties_set(props, "remix", NULL);
90
}
91
92
- if ((str = pw_properties_get(props, "latency_msec")) != NULL)
93
- d->latency_msec = atoi(str);
94
+ if ((str = pw_properties_get(props, "latency_msec")) != NULL) {
95
+ uint32_t latency_msec = atoi(str);
96
+ char val256;
97
+ pw_properties_setf(global_props, "target.delay.sec",
98
+ "%s", spa_json_format_float(val, sizeof(val),
99
+ latency_msec / 1000.0f));
100
+ }
101
102
if ((str = pw_properties_get(props, "sink_input_properties")) != NULL) {
103
module_args_add_props(playback_props, str);
104
105
}
106
107
d->module = module;
108
+ d->global_props = global_props;
109
d->capture_props = capture_props;
110
d->playback_props = playback_props;
111
- d->info = info;
112
113
return 0;
114
out:
115
+ pw_properties_free(global_props);
116
pw_properties_free(playback_props);
117
pw_properties_free(capture_props);
118
119
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c
Changed
48
1
2
struct pw_properties * const props = module->props;
3
const char *str;
4
struct spa_audio_info_raw info = { 0 };
5
- uint32_t i;
6
7
PW_LOG_TOPIC_INIT(mod_topic);
8
9
10
pw_properties_set(props, "sink_properties", NULL);
11
}
12
13
- if (module_args_to_audioinfo(module->impl, props, &info) < 0)
14
+ if (module_args_to_audioinfo_keys(module->impl, props,
15
+ "format", "rate", "channels", "channel_map", &info) < 0)
16
return -EINVAL;
17
18
- info.format = module->impl->defs.sample_spec.format;
19
- if ((str = pw_properties_get(props, "format")) != NULL) {
20
- info.format = format_paname2id(str, strlen(str));
21
- if (info.format == SPA_AUDIO_FORMAT_UNKNOWN) {
22
- pw_log_error("invalid format '%s'", str);
23
- return -EINVAL;
24
- }
25
- pw_properties_set(props, "format", NULL);
26
- }
27
-
28
- if (info.format)
29
- pw_properties_setf(props, SPA_KEY_AUDIO_FORMAT, "%s",
30
- format_id2name(info.format));
31
- if (info.rate)
32
- pw_properties_setf(props, SPA_KEY_AUDIO_RATE, "%u", info.rate);
33
- if (info.channels) {
34
- char *s, *p;
35
-
36
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info.channels);
37
-
38
- p = s = alloca(info.channels * 8);
39
- for (i = 0; i < info.channels; i++)
40
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
41
- channel_id2name(info.positioni));
42
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
43
- }
44
+ audioinfo_to_properties(&info, props);
45
46
if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
47
pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
48
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c
Changed
125
1
2
struct spa_hook mod_listener;
3
struct pw_impl_module *mod;
4
5
+ struct pw_properties *global_props;
6
struct pw_properties *capture_props;
7
- struct spa_audio_info_raw info;
8
- char *filename;
9
};
10
11
static void module_destroy(void *data)
12
13
FILE *f;
14
char *args;
15
size_t size;
16
- uint32_t i;
17
18
pw_properties_setf(data->capture_props, "pulse.module.id",
19
"%u", module->index);
20
21
return -errno;
22
23
fprintf(f, "{");
24
- fprintf(f, " \"tunnel.mode\" = \"sink\" ");
25
- if (data->filename != NULL)
26
- fprintf(f, " \"pipe.filename\": \"%s\"", data->filename);
27
- if (data->info.format != 0)
28
- fprintf(f, " \"audio.format\": \"%s\"", format_id2name(data->info.format));
29
- if (data->info.rate != 0)
30
- fprintf(f, " \"audio.rate\": %u,", data->info.rate);
31
- if (data->info.channels != 0) {
32
- fprintf(f, " \"audio.channels\": %u,", data->info.channels);
33
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
34
- fprintf(f, " \"audio.position\": ");
35
- for (i = 0; i < data->info.channels; i++)
36
- fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
37
- channel_id2name(data->info.positioni));
38
- fprintf(f, " ,");
39
- }
40
- }
41
+ pw_properties_serialize_dict(f, &data->global_props->dict, 0);
42
fprintf(f, " \"stream.props\": {");
43
pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
44
fprintf(f, " } }");
45
46
d->mod = NULL;
47
}
48
pw_properties_free(d->capture_props);
49
- free(d->filename);
50
+ pw_properties_free(d->global_props);
51
return 0;
52
}
53
54
55
{
56
struct module_pipesink_data * const d = module->user_data;
57
struct pw_properties * const props = module->props;
58
- struct pw_properties *capture_props = NULL;
59
+ struct pw_properties *global_props = NULL, *capture_props = NULL;
60
struct spa_audio_info_raw info = { 0 };
61
const char *str;
62
- char *filename = NULL;
63
int res = 0;
64
65
PW_LOG_TOPIC_INIT(mod_topic);
66
67
+ global_props = pw_properties_new(NULL, NULL);
68
capture_props = pw_properties_new(NULL, NULL);
69
- if (!capture_props) {
70
+ if (!global_props || !capture_props) {
71
res = -EINVAL;
72
goto out;
73
}
74
75
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
76
+ pw_properties_set(global_props, "tunnel.mode", "sink");
77
+
78
+ info.format = SPA_AUDIO_FORMAT_S16;
79
+ if (module_args_to_audioinfo_keys(module->impl, props,
80
+ "format", "rate", "channels", "channel_map", &info) < 0) {
81
res = -EINVAL;
82
goto out;
83
}
84
+ audioinfo_to_properties(&info, global_props);
85
86
- info.format = SPA_AUDIO_FORMAT_S16;
87
- if ((str = pw_properties_get(props, "format")) != NULL) {
88
- info.format = format_paname2id(str, strlen(str));
89
- if (info.format == SPA_AUDIO_FORMAT_UNKNOWN) {
90
- pw_log_error("invalid format '%s'", str);
91
- res = -EINVAL;
92
- goto out;
93
- }
94
- pw_properties_set(props, "format", NULL);
95
- }
96
if ((str = pw_properties_get(props, "sink_name")) != NULL) {
97
pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
98
pw_properties_set(props, "sink_name", NULL);
99
100
module_args_add_props(capture_props, str);
101
102
if ((str = pw_properties_get(props, "file")) != NULL) {
103
- filename = strdup(str);
104
+ pw_properties_set(global_props, "pipe.filename", str);
105
pw_properties_set(props, "file", NULL);
106
}
107
if ((str = pw_properties_get(capture_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
108
109
"fifo_output");
110
111
d->module = module;
112
+ d->global_props = global_props;
113
d->capture_props = capture_props;
114
- d->info = info;
115
- d->filename = filename;
116
117
return 0;
118
out:
119
+ pw_properties_free(global_props);
120
pw_properties_free(capture_props);
121
- free(filename);
122
return res;
123
}
124
125
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c
Changed
124
1
2
struct spa_hook mod_listener;
3
struct pw_impl_module *mod;
4
5
+ struct pw_properties *global_props;
6
struct pw_properties *playback_props;
7
- struct spa_audio_info_raw info;
8
- char *filename;
9
};
10
11
static void module_destroy(void *data)
12
13
FILE *f;
14
char *args;
15
size_t size;
16
- uint32_t i;
17
18
pw_properties_setf(data->playback_props, "pulse.module.id",
19
"%u", module->index);
20
21
return -errno;
22
23
fprintf(f, "{");
24
- fprintf(f, " \"tunnel.mode\" = \"source\" ");
25
- if (data->filename != NULL)
26
- fprintf(f, " \"pipe.filename\": \"%s\"", data->filename);
27
- if (data->info.format != 0)
28
- fprintf(f, " \"audio.format\": \"%s\"", format_id2name(data->info.format));
29
- if (data->info.rate != 0)
30
- fprintf(f, " \"audio.rate\": %u,", data->info.rate);
31
- if (data->info.channels != 0) {
32
- fprintf(f, " \"audio.channels\": %u,", data->info.channels);
33
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
34
- fprintf(f, " \"audio.position\": ");
35
- for (i = 0; i < data->info.channels; i++)
36
- fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
37
- channel_id2name(data->info.positioni));
38
- fprintf(f, " ,");
39
- }
40
- }
41
+ pw_properties_serialize_dict(f, &data->global_props->dict, 0);
42
fprintf(f, " \"stream.props\": {");
43
pw_properties_serialize_dict(f, &data->playback_props->dict, 0);
44
fprintf(f, " } }");
45
46
d->mod = NULL;
47
}
48
pw_properties_free(d->playback_props);
49
- free(d->filename);
50
+ pw_properties_free(d->global_props);
51
return 0;
52
}
53
54
55
{
56
struct module_pipesrc_data * const d = module->user_data;
57
struct pw_properties * const props = module->props;
58
- struct pw_properties *playback_props = NULL;
59
+ struct pw_properties *global_props = NULL, *playback_props = NULL;
60
struct spa_audio_info_raw info = { 0 };
61
const char *str;
62
- char *filename = NULL;
63
int res = 0;
64
65
PW_LOG_TOPIC_INIT(mod_topic);
66
67
+ global_props = pw_properties_new(NULL, NULL);
68
playback_props = pw_properties_new(NULL, NULL);
69
- if (!playback_props) {
70
+ if (!global_props || !playback_props) {
71
res = -errno;
72
goto out;
73
}
74
75
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
76
+ pw_properties_set(global_props, "tunnel.mode", "source");
77
+
78
+ info.format = SPA_AUDIO_FORMAT_S16;
79
+ if (module_args_to_audioinfo_keys(module->impl, props,
80
+ "format", "rate", "channels", "channel_map", &info) < 0) {
81
res = -EINVAL;
82
goto out;
83
}
84
+ audioinfo_to_properties(&info, global_props);
85
86
- info.format = SPA_AUDIO_FORMAT_S16;
87
- if ((str = pw_properties_get(props, "format")) != NULL) {
88
- info.format = format_paname2id(str, strlen(str));
89
- if (info.format == SPA_AUDIO_FORMAT_UNKNOWN) {
90
- pw_log_error("invalid format '%s'", str);
91
- res = -EINVAL;
92
- goto out;
93
- }
94
- pw_properties_set(props, "format", NULL);
95
- }
96
if ((str = pw_properties_get(props, "source_name")) != NULL) {
97
pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
98
pw_properties_set(props, "source_name", NULL);
99
100
module_args_add_props(playback_props, str);
101
102
if ((str = pw_properties_get(props, "file")) != NULL) {
103
- filename = strdup(str);
104
+ pw_properties_set(global_props, "pipe.filename", str);
105
pw_properties_set(props, "file", NULL);
106
}
107
if ((str = pw_properties_get(playback_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
108
109
110
d->module = module;
111
d->playback_props = playback_props;
112
- d->info = info;
113
- d->filename = filename;
114
+ d->global_props = global_props;
115
116
return 0;
117
out:
118
+ pw_properties_free(global_props);
119
pw_properties_free(playback_props);
120
- free(filename);
121
return res;
122
}
123
124
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c
Changed
64
1
2
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
3
};
4
5
-static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
6
-{
7
- char *s, *p;
8
- uint32_t i;
9
-
10
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
11
- p = s = alloca(info->channels * 8);
12
- for (i = 0; i < info->channels; i++)
13
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
14
- channel_id2name(info->positioni));
15
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
16
-}
17
-
18
static int module_remap_sink_prepare(struct module * const module)
19
{
20
struct module_remap_sink_data * const d = module->user_data;
21
22
pw_properties_set(props, "master", NULL);
23
}
24
25
- if (module_args_to_audioinfo(module->impl, props, &capture_info) < 0) {
26
+ if (module_args_to_audioinfo_keys(module->impl, props,
27
+ NULL, NULL, "channels", "channel_map", &capture_info) < 0) {
28
res = -EINVAL;
29
goto out;
30
}
31
playback_info = capture_info;
32
-
33
- if ((str = pw_properties_get(props, "master_channel_map")) != NULL) {
34
- struct channel_map map;
35
-
36
- channel_map_parse(str, &map);
37
- if (map.channels == 0 || map.channels > SPA_AUDIO_MAX_CHANNELS) {
38
- pw_log_error("invalid channel_map '%s'", str);
39
- res = -EINVAL;
40
- goto out;
41
- }
42
- channel_map_to_positions(&map, playback_info.position);
43
- pw_properties_set(props, "master_channel_map", NULL);
44
+ if (module_args_to_audioinfo_keys(module->impl, props,
45
+ NULL, NULL, NULL, "master_channel_map", &playback_info) < 0) {
46
+ res = -EINVAL;
47
+ goto out;
48
}
49
- position_to_props(&capture_info, capture_props);
50
- position_to_props(&playback_info, playback_props);
51
+ audioinfo_to_properties(&capture_info, capture_props);
52
+ audioinfo_to_properties(&playback_info, playback_props);
53
54
if ((str = pw_properties_get(props, "remix")) != NULL) {
55
/* Note that the boolean is inverted */
56
57
out:
58
pw_properties_free(playback_props);
59
pw_properties_free(capture_props);
60
-
61
return res;
62
}
63
64
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c
Changed
64
1
2
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
3
};
4
5
-static void position_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
6
-{
7
- char *s, *p;
8
- uint32_t i;
9
-
10
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
11
- p = s = alloca(info->channels * 8);
12
- for (i = 0; i < info->channels; i++)
13
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
14
- channel_id2name(info->positioni));
15
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
16
-}
17
-
18
static int module_remap_source_prepare(struct module * const module)
19
{
20
struct module_remap_source_data * const d = module->user_data;
21
22
pw_properties_set(props, "master", NULL);
23
}
24
25
- if (module_args_to_audioinfo(module->impl, props, &playback_info) < 0) {
26
+ if (module_args_to_audioinfo_keys(module->impl, props,
27
+ NULL, NULL, "channels", "channel_map", &playback_info) < 0) {
28
res = -EINVAL;
29
goto out;
30
}
31
capture_info = playback_info;
32
-
33
- if ((str = pw_properties_get(props, "master_channel_map")) != NULL) {
34
- struct channel_map map;
35
-
36
- channel_map_parse(str, &map);
37
- if (map.channels == 0 || map.channels > SPA_AUDIO_MAX_CHANNELS) {
38
- pw_log_error("invalid channel_map '%s'", str);
39
- res = -EINVAL;
40
- goto out;
41
- }
42
- channel_map_to_positions(&map, capture_info.position);
43
- pw_properties_set(props, "master_channel_map", NULL);
44
+ if (module_args_to_audioinfo_keys(module->impl, props,
45
+ NULL, NULL, NULL, "master_channel_map", &capture_info) < 0) {
46
+ res = -EINVAL;
47
+ goto out;
48
}
49
- position_to_props(&playback_info, playback_props);
50
- position_to_props(&capture_info, capture_props);
51
+ audioinfo_to_properties(&playback_info, playback_props);
52
+ audioinfo_to_properties(&capture_info, capture_props);
53
54
if ((str = pw_properties_get(props, "remix")) != NULL) {
55
/* Note that the boolean is inverted */
56
57
out:
58
pw_properties_free(playback_props);
59
pw_properties_free(capture_props);
60
-
61
return res;
62
}
63
64
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-send.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-send.c
Changed
71
1
2
struct pw_properties *stream_props;
3
struct pw_properties *global_props;
4
struct pw_properties *sap_props;
5
-
6
- struct spa_audio_info_raw info;
7
};
8
9
static void module_destroy(void *data)
10
11
FILE *f;
12
char *args;
13
size_t size;
14
- uint32_t i;
15
16
pw_properties_setf(data->stream_props, "pulse.module.id",
17
"%u", module->index);
18
19
20
fprintf(f, "{");
21
pw_properties_serialize_dict(f, &data->global_props->dict, 0);
22
- if (data->info.format != 0)
23
- fprintf(f, " \"audio.format\": \"%s\"", format_id2name(data->info.format));
24
- if (data->info.rate != 0)
25
- fprintf(f, " \"audio.rate\": %u,", data->info.rate);
26
- if (data->info.channels != 0) {
27
- fprintf(f, " \"audio.channels\": %u,", data->info.channels);
28
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
29
- fprintf(f, " \"audio.position\": ");
30
- for (i = 0; i < data->info.channels; i++)
31
- fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
32
- channel_id2name(data->info.positioni));
33
- fprintf(f, " ,");
34
- }
35
- }
36
fprintf(f, " stream.props = {");
37
pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
38
fprintf(f, " } }");
39
40
pw_properties_set(stream_props, PW_KEY_TARGET_OBJECT, str);
41
}
42
}
43
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
44
+
45
+ if (module_args_to_audioinfo_keys(module->impl, props,
46
+ "format", "rate", "channels", "channel_map", &info) < 0) {
47
res = -EINVAL;
48
goto out;
49
}
50
- info.format = 0;
51
- if ((str = pw_properties_get(props, "format")) != NULL) {
52
- if ((info.format = format_paname2id(str, strlen(str))) ==
53
- SPA_AUDIO_FORMAT_UNKNOWN) {
54
- pw_log_error("unknown format %s", str);
55
- res = -EINVAL;
56
- goto out;
57
- }
58
- }
59
+ audioinfo_to_properties(&info, global_props);
60
61
pw_properties_set(global_props, "sess.media", "audio");
62
if ((str = pw_properties_get(props, "enable_opus")) != NULL) {
63
64
d->stream_props = stream_props;
65
d->global_props = global_props;
66
d->sap_props = sap_props;
67
- d->info = info;
68
69
return 0;
70
out:
71
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c
Changed
47
1
2
struct impl *impl = module->impl;
3
char *args;
4
size_t size;
5
- uint32_t i;
6
FILE *f;
7
8
if ((f = open_memstream(&args, &size)) == NULL)
9
return -errno;
10
11
fprintf(f, "{");
12
- if (data->info.rate != 0)
13
- fprintf(f, " \"audio.rate\": %u,", data->info.rate);
14
- if (data->info.channels != 0) {
15
- fprintf(f, " \"audio.channels\": %u,", data->info.channels);
16
- if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
17
- fprintf(f, " \"audio.position\": ");
18
- for (i = 0; i < data->info.channels; i++)
19
- fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
20
- channel_id2name(data->info.positioni));
21
- fprintf(f, " ,");
22
- }
23
- }
24
pw_properties_serialize_dict(f, &data->module_props->dict, 0);
25
fprintf(f, "}");
26
fclose(f);
27
28
goto out;
29
}
30
31
- if ((str = pw_properties_get(props, "format")) != NULL) {
32
- pw_properties_set(module_props, "audio.format",
33
- format_id2name(format_paname2id(str, strlen(str))));
34
- pw_properties_set(props, "format", NULL);
35
- }
36
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
37
+ if (module_args_to_audioinfo_keys(module->impl, props,
38
+ "format", "rate", "channels", "channel_map", &info) < 0) {
39
res = -EINVAL;
40
goto out;
41
}
42
+ audioinfo_to_properties(&info, module_props);
43
+
44
if ((str = pw_properties_get(props, "playback")) != NULL) {
45
pw_properties_set(module_props, "playback", str);
46
pw_properties_set(props, "playback", NULL);
47
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c
Changed
121
1
2
struct pw_impl_module *mod;
3
struct spa_hook mod_listener;
4
5
- uint32_t latency_msec;
6
-
7
struct pw_properties *stream_props;
8
};
9
10
11
FILE *f;
12
char *args;
13
size_t size;
14
- const char *server;
15
-
16
- server = pw_properties_get(module->props, "server");
17
18
pw_properties_setf(data->stream_props, "pulse.module.id",
19
"%u", module->index);
20
21
22
fprintf(f, "{");
23
pw_properties_serialize_dict(f, &module->props->dict, 0);
24
- fprintf(f, " pulse.server.address = \"%s\" ", server);
25
- fprintf(f, " tunnel.mode = sink ");
26
- if (data->latency_msec > 0)
27
- fprintf(f, " pulse.latency = %u ", data->latency_msec);
28
fprintf(f, " stream.props = {");
29
pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
30
fprintf(f, " } }");
31
32
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
33
};
34
35
-static void audio_info_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
36
-{
37
- char *s, *p;
38
- uint32_t i;
39
-
40
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
41
- p = s = alloca(info->channels * 8);
42
- for (i = 0; i < info->channels; i++)
43
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
44
- channel_id2name(info->positioni));
45
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
46
-}
47
-
48
static int module_tunnel_sink_prepare(struct module * const module)
49
{
50
struct module_tunnel_sink_data * const d = module->user_data;
51
52
goto out;
53
}
54
55
+ pw_properties_set(props, "tunnel.mode", "sink");
56
+
57
remote_sink_name = pw_properties_get(props, "sink");
58
if (remote_sink_name)
59
pw_properties_set(props, PW_KEY_TARGET_OBJECT, remote_sink_name);
60
61
pw_log_error("no server given");
62
res = -EINVAL;
63
goto out;
64
+ } else {
65
+ pw_properties_set(props, "pulse.server.address", server);
66
}
67
68
pw_properties_setf(stream_props, PW_KEY_NODE_DESCRIPTION,
69
- _("Tunnel to %s/%s"), server,
70
+ _("Tunnel to %s%s%s"), server,
71
+ remote_sink_name ? "/" : "",
72
remote_sink_name ? remote_sink_name : "");
73
+
74
pw_properties_set(stream_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
75
76
if ((str = pw_properties_get(props, "sink_name")) != NULL) {
77
78
pw_properties_setf(stream_props, PW_KEY_NODE_NAME,
79
"tunnel-sink.%s", server);
80
}
81
+ pw_properties_set(props, "server", NULL);
82
83
if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
84
module_args_add_props(stream_props, str);
85
pw_properties_set(props, "sink_properties", NULL);
86
}
87
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
88
+ if (module_args_to_audioinfo_keys(module->impl, props,
89
+ "format", "rate", "channels", "channel_map", &info) < 0) {
90
res = -EINVAL;
91
goto out;
92
}
93
+ audioinfo_to_properties(&info, stream_props);
94
95
- audio_info_to_props(&info, stream_props);
96
- if ((str = pw_properties_get(props, "format")) != NULL) {
97
- uint32_t id = format_paname2id(str, strlen(str));
98
- if (id == SPA_AUDIO_FORMAT_UNKNOWN) {
99
- res = -EINVAL;
100
- goto out;
101
- }
102
-
103
- pw_properties_set(stream_props, PW_KEY_AUDIO_FORMAT, format_id2name(id));
104
+ if ((str = pw_properties_get(props, "latency_msec")) != NULL) {
105
+ pw_properties_set(props, "pulse.latency", str);
106
+ pw_properties_set(props, "latency_msec", NULL);
107
}
108
109
d->module = module;
110
d->stream_props = stream_props;
111
112
- pw_properties_fetch_uint32(props, "latency_msec", &d->latency_msec);
113
-
114
return 0;
115
out:
116
pw_properties_free(stream_props);
117
-
118
return res;
119
}
120
121
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c
Changed
107
1
2
struct pw_impl_module *mod;
3
struct spa_hook mod_listener;
4
5
- uint32_t latency_msec;
6
-
7
struct pw_properties *stream_props;
8
};
9
10
11
FILE *f;
12
char *args;
13
size_t size;
14
- const char *server;
15
16
pw_properties_setf(data->stream_props, "pulse.module.id",
17
"%u", module->index);
18
19
- server = pw_properties_get(module->props, "server");
20
-
21
if ((f = open_memstream(&args, &size)) == NULL)
22
return -errno;
23
24
fprintf(f, "{");
25
pw_properties_serialize_dict(f, &module->props->dict, 0);
26
- fprintf(f, " pulse.server.address = \"%s\" ", server);
27
- fprintf(f, " tunnel.mode = source ");
28
- if (data->latency_msec > 0)
29
- fprintf(f, " pulse.latency = %u ", data->latency_msec);
30
fprintf(f, " stream.props = {");
31
pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
32
fprintf(f, " } }");
33
34
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
35
};
36
37
-static void audio_info_to_props(struct spa_audio_info_raw *info, struct pw_properties *props)
38
-{
39
- char *s, *p;
40
- uint32_t i;
41
-
42
- pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
43
- p = s = alloca(info->channels * 8);
44
- for (i = 0; i < info->channels; i++)
45
- p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
46
- channel_id2name(info->positioni));
47
- pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
48
-}
49
-
50
static int module_tunnel_source_prepare(struct module * const module)
51
{
52
struct module_tunnel_source_data * const d = module->user_data;
53
54
goto out;
55
}
56
57
+ pw_properties_set(props, "tunnel.mode", "source");
58
+
59
remote_source_name = pw_properties_get(props, "source");
60
if (remote_source_name)
61
pw_properties_set(props, PW_KEY_TARGET_OBJECT, remote_source_name);
62
63
pw_log_error("no server given");
64
res = -EINVAL;
65
goto out;
66
+ } else {
67
+ pw_properties_set(props, "pulse.server.address", server);
68
}
69
70
pw_properties_setf(stream_props, PW_KEY_NODE_DESCRIPTION,
71
- _("Tunnel to %s/%s"), server,
72
+ _("Tunnel to %s%s%s"), server,
73
+ remote_source_name ? "/" : "",
74
remote_source_name ? remote_source_name : "");
75
pw_properties_set(stream_props, PW_KEY_MEDIA_CLASS, "Audio/Source");
76
77
78
module_args_add_props(stream_props, str);
79
pw_properties_set(props, "source_properties", NULL);
80
}
81
- if (module_args_to_audioinfo(module->impl, props, &info) < 0) {
82
+ if (module_args_to_audioinfo_keys(module->impl, props,
83
+ "format", "rate", "channels", "channel_map", &info) < 0) {
84
res = -EINVAL;
85
goto out;
86
}
87
+ audioinfo_to_properties(&info, stream_props);
88
89
- audio_info_to_props(&info, stream_props);
90
+ if ((str = pw_properties_get(props, "latency_msec")) != NULL) {
91
+ pw_properties_set(props, "pulse.latency", str);
92
+ pw_properties_set(props, "latency_msec", NULL);
93
+ }
94
95
d->module = module;
96
d->stream_props = stream_props;
97
98
- pw_properties_fetch_uint32(props, "latency_msec", &d->latency_msec);
99
-
100
return 0;
101
out:
102
pw_properties_free(stream_props);
103
-
104
return res;
105
}
106
107
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/operation.h -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/operation.h
Changed
13
1
2
void operation_free(struct operation *o);
3
void operation_complete(struct operation *o);
4
5
+static inline void operation_free_by_tag(struct client *client, uint32_t tag)
6
+{
7
+ struct operation *o = operation_find(client, tag);
8
+ if (o)
9
+ operation_free(o);
10
+}
11
+
12
#endif /* PULSER_SERVER_OPERATION_H */
13
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/pending-sample.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/pending-sample.c
Changed
137
1
2
#include <pipewire/work-queue.h>
3
4
#include "client.h"
5
+#include "collect.h"
6
+#include "commands.h"
7
#include "internal.h"
8
#include "log.h"
9
+#include "message.h"
10
#include "operation.h"
11
#include "pending-sample.h"
12
+#include "reply.h"
13
#include "sample-play.h"
14
15
+static void do_pending_sample_finish(void *obj, void *data, int res, uint32_t id)
16
+{
17
+ struct pending_sample *ps = obj;
18
+ struct client *client = ps->client;
19
+
20
+ pending_sample_free(ps);
21
+ client_unref(client);
22
+}
23
+
24
+static void schedule_maybe_finish(struct pending_sample *ps)
25
+{
26
+ if (!ps->done || !ps->replied)
27
+ return;
28
+
29
+ pw_work_queue_add(ps->client->impl->work_queue, ps, 0,
30
+ do_pending_sample_finish, NULL);
31
+}
32
+
33
+static void sample_play_ready_reply(void *data, struct client *client, uint32_t tag)
34
+{
35
+ struct pending_sample *ps = data;
36
+ uint32_t index = id_to_index(client->manager, ps->play->id);
37
+
38
+ pw_log_info("%s PLAY_SAMPLE tag:%u index:%u",
39
+ client->name, ps->tag, index);
40
+
41
+ if (!ps->replied) {
42
+ struct message *reply = reply_new(client, ps->tag);
43
+ if (client->version >= 13)
44
+ message_put(reply,
45
+ TAG_U32, index,
46
+ TAG_INVALID);
47
+
48
+ client_queue_message(client, reply);
49
+ ps->replied = true;
50
+ }
51
+
52
+ schedule_maybe_finish(ps);
53
+}
54
+
55
+static void on_sample_play_ready(void *data, uint32_t id)
56
+{
57
+ struct pending_sample *ps = data;
58
+ struct client *client = ps->client;
59
+
60
+ if (!ps->replied)
61
+ operation_new_cb(client, ps->tag, sample_play_ready_reply, ps);
62
+}
63
+
64
+static void on_sample_play_done(void *data, int res)
65
+{
66
+ struct pending_sample *ps = data;
67
+ struct client *client = ps->client;
68
+
69
+ if (!ps->replied && res < 0) {
70
+ reply_error(client, COMMAND_PLAY_SAMPLE, ps->tag, res);
71
+ ps->replied = true;
72
+ }
73
+
74
+ pw_log_info("%s PLAY_SAMPLE done tag:%u result:%d", client->name, ps->tag, res);
75
+
76
+ ps->done = true;
77
+ schedule_maybe_finish(ps);
78
+}
79
+
80
+static const struct sample_play_events sample_play_events = {
81
+ VERSION_SAMPLE_PLAY_EVENTS,
82
+ .ready = on_sample_play_ready,
83
+ .done = on_sample_play_done,
84
+};
85
+
86
+static void on_client_disconnect(void *data)
87
+{
88
+ struct pending_sample *ps = data;
89
+
90
+ ps->replied = true;
91
+ operation_free_by_tag(ps->client, ps->tag);
92
+
93
+ schedule_maybe_finish(ps);
94
+}
95
+
96
+static const struct client_events client_events = {
97
+ VERSION_CLIENT_EVENTS,
98
+ .disconnect = on_client_disconnect,
99
+};
100
+
101
+int pending_sample_new(struct client *client, struct sample *sample, struct pw_properties *props, uint32_t tag)
102
+{
103
+ struct pending_sample *ps;
104
+ struct sample_play *p = sample_play_new(client->core, sample, props, sizeof(*ps));
105
+ if (!p)
106
+ return -errno;
107
+
108
+ ps = p->user_data;
109
+ ps->client = client;
110
+ ps->play = p;
111
+ ps->tag = tag;
112
+ sample_play_add_listener(p, &ps->listener, &sample_play_events, ps);
113
+ client_add_listener(client, &ps->client_listener, &client_events, ps);
114
+ spa_list_append(&client->pending_samples, &ps->link);
115
+ client->ref++;
116
+
117
+ return 0;
118
+}
119
+
120
void pending_sample_free(struct pending_sample *ps)
121
{
122
struct client * const client = ps->client;
123
struct impl * const impl = client->impl;
124
- struct operation *o;
125
126
spa_list_remove(&ps->link);
127
spa_hook_remove(&ps->listener);
128
+ spa_hook_remove(&ps->client_listener);
129
pw_work_queue_cancel(impl->work_queue, ps, SPA_ID_INVALID);
130
131
- if ((o = operation_find(client, ps->tag)) != NULL)
132
- operation_free(o);
133
+ operation_free_by_tag(client, ps->tag);
134
135
sample_play_destroy(ps->play);
136
}
137
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/pending-sample.h -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/pending-sample.h
Changed
25
1
2
#include <spa/utils/hook.h>
3
4
struct client;
5
+struct pw_properties;
6
+struct sample;
7
struct sample_play;
8
9
struct pending_sample {
10
11
struct client *client;
12
struct sample_play *play;
13
struct spa_hook listener;
14
+ struct spa_hook client_listener;
15
uint32_t tag;
16
- unsigned ready:1;
17
+ unsigned replied:1;
18
unsigned done:1;
19
};
20
21
+int pending_sample_new(struct client *client, struct sample *sample, struct pw_properties *props, uint32_t tag);
22
void pending_sample_free(struct pending_sample *ps);
23
24
#endif /* PULSE_SERVER_PENDING_SAMPLE_H */
25
pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
126
1
2
#include "quirks.h"
3
#include "reply.h"
4
#include "sample.h"
5
-#include "sample-play.h"
6
#include "server.h"
7
#include "stream.h"
8
#include "utils.h"
9
10
return o;
11
}
12
13
-static void sample_play_finish(struct pending_sample *ps)
14
-{
15
- struct client *client = ps->client;
16
- pending_sample_free(ps);
17
- client_unref(client);
18
-}
19
-
20
-static void sample_play_ready_reply(void *data, struct client *client, uint32_t tag)
21
-{
22
- struct pending_sample *ps = data;
23
- struct message *reply;
24
- uint32_t index = id_to_index(client->manager, ps->play->id);
25
-
26
- pw_log_info("%s PLAY_SAMPLE tag:%u index:%u",
27
- client->name, ps->tag, index);
28
-
29
- ps->ready = true;
30
-
31
- reply = reply_new(client, ps->tag);
32
- if (client->version >= 13)
33
- message_put(reply,
34
- TAG_U32, index,
35
- TAG_INVALID);
36
-
37
- client_queue_message(client, reply);
38
-
39
- if (ps->done)
40
- sample_play_finish(ps);
41
-}
42
-
43
-static void sample_play_ready(void *data, uint32_t id)
44
-{
45
- struct pending_sample *ps = data;
46
- struct client *client = ps->client;
47
- operation_new_cb(client, ps->tag, sample_play_ready_reply, ps);
48
-}
49
-
50
-static void on_sample_done(void *obj, void *data, int res, uint32_t id)
51
-{
52
- struct pending_sample *ps = obj;
53
- ps->done = true;
54
- if (ps->ready)
55
- sample_play_finish(ps);
56
-}
57
-
58
-static void sample_play_done(void *data, int res)
59
-{
60
- struct pending_sample *ps = data;
61
- struct client *client = ps->client;
62
- struct impl *impl = client->impl;
63
-
64
- if (res < 0)
65
- reply_error(client, COMMAND_PLAY_SAMPLE, ps->tag, res);
66
- else
67
- pw_log_info("%s PLAY_SAMPLE done tag:%u", client->name, ps->tag);
68
-
69
- pw_work_queue_add(impl->work_queue, ps, 0,
70
- on_sample_done, client);
71
-}
72
-
73
-static const struct sample_play_events sample_play_events = {
74
- VERSION_SAMPLE_PLAY_EVENTS,
75
- .ready = sample_play_ready,
76
- .done = sample_play_done,
77
-};
78
-
79
static int do_play_sample(struct client *client, uint32_t command, uint32_t tag, struct message *m)
80
{
81
struct impl *impl = client->impl;
82
uint32_t sink_index, volume;
83
struct sample *sample;
84
- struct sample_play *play;
85
const char *sink_name, *name;
86
struct pw_properties *props = NULL;
87
- struct pending_sample *ps;
88
struct pw_manager_object *o;
89
int res;
90
91
92
93
pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%"PRIu64, o->serial);
94
95
- play = sample_play_new(client->core, sample, props, sizeof(struct pending_sample));
96
- props = NULL;
97
- if (play == NULL)
98
- goto error_errno;
99
-
100
- ps = play->user_data;
101
- ps->client = client;
102
- ps->play = play;
103
- ps->tag = tag;
104
- sample_play_add_listener(play, &ps->listener, &sample_play_events, ps);
105
- spa_list_append(&client->pending_samples, &ps->link);
106
- client->ref++;
107
-
108
- return 0;
109
+ return pending_sample_new(client, sample, props, tag);
110
111
error_errno:
112
res = -errno;
113
114
&context_events, impl);
115
116
#ifdef HAVE_DBUS
117
- impl->dbus_name = dbus_request_name(context, "org.pulseaudio.Server");
118
+ str = pw_properties_get(props, "server.dbus-name");
119
+ if (str == NULL)
120
+ str = "org.pulseaudio.Server";
121
+ if (strlen(str) > 0)
122
+ impl->dbus_name = dbus_request_name(context, str);
123
#endif
124
cmd_run(impl);
125
126
pipewire-0.3.70.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.71.tar.gz/src/modules/module-pulse-tunnel.c
Changed
61
1
2
switch (state) {
3
case PW_STREAM_STATE_ERROR:
4
case PW_STREAM_STATE_UNCONNECTED:
5
- pw_impl_module_schedule_destroy(impl->module);
6
+ if (impl->module)
7
+ pw_impl_module_schedule_destroy(impl->module);
8
break;
9
case PW_STREAM_STATE_PAUSED:
10
cork_stream(impl, true);
11
12
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
13
{
14
struct impl *impl = user_data;
15
- pw_impl_module_schedule_destroy(impl->module);
16
+ if (impl->module)
17
+ pw_impl_module_schedule_destroy(impl->module);
18
return 0;
19
}
20
21
22
pw_log_error("error id:%u seq:%d res:%d (%s): %s",
23
id, seq, res, spa_strerror(res), message);
24
25
- if (id == PW_ID_CORE && res == -EPIPE)
26
- pw_impl_module_schedule_destroy(impl->module);
27
+ if (id == PW_ID_CORE && res == -EPIPE) {
28
+ if (impl->module)
29
+ pw_impl_module_schedule_destroy(impl->module);
30
+ }
31
}
32
33
static const struct pw_core_events core_events = {
34
35
struct impl *impl = d;
36
spa_hook_remove(&impl->core_listener);
37
impl->core = NULL;
38
- pw_impl_module_schedule_destroy(impl->module);
39
+ if (impl->module)
40
+ pw_impl_module_schedule_destroy(impl->module);
41
}
42
43
static const struct pw_proxy_events core_proxy_events = {
44
45
if (impl->core && impl->do_disconnect)
46
pw_core_disconnect(impl->core);
47
48
+ pw_loop_invoke(impl->main_loop, NULL, 0, NULL, 0, false, impl);
49
+
50
pw_properties_free(impl->stream_props);
51
pw_properties_free(impl->props);
52
53
54
{
55
struct impl *impl = data;
56
spa_hook_remove(&impl->module_listener);
57
+ impl->module = NULL;
58
impl_destroy(impl);
59
}
60
61
pipewire-0.3.70.tar.gz/src/modules/module-raop-discover.c -> pipewire-0.3.71.tar.gz/src/modules/module-raop-discover.c
Changed
131
1
2
};
3
4
struct tunnel_info {
5
- AvahiIfIndex interface;
6
- AvahiProtocol protocol;
7
const char *name;
8
const char *host_name;
9
- const char *type;
10
- const char *domain;
11
+ const char *ip;
12
+ const char *port;
13
};
14
15
#define TUNNEL_INFO(...) ((struct tunnel_info){ __VA_ARGS__ })
16
17
if (t == NULL)
18
return NULL;
19
20
- t->info.interface = info->interface;
21
- t->info.protocol = info->protocol;
22
t->info.name = strdup(info->name);
23
t->info.host_name = strdup(info->host_name);
24
- t->info.type = strdup(info->type);
25
- t->info.domain = strdup(info->domain);
26
+ t->info.ip = strdup(info->ip);
27
+ t->info.port = strdup(info->port);
28
spa_list_append(&impl->tunnel_list, &t->link);
29
30
return t;
31
32
{
33
struct tunnel *t;
34
spa_list_for_each(t, &impl->tunnel_list, link) {
35
- if (t->info.interface == info->interface &&
36
- t->info.protocol == info->protocol &&
37
- spa_streq(t->info.name, info->name) &&
38
- spa_streq(t->info.type, info->type) &&
39
- spa_streq(t->info.domain, info->domain))
40
+ if (spa_streq(t->info.name, info->name))
41
return t;
42
}
43
return NULL;
44
45
46
free((char *) t->info.name);
47
free((char *) t->info.host_name);
48
- free((char *) t->info.type);
49
- free((char *) t->info.domain);
50
+ free((char *) t->info.ip);
51
+ free((char *) t->info.port);
52
53
free(t);
54
}
55
56
{
57
struct impl *impl = userdata;
58
struct tunnel_info tinfo;
59
- const char *str;
60
+ const char *str, *port_str;
61
AvahiStringList *l;
62
struct pw_properties *props = NULL;
63
char atAVAHI_ADDRESS_STR_MAX;
64
- int ipv;
65
66
if (event != AVAHI_RESOLVER_FOUND) {
67
pw_log_error("Resolving of '%s' failed: %s", name,
68
avahi_strerror(avahi_client_errno(impl->client)));
69
goto done;
70
}
71
- tinfo = TUNNEL_INFO(.interface = interface,
72
- .protocol = protocol,
73
- .host_name = host_name,
74
- .name = name,
75
- .type = type,
76
- .domain = domain);
77
+
78
+ avahi_address_snprint(at, sizeof(at), a);
79
80
props = pw_properties_new(NULL, NULL);
81
if (props == NULL) {
82
83
goto done;
84
}
85
86
- avahi_address_snprint(at, sizeof(at), a);
87
- ipv = protocol == AVAHI_PROTO_INET ? 4 : 6;
88
-
89
pw_properties_setf(props, "raop.ip", "%s", at);
90
- pw_properties_setf(props, "raop.ip.version", "%d", ipv);
91
pw_properties_setf(props, "raop.port", "%u", port);
92
pw_properties_setf(props, "raop.name", "%s", name);
93
pw_properties_setf(props, "raop.hostname", "%s", host_name);
94
95
avahi_free(value);
96
}
97
98
+ port_str = pw_properties_get(props, "raop.port");
99
+
100
+ tinfo = TUNNEL_INFO(.name = name,
101
+ .host_name = host_name,
102
+ .ip = at,
103
+ .port = port_str);
104
+
105
if ((str = pw_properties_get(impl->properties, "stream.rules")) == NULL)
106
str = DEFAULT_CREATE_RULES;
107
if (str != NULL) {
108
109
if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
110
return;
111
112
- info = TUNNEL_INFO(.interface = interface,
113
- .protocol = protocol,
114
- .name = name,
115
- .type = type,
116
- .domain = domain);
117
+ info = TUNNEL_INFO(.name = name);
118
119
t = find_tunnel(impl, &info);
120
121
switch (event) {
122
case AVAHI_BROWSER_NEW:
123
- if (t != NULL)
124
+ if (t != NULL) {
125
+ pw_log_debug("found duplicate mdns entry - skipping tunnel creation");
126
return;
127
+ }
128
if (!(avahi_service_resolver_new(impl->client,
129
interface, protocol,
130
name, type, domain,
131
pipewire-0.3.70.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-raop-sink.c
Changed
120
1
2
return res;
3
}
4
5
+static int rtsp_send_volume(struct impl *impl)
6
+{
7
+ if (!impl->recording)
8
+ return 0;
9
+
10
+ char header128, volstr64;
11
+ snprintf(header, sizeof(header), "volume: %s\r\n",
12
+ spa_dtoa(volstr, sizeof(volstr), impl->volume));
13
+ return rtsp_send(impl, "SET_PARAMETER", "text/parameters", header, NULL);
14
+}
15
+
16
static int rtsp_record_reply(void *data, int status, const struct spa_dict *headers)
17
{
18
struct impl *impl = data;
19
20
impl->sync_period = impl->info.rate / (impl->block_size / impl->frame_size);
21
impl->recording = true;
22
23
+ rtsp_send_volume(impl);
24
+
25
snprintf(progress, sizeof(progress), "progress: %s/%s/%s\r\n", "0", "0", "0");
26
return rtsp_send(impl, "SET_PARAMETER", "text/parameters", progress, NULL);
27
}
28
29
uint32_t i, n_vols;
30
float volsSPA_AUDIO_MAX_CHANNELS, volume;
31
float soft_volsSPA_AUDIO_MAX_CHANNELS;
32
- char header128, volstr64;
33
34
if ((n_vols = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
35
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
36
37
volume = SPA_CLAMPF(20.0 * log10(volume), VOLUME_MIN, VOLUME_MAX);
38
impl->volume = volume;
39
40
- snprintf(header, sizeof(header), "volume: %s\r\n",
41
- spa_dtoa(volstr, sizeof(volstr), volume));
42
- rtsp_send(impl, "SET_PARAMETER", "text/parameters", header, NULL);
43
+ rtsp_send_volume(impl);
44
}
45
+
46
spa_pod_builder_prop(&b, SPA_PROP_softVolumes, 0);
47
spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
48
n_vols, soft_vols);
49
50
case SPA_PARAM_Props:
51
if (param != NULL)
52
stream_props_changed(impl, id, param);
53
+ break;
54
default:
55
break;
56
}
57
58
struct pw_context *context = pw_impl_module_get_context(module);
59
struct pw_properties *props = NULL;
60
struct impl *impl;
61
- const char *str, *name, *hostname, *ipv;
62
+ const char *str, *name, *hostname, *ip, *port;
63
int res;
64
65
PW_LOG_TOPIC_INIT(mod_topic);
66
67
impl->context = context;
68
impl->loop = pw_context_get_main_loop(context);
69
70
+ ip = pw_properties_get(props, "raop.ip");
71
+ port = pw_properties_get(props, "raop.port");
72
+ if (ip == NULL || port == NULL) {
73
+ pw_log_error("Missing raop.ip or raop.port");
74
+ res = -EINVAL;
75
+ goto error;
76
+ }
77
+
78
if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
79
pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
80
81
if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
82
pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
83
84
+ if (pw_properties_get(props, PW_KEY_DEVICE_ICON_NAME) == NULL)
85
+ pw_properties_set(props, PW_KEY_DEVICE_ICON_NAME, "audio-speakers");
86
+
87
if ((name = pw_properties_get(props, "raop.name")) == NULL)
88
name = "RAOP";
89
90
91
if (strlen(str) > 0)
92
name = str;
93
}
94
- if ((ipv = pw_properties_get(props, "raop.ip.version")) == NULL)
95
- ipv = "4";
96
if ((hostname = pw_properties_get(props, "raop.hostname")) == NULL)
97
hostname = name;
98
99
+ if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
100
+ pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.%s",
101
+ hostname, ip, port);
102
if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
103
pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
104
- "%s (IPv%s)", name, ipv);
105
- if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
106
- pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.ipv%s",
107
- hostname, ipv);
108
+ "%s", name);
109
if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL)
110
pw_properties_set(props, PW_KEY_NODE_LATENCY, "352/44100");
111
112
113
copy_props(impl, props, PW_KEY_AUDIO_RATE);
114
copy_props(impl, props, PW_KEY_AUDIO_CHANNELS);
115
copy_props(impl, props, SPA_KEY_AUDIO_POSITION);
116
+ copy_props(impl, props, PW_KEY_DEVICE_ICON_NAME);
117
copy_props(impl, props, PW_KEY_NODE_NAME);
118
copy_props(impl, props, PW_KEY_NODE_DESCRIPTION);
119
copy_props(impl, props, PW_KEY_NODE_GROUP);
120
pipewire-0.3.70.tar.gz/src/modules/module-roc-source.c -> pipewire-0.3.71.tar.gz/src/modules/module-roc-source.c
Changed
10
1
2
* See API reference:
3
* https://roc-streaming.org/toolkit/docs/api/reference.html
4
*/
5
- receiver_config.target_latency = data->sess_latency_msec * 1000000;
6
+ receiver_config.target_latency = (unsigned long long)data->sess_latency_msec * 1000000ULL;
7
8
res = roc_receiver_open(data->context, &receiver_config, &data->receiver);
9
if (res) {
10
pipewire-0.3.70.tar.gz/src/modules/module-rt.c -> pipewire-0.3.71.tar.gz/src/modules/module-rt.c
Changed
97
1
2
#define PW_SCHED_RESET_ON_FORK 0
3
#endif
4
5
-#define IS_VALID_NICE_LEVEL(l) ((l)>=-20 && (l)<=19)
6
+#define MIN_NICE_LEVEL -20
7
+#define MAX_NICE_LEVEL 19
8
+#define IS_VALID_NICE_LEVEL(l) ((l)>=MIN_NICE_LEVEL && (l)<=MAX_NICE_LEVEL)
9
10
#define DEFAULT_NICE_LEVEL 20
11
#define DEFAULT_RT_PRIO_MIN 11
12
13
bool pw_rtkit_check_xdg_portal(struct pw_rtkit_bus *system_bus)
14
{
15
if (!dbus_bus_name_has_owner(system_bus->bus, XDG_PORTAL_SERVICE_NAME, NULL)) {
16
- pw_log_warn("Can't find %s. Is xdg-desktop-portal running?", XDG_PORTAL_SERVICE_NAME);
17
+ pw_log_info("Can't find %s. Is xdg-desktop-portal running?", XDG_PORTAL_SERVICE_NAME);
18
return false;
19
}
20
21
22
if (spa_streq(name, DBUS_ERROR_ACCESS_DENIED) ||
23
spa_streq(name, DBUS_ERROR_AUTH_FAILED))
24
return -EACCES;
25
-
26
+ if (spa_streq(name, DBUS_ERROR_IO_ERROR))
27
+ return -EIO;
28
+ if (spa_streq(name, DBUS_ERROR_NOT_SUPPORTED))
29
+ return -ENOTSUP;
30
+ if (spa_streq(name, DBUS_ERROR_INVALID_ARGS))
31
+ return -EINVAL;
32
+ if (spa_streq(name, DBUS_ERROR_TIMED_OUT))
33
+ return -ETIMEDOUT;
34
return -EIO;
35
}
36
37
38
int res = 0;
39
40
#ifdef HAVE_DBUS
41
- if (impl->use_rtkit)
42
+ if (impl->use_rtkit) {
43
+ int min_nice = nice_level;
44
+ pw_rtkit_get_min_nice_level(impl, &min_nice);
45
+ if (nice_level < min_nice) {
46
+ pw_log_info("clamped nice level %d to %d",
47
+ nice_level, min_nice);
48
+ nice_level = min_nice;
49
+ }
50
res = pw_rtkit_make_high_priority(impl, 0, nice_level);
51
+ }
52
else
53
res = sched_set_nice(nice_level);
54
#else
55
56
57
bool can_use_rtkit = false, use_rtkit = false;
58
59
+ if (!IS_VALID_NICE_LEVEL(impl->nice_level)) {
60
+ pw_log_info("invalid nice level %d (not between %d and %d). "
61
+ "nice level will not be adjusted",
62
+ impl->nice_level, MIN_NICE_LEVEL, MAX_NICE_LEVEL);
63
+ }
64
+
65
#ifdef HAVE_DBUS
66
spa_list_init(&impl->threads_list);
67
pthread_mutex_init(&impl->lock, NULL);
68
69
if (!check_realtime_privileges(impl)) {
70
if (!can_use_rtkit) {
71
res = -ENOTSUP;
72
- pw_log_warn("regular realtime scheduling not available (RTKit fallback disabled)");
73
+ pw_log_warn("regular realtime scheduling not available"
74
+ " (Portal/RTKit fallback disabled)");
75
goto error;
76
}
77
use_rtkit = true;
78
79
impl->object_path = XDG_PORTAL_OBJECT_PATH;
80
impl->interface = XDG_PORTAL_INTERFACE;
81
} else {
82
- pw_log_warn("found session bus but no portal");
83
+ pw_log_info("found session bus but no portal, trying RTKit fallback");
84
pw_rtkit_bus_free(impl->rtkit_bus);
85
impl->rtkit_bus = NULL;
86
}
87
88
impl->interface = RTKIT_INTERFACE;
89
} else {
90
res = -errno;
91
- pw_log_warn("could not get system bus: %m");
92
+ pw_log_warn("Realtime scheduling disabled: unsufficient realtime privileges, "
93
+ "Portal not found on session bus, and no system bus for RTKit: %m");
94
goto error;
95
}
96
}
97
pipewire-0.3.70.tar.gz/src/modules/module-rtp-sap.c -> pipewire-0.3.71.tar.gz/src/modules/module-rtp-sap.c
Changed
28
1
2
struct spa_source *timer;
3
4
char *ifname;
5
- bool ttl;
6
+ uint32_t ttl;
7
bool mcast_loop;
8
9
struct sockaddr_storage src_addr;
10
11
{ SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_ALAW, 1, "PCMA", "audio", "ALAW" },
12
{ SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_ULAW, 1, "PCMU", "audio", "ULAW" },
13
{ SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S16_BE, 2, "L16", "audio", "S16BE" },
14
- { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S24_BE, 3, "L24", "audio", "S16LE" },
15
+ { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S24_BE, 3, "L24", "audio", "S24BE" },
16
{ SPA_MEDIA_SUBTYPE_control, 0, 1, "rtp-midi", "midi", NULL },
17
{ SPA_MEDIA_SUBTYPE_opus, 0, 1, "opus", "opus", NULL },
18
};
19
20
if (sess->announce)
21
send_sap(impl, sess, 1);
22
spa_list_remove(&sess->link);
23
- impl->n_sessions++;
24
+ impl->n_sessions--;
25
}
26
if (sess->node && sess->node->session != NULL)
27
sess->node->session = NULL;
28
pipewire-0.3.70.tar.gz/src/modules/module-rtp-session.c -> pipewire-0.3.71.tar.gz/src/modules/module-rtp-session.c
Changed
47
1
2
.send_feedback = recv_send_feedback,
3
};
4
5
-static void free_session(struct session *sess)
6
+static int
7
+do_unlink_session(struct spa_loop *loop,
8
+ bool async, uint32_t seq, const void *data, size_t size, void *user_data)
9
{
10
+ struct session *sess = user_data;
11
spa_list_remove(&sess->link);
12
+ return 0;
13
+}
14
+
15
+static void free_session(struct session *sess)
16
+{
17
+ struct impl *impl = sess->impl;
18
+
19
+ pw_loop_invoke(impl->data_loop, do_unlink_session, 1, NULL, 0, true, sess);
20
+
21
sess->impl->n_sessions--;
22
23
if (sess->send)
24
25
impl->loop = pw_context_get_main_loop(context);
26
impl->data_loop = pw_data_loop_get_loop(pw_context_get_data_loop(context));
27
28
+ if (pw_properties_get(props, "sess.media") == NULL)
29
+ pw_properties_set(props, "sess.media", "midi");
30
+
31
if ((str = pw_properties_get(props, "stream.props")) != NULL)
32
pw_properties_update_string(stream_props, str, strlen(str));
33
34
35
impl->ttl = pw_properties_get_uint32(props, "net.ttl", DEFAULT_TTL);
36
impl->mcast_loop = pw_properties_get_bool(props, "net.loop", DEFAULT_LOOP);
37
38
- if ((str = pw_properties_get(stream_props, "sess.media")) == NULL) {
39
- str = "midi";
40
- pw_properties_set(stream_props, "sess.media", str);
41
- }
42
+ str = pw_properties_get(stream_props, "sess.media");
43
+
44
if (spa_streq(str, "audio")) {
45
struct spa_dict_item items = {
46
{ "audio.format", DEFAULT_FORMAT },
47
pipewire-0.3.70.tar.gz/src/modules/module-rtp-sink.c -> pipewire-0.3.71.tar.gz/src/modules/module-rtp-sink.c
Changed
10
1
2
3
char *ifname;
4
char *session_name;
5
- bool ttl;
6
+ uint32_t ttl;
7
bool mcast_loop;
8
uint32_t dscp;
9
10
pipewire-0.3.70.tar.gz/src/pipewire/context.c -> pipewire-0.3.71.tar.gz/src/pipewire/context.c
Changed
154
1
2
struct spa_plugin_loader plugin_loader;
3
unsigned int recalc:1;
4
unsigned int recalc_pending:1;
5
+
6
+ struct pw_data_loop *data_loop_impl;
7
};
8
9
10
11
12
static int context_set_freewheel(struct pw_context *context, bool freewheel)
13
{
14
+ struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
15
struct spa_thread *thr;
16
int res = 0;
17
18
- if ((thr = pw_data_loop_get_thread(context->data_loop_impl)) == NULL)
19
+ if ((thr = pw_data_loop_get_thread(impl->data_loop_impl)) == NULL)
20
return -EIO;
21
22
if (freewheel) {
23
24
if ((str = pw_properties_get(pr, "context.data-loop." PW_KEY_LIBRARY_NAME_SYSTEM)))
25
pw_properties_set(pr, PW_KEY_LIBRARY_NAME_SYSTEM, str);
26
27
- this->data_loop_impl = pw_data_loop_new(&pr->dict);
28
+ impl->data_loop_impl = pw_data_loop_new(&pr->dict);
29
pw_properties_free(pr);
30
- if (this->data_loop_impl == NULL) {
31
+ if (impl->data_loop_impl == NULL) {
32
res = -errno;
33
goto error_free;
34
}
35
36
goto error_free;
37
}
38
39
- this->data_loop = pw_data_loop_get_loop(this->data_loop_impl);
40
+ this->data_loop = pw_data_loop_get_loop(impl->data_loop_impl);
41
this->data_system = this->data_loop->system;
42
this->main_loop = main_loop;
43
44
45
goto error_free;
46
pw_log_info("%p: parsed %d context.exec items", this, res);
47
48
- if ((res = pw_data_loop_start(this->data_loop_impl)) < 0)
49
+ if ((res = pw_data_loop_start(impl->data_loop_impl)) < 0)
50
goto error_free;
51
52
- pw_data_loop_invoke(this->data_loop_impl,
53
+ pw_data_loop_invoke(impl->data_loop_impl,
54
do_data_loop_setup, 0, NULL, 0, false, this);
55
56
pw_settings_expose(this);
57
58
spa_list_consume(resource, &context->registry_resource_list, link)
59
pw_resource_destroy(resource);
60
61
- if (context->data_loop_impl)
62
- pw_data_loop_stop(context->data_loop_impl);
63
+ if (impl->data_loop_impl)
64
+ pw_data_loop_stop(impl->data_loop_impl);
65
66
spa_list_consume(module, &context->module_list, link)
67
pw_impl_module_destroy(module);
68
69
pw_log_debug("%p: free", context);
70
pw_context_emit_free(context);
71
72
- if (context->data_loop_impl)
73
- pw_data_loop_destroy(context->data_loop_impl);
74
+ if (impl->data_loop_impl)
75
+ pw_data_loop_destroy(impl->data_loop_impl);
76
77
if (context->pool)
78
pw_mempool_destroy(context->pool);
79
80
SPA_EXPORT
81
struct pw_data_loop *pw_context_get_data_loop(struct pw_context *context)
82
{
83
- return context->data_loop_impl;
84
+ struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
85
+ return impl->data_loop_impl;
86
}
87
88
SPA_EXPORT
89
90
91
pw_log_debug(" peer %p: '%s'", t, t->name);
92
t->runnable = true;
93
- if (!t->driver)
94
+ if (!t->driving)
95
run_nodes(context, t, nodes);
96
}
97
}
98
99
100
pw_log_debug(" peer %p: '%s'", t, t->name);
101
t->runnable = true;
102
- if (!t->driver)
103
+ if (!t->driving)
104
run_nodes(context, t, nodes);
105
}
106
}
107
108
109
pw_log_debug(" group %p: '%s'", t, t->name);
110
t->runnable = true;
111
- if (!t->driver)
112
+ if (!t->driving)
113
run_nodes(context, t, nodes);
114
}
115
}
116
117
pw_log_debug(" next node %p: '%s' runnable:%u", n, n->name, n->runnable);
118
}
119
spa_list_for_each(n, collect, sort_link)
120
- if (!n->driver && n->runnable)
121
+ if (!n->driving && n->runnable)
122
run_nodes(context, n, collect);
123
124
return 0;
125
126
driver = NULL;
127
spa_list_for_each(t, &collect, sort_link) {
128
/* is any active and want a driver */
129
- if (t->want_driver && t->active && t->runnable) {
130
+ if ((t->want_driver && t->active && t->runnable) ||
131
+ t->always_process) {
132
driver = target;
133
driver->runnable = true;
134
break;
135
136
int pw_context_set_object(struct pw_context *context, const char *type, void *value)
137
{
138
struct object_entry *entry;
139
+ struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
140
141
entry = find_object(context, type);
142
143
144
}
145
if (spa_streq(type, SPA_TYPE_INTERFACE_ThreadUtils)) {
146
context->thread_utils = value;
147
- if (context->data_loop_impl)
148
- pw_data_loop_set_thread_utils(context->data_loop_impl,
149
+ if (impl->data_loop_impl)
150
+ pw_data_loop_set_thread_utils(impl->data_loop_impl,
151
context->thread_utils);
152
}
153
return 0;
154
pipewire-0.3.70.tar.gz/src/pipewire/data-loop.c -> pipewire-0.3.71.tar.gz/src/pipewire/data-loop.c
Changed
21
1
2
{
3
struct pw_data_loop *this = user_data;
4
int res;
5
+ struct spa_callbacks *cb = &this->loop->control->iface.cb;
6
+ const struct spa_loop_control_methods *m = cb->funcs;
7
+ void *data = cb->data;
8
+ int (*iterate) (void *object, int timeout) = m->iterate;
9
10
pw_log_debug("%p: enter thread", this);
11
pw_loop_enter(this->loop);
12
13
pthread_cleanup_push(thread_cleanup, this);
14
15
while (SPA_LIKELY(this->running)) {
16
- if (SPA_UNLIKELY((res = pw_loop_iterate(this->loop, -1)) < 0)) {
17
+ if (SPA_UNLIKELY((res = iterate(data, -1)) < 0)) {
18
if (res == -EINTR)
19
continue;
20
pw_log_error("%p: iterate error %d (%s)",
21
pipewire-0.3.70.tar.gz/src/pipewire/filter.c -> pipewire-0.3.71.tar.gz/src/pipewire/filter.c
Changed
201
1
2
struct queue {
3
uint32_t idsMAX_BUFFERS;
4
struct spa_ringbuffer ring;
5
- uint64_t incount;
6
- uint64_t outcount;
7
};
8
9
struct data {
10
11
const char *path;
12
13
struct pw_context *context;
14
+ struct pw_loop *main_loop;
15
+ struct pw_loop *data_loop;
16
17
enum pw_filter_flags flags;
18
19
20
#define NODE_PropInfo 0
21
#define NODE_Props 1
22
#define NODE_ProcessLatency 2
23
-#define N_NODE_PARAMS 3
24
+#define NODE_EnumFormat 3
25
+#define NODE_Format 4
26
+#define N_NODE_PARAMS 5
27
struct spa_param_info paramsN_NODE_PARAMS;
28
29
struct spa_process_latency_info process_latency;
30
31
struct data data;
32
- uintptr_t seq;
33
struct pw_time time;
34
uint64_t base_pos;
35
uint32_t clock_id;
36
37
unsigned int disconnecting:1;
38
unsigned int disconnect_core:1;
39
unsigned int draining:1;
40
+ unsigned int drained:1;
41
unsigned int allow_mlock:1;
42
unsigned int warn_mlock:1;
43
unsigned int process_rt:1;
44
45
return NODE_Props;
46
case SPA_PARAM_ProcessLatency:
47
return NODE_ProcessLatency;
48
+ case SPA_PARAM_EnumFormat:
49
+ return NODE_EnumFormat;
50
+ case SPA_PARAM_Format:
51
+ return NODE_Format;
52
default:
53
return -1;
54
}
55
56
return -EINVAL;
57
58
SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED);
59
- queue->incount += buffer->this.size;
60
61
spa_ringbuffer_get_write_index(&queue->ring, &index);
62
queue->idsindex & MASK_BUFFERS = buffer->id;
63
64
spa_ringbuffer_read_update(&queue->ring, index + 1);
65
66
buffer = &port->buffersid;
67
- queue->outcount += buffer->this.size;
68
SPA_FLAG_CLEAR(buffer->flags, BUFFER_FLAG_QUEUED);
69
70
return buffer;
71
72
static inline void clear_queue(struct port *port, struct queue *queue)
73
{
74
spa_ringbuffer_init(&queue->ring);
75
- queue->incount = queue->outcount;
76
}
77
78
-static bool filter_set_state(struct pw_filter *filter, enum pw_filter_state state, const char *error)
79
+static bool filter_set_state(struct pw_filter *filter, enum pw_filter_state state,
80
+ int res, const char *error)
81
{
82
enum pw_filter_state old = filter->state;
83
- bool res = old != state;
84
+ bool changed = old != state;
85
86
- if (res) {
87
+ if (changed) {
88
free(filter->error);
89
filter->error = error ? strdup(error) : NULL;
90
+ filter->error_res = res;
91
92
- pw_log_debug("%p: update state from %s -> %s (%s)", filter,
93
+ pw_log_debug("%p: update state from %s -> %s: (%d) %s", filter,
94
pw_filter_state_as_string(old),
95
- pw_filter_state_as_string(state), filter->error);
96
+ pw_filter_state_as_string(state), res, error);
97
98
if (state == PW_FILTER_STATE_ERROR)
99
- pw_log_error("%p: error %s", filter, error);
100
+ pw_log_error("%p: error (%d) %s", filter, res, error);
101
102
filter->state = state;
103
pw_filter_emit_state_changed(filter, old, state, error);
104
}
105
- return res;
106
+ return changed;
107
}
108
109
static int enum_params(struct filter *d, struct spa_list *param_list, int seq,
110
111
struct filter *impl = object;
112
struct pw_filter *filter = &impl->this;
113
114
- if (id != SPA_PARAM_Props)
115
- return -ENOTSUP;
116
-
117
pw_filter_emit_param_changed(filter, NULL, id, param);
118
return 0;
119
}
120
121
impl->position = data;
122
else
123
impl->position = NULL;
124
- pw_loop_invoke(impl->context->data_loop,
125
+ pw_loop_invoke(impl->data_loop,
126
do_set_position, 1, NULL, 0, true, impl);
127
break;
128
}
129
130
case SPA_NODE_COMMAND_Suspend:
131
case SPA_NODE_COMMAND_Flush:
132
case SPA_NODE_COMMAND_Pause:
133
- pw_loop_invoke(impl->context->main_loop,
134
+ pw_loop_invoke(impl->main_loop,
135
NULL, 0, NULL, 0, false, impl);
136
if (filter->state == PW_FILTER_STATE_STREAMING) {
137
pw_log_debug("%p: pause", filter);
138
- filter_set_state(filter, PW_FILTER_STATE_PAUSED, NULL);
139
+ filter_set_state(filter, PW_FILTER_STATE_PAUSED, 0, NULL);
140
}
141
break;
142
case SPA_NODE_COMMAND_Start:
143
if (filter->state == PW_FILTER_STATE_PAUSED) {
144
pw_log_debug("%p: start", filter);
145
- filter_set_state(filter, PW_FILTER_STATE_STREAMING, NULL);
146
+ filter_set_state(filter, PW_FILTER_STATE_STREAMING, 0, NULL);
147
}
148
break;
149
default:
150
151
pw_filter_emit_param_changed(filter, port->user_data, id, param);
152
153
if (filter->state == PW_FILTER_STATE_ERROR)
154
- return -EIO;
155
+ return filter->error_res;
156
157
emit_port_info(impl, port, false);
158
159
160
return 0;
161
}
162
163
-static inline void copy_position(struct filter *impl)
164
-{
165
- struct spa_io_position *p = impl->rt.position;
166
- if (SPA_UNLIKELY(p != NULL)) {
167
- SEQ_WRITE(impl->seq);
168
- impl->time.now = p->clock.nsec;
169
- impl->time.rate = p->clock.rate;
170
- if (SPA_UNLIKELY(impl->clock_id != p->clock.id)) {
171
- impl->base_pos = p->clock.position - impl->time.ticks;
172
- impl->clock_id = p->clock.id;
173
- }
174
- impl->time.ticks = p->clock.position - impl->base_pos;
175
- impl->time.delay = 0;
176
- SEQ_WRITE(impl->seq);
177
- }
178
-}
179
-
180
static int
181
do_call_process(struct spa_loop *loop,
182
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
183
184
process, 0, impl->rt.position);
185
}
186
else {
187
- pw_loop_invoke(impl->context->main_loop,
188
+ pw_loop_invoke(impl->main_loop,
189
do_call_process, 1, NULL, 0, false, impl);
190
}
191
}
192
193
struct pw_filter *filter = &impl->this;
194
pw_log_trace("%p: drained", filter);
195
pw_filter_emit_drained(filter);
196
- impl->draining = false;
197
return 0;
198
}
199
200
static void call_drained(struct filter *impl)
201
pipewire-0.3.70.tar.gz/src/pipewire/impl-client.c -> pipewire-0.3.71.tar.gz/src/pipewire/impl-client.c
Changed
49
1
2
{
3
struct pw_resource *r = object;
4
struct error_data *d = data;
5
- if (r && r->bound_id == d->id)
6
+
7
+ if (r && r->bound_id == d->id) {
8
+ pw_log_debug("%p: client error for global %u: %d (%s)",
9
+ r, d->id, d->res, d->error);
10
pw_resource_error(r, d->res, d->error);
11
+ }
12
return 0;
13
}
14
15
static int client_error(void *object, uint32_t id, int res, const char *error)
16
{
17
struct resource_data *data = object;
18
+ struct pw_resource *resource = data->resource;
19
+ struct pw_impl_client *sender = resource->client;
20
struct pw_impl_client *client = data->client;
21
struct error_data d = { id, res, error };
22
+ struct pw_global *global;
23
24
- pw_log_debug("%p: error for global %d", client, id);
25
+ /* Check the global id provided by sender refers to a registered global
26
+ * known to the sender.
27
+ */
28
+ if ((global = pw_context_find_global(resource->context, id)) == NULL)
29
+ goto error_no_id;
30
+ if (sender->recv_generation != 0 && global->generation > sender->recv_generation)
31
+ goto error_stale_id;
32
+
33
+ pw_log_debug("%p: sender %p: error for global %u", client, sender, id);
34
pw_map_for_each(&client->objects, error_resource, &d);
35
return 0;
36
+
37
+error_no_id:
38
+ pw_log_debug("%p: sender %p: error for invalid global %u", client, sender, id);
39
+ pw_resource_errorf(resource, -ENOENT, "no global %u", id);
40
+ return -ENOENT;
41
+error_stale_id:
42
+ pw_log_debug("%p: sender %p: error for stale global %u generation:%"PRIu64" recv-generation:%"PRIu64,
43
+ client, sender, id, global->generation, sender->recv_generation);
44
+ pw_resource_errorf(resource, -ESTALE, "no global %u any more", id);
45
+ return -ESTALE;
46
}
47
48
static bool has_key(const char * const keys, const char *key)
49
pipewire-0.3.70.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.71.tar.gz/src/pipewire/impl-link.c
Changed
182
1
2
3
/** \endcond */
4
5
+static struct pw_node_peer *pw_node_peer_ref(struct pw_impl_node *onode, struct pw_impl_node *inode)
6
+{
7
+ struct pw_node_peer *peer;
8
+
9
+ spa_list_for_each(peer, &onode->peer_list, link) {
10
+ if (peer->target.node == inode) {
11
+ pw_log_debug("exiting peer %p from %p to %p", peer, onode, inode);
12
+ peer->ref++;
13
+ return peer;
14
+ }
15
+ }
16
+ peer = calloc(1, sizeof(*peer));
17
+ if (peer == NULL)
18
+ return NULL;
19
+
20
+ peer->ref = 1;
21
+ peer->output = onode;
22
+ peer->active_count = 0;
23
+ peer->target.node = inode;
24
+ peer->target.activation = inode->rt.activation;
25
+ peer->target.system = inode->data_system;
26
+ peer->target.fd = inode->source.fd;
27
+
28
+ spa_list_append(&onode->peer_list, &peer->link);
29
+ pw_log_debug("new peer %p from %p to %p", peer, onode, inode);
30
+ pw_impl_node_emit_peer_added(onode, inode);
31
+
32
+ return peer;
33
+}
34
+
35
+static void pw_node_peer_unref(struct pw_node_peer *peer)
36
+{
37
+ if (--peer->ref > 0)
38
+ return;
39
+ spa_list_remove(&peer->link);
40
+ pw_log_debug("remove peer %p from %p to %p", peer, peer->output, peer->target.node);
41
+ pw_impl_node_emit_peer_removed(peer->output, peer->target.node);
42
+ free(peer);
43
+}
44
+
45
+static void pw_node_peer_activate(struct pw_node_peer *peer)
46
+{
47
+ struct pw_node_activation_state *state;
48
+
49
+ state = &peer->target.activation->state0;
50
+
51
+ if (peer->active_count++ == 0) {
52
+ spa_list_append(&peer->output->rt.target_list, &peer->target.link);
53
+ if (!peer->target.active && peer->output->rt.driver_target.node != NULL) {
54
+ state->required++;
55
+ peer->target.active = true;
56
+ }
57
+ }
58
+ pw_log_trace("%p: node:%p state:%p pending:%d/%d", peer->output,
59
+ peer->target.node, state, state->pending, state->required);
60
+}
61
+
62
+static void pw_node_peer_deactivate(struct pw_node_peer *peer)
63
+{
64
+ struct pw_node_activation_state *state;
65
+ state = &peer->target.activation->state0;
66
+ if (--peer->active_count == 0) {
67
+
68
+ spa_list_remove(&peer->target.link);
69
+
70
+ if (peer->target.active) {
71
+ state->required--;
72
+ peer->target.active = false;
73
+ }
74
+ }
75
+ pw_log_trace("%p: node:%p state:%p pending:%d/%d", peer->output,
76
+ peer->target.node, state, state->pending, state->required);
77
+}
78
+
79
+
80
static void info_changed(struct pw_impl_link *link)
81
{
82
struct pw_resource *resource;
83
84
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
85
{
86
struct pw_impl_link *this = user_data;
87
- struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
88
89
pw_log_trace("%p: activate", this);
90
91
spa_list_append(&this->output->rt.mix_list, &this->rt.out_mix.rt_link);
92
spa_list_append(&this->input->rt.mix_list, &this->rt.in_mix.rt_link);
93
94
- if (impl->inode != impl->onode) {
95
- struct pw_node_activation_state *state;
96
-
97
- this->rt.target.activation = impl->inode->rt.activation;
98
- spa_list_append(&impl->onode->rt.target_list, &this->rt.target.link);
99
-
100
- state = &this->rt.target.activation->state0;
101
- if (!this->rt.target.active && impl->onode->rt.driver_target.node != NULL) {
102
- state->required++;
103
- this->rt.target.active = true;
104
- }
105
+ if (this->peer)
106
+ pw_node_peer_activate(this->peer);
107
108
- pw_log_trace("%p: node:%p state:%p pending:%d/%d", this, impl->inode,
109
- state, state->pending, state->required);
110
- }
111
return 0;
112
}
113
114
115
pw_link_state_as_string(this->info.state));
116
117
if (impl->activated || !this->prepared ||
118
- !impl->inode->active || !impl->onode->active)
119
+ !impl->inode->runnable || !impl->onode->runnable)
120
return 0;
121
122
if (!impl->io_set) {
123
124
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
125
{
126
struct pw_impl_link *this = user_data;
127
- struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
128
129
pw_log_trace("%p: disable %p and %p", this, &this->rt.in_mix, &this->rt.out_mix);
130
131
spa_list_remove(&this->rt.out_mix.rt_link);
132
spa_list_remove(&this->rt.in_mix.rt_link);
133
134
- if (impl->inode != impl->onode) {
135
- struct pw_node_activation_state *state;
136
-
137
- spa_list_remove(&this->rt.target.link);
138
- state = &this->rt.target.activation->state0;
139
- if (this->rt.target.active) {
140
- state->required--;
141
- this->rt.target.active = false;
142
- }
143
-
144
- pw_log_trace("%p: node:%p state:%p pending:%d/%d", this, impl->inode,
145
- state, state->pending, state->required);
146
- }
147
+ if (this->peer)
148
+ pw_node_peer_deactivate(this->peer);
149
150
return 0;
151
}
152
153
impl->inode = input_node;
154
}
155
156
- this->rt.target.signal_func = impl->inode->rt.target.signal_func;
157
- this->rt.target.data = impl->inode->rt.target.data;
158
-
159
pw_log_debug("%p: constructed out:%p:%d.%d -> in:%p:%d.%d", impl,
160
output_node, output->port_id, this->rt.out_mix.port.port_id,
161
input_node, input->port_id, this->rt.in_mix.port.port_id);
162
163
pw_impl_port_recalc_latency(output);
164
pw_impl_port_recalc_latency(input);
165
166
- pw_impl_node_emit_peer_added(impl->onode, impl->inode);
167
+ if (impl->onode != impl->inode)
168
+ this->peer = pw_node_peer_ref(impl->onode, impl->inode);
169
170
return this;
171
172
173
if (link->registered)
174
spa_list_remove(&link->link);
175
176
- pw_impl_node_emit_peer_removed(impl->onode, impl->inode);
177
+ if (link->peer)
178
+ pw_node_peer_unref(link->peer);
179
180
try_unlink_controls(impl, link->output, link->input);
181
182
pipewire-0.3.70.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.71.tar.gz/src/pipewire/impl-node.c
Changed
201
1
2
3
unsigned int cache_params:1;
4
unsigned int pending_play:1;
5
+
6
+ uint64_t prev_signal_time;
7
};
8
9
#define pw_node_resource(r,m,v,...) pw_resource_call(r,struct pw_node_events,m,v,__VA_ARGS__)
10
11
12
/** \endcond */
13
14
+/* Called from the node data loop when a node needs to be scheduled by
15
+ * the given driver. 3 things needs to happen:
16
+ *
17
+ * - the node is added to the driver target list and the required state
18
+ * is incremented. This makes sure the node is woken up when the driver
19
+ * starts a new cycle.
20
+ * - the node needs to trigger the driver when it completes. This means
21
+ * the driver is added to the target list.
22
+ * - the node targets (including the driver we added above) have their
23
+ * required state incremented.
24
+ *
25
+ * This code is called from the data-loop to ensure synchronization
26
+ */
27
static void add_node(struct pw_impl_node *this, struct pw_impl_node *driver)
28
{
29
struct pw_node_activation_state *dstate, *nstate;
30
31
pw_log_trace("%p: add to driver %p %p %p", this, driver,
32
driver->rt.activation, this->rt.activation);
33
34
- /* signal the driver */
35
- this->rt.driver_target.activation = driver->rt.activation;
36
- this->rt.driver_target.node = driver;
37
- this->rt.driver_target.data = driver;
38
- spa_list_append(&this->rt.target_list, &this->rt.driver_target.link);
39
-
40
+ /* let the driver trigger us as part of the processing cycle */
41
spa_list_append(&driver->rt.target_list, &this->rt.target.link);
42
nstate = &this->rt.activation->state0;
43
if (!this->rt.target.active) {
44
45
this->rt.target.active = true;
46
}
47
48
+ /* trigger the driver when we complete */
49
+ this->rt.driver_target.activation = driver->rt.activation;
50
+ this->rt.driver_target.node = driver;
51
+ this->rt.driver_target.system = driver->data_system;
52
+ this->rt.driver_target.fd = driver->source.fd;
53
+ spa_list_append(&this->rt.target_list, &this->rt.driver_target.link);
54
+
55
+ /* now increment the required states of all this node targets, including
56
+ * the driver we added above */
57
spa_list_for_each(t, &this->rt.target_list, link) {
58
dstate = &t->activation->state0;
59
if (!t->active) {
60
61
}
62
}
63
64
+/* called from the data loop and undoes the changes done in add_node. */
65
static void remove_node(struct pw_impl_node *this)
66
{
67
struct pw_node_activation_state *dstate, *nstate;
68
69
return;
70
71
pw_log_trace("%p: remove from driver %p %p %p",
72
- this, this->rt.driver_target.data,
73
+ this, this->rt.driver_target.node,
74
this->rt.driver_target.activation, this->rt.activation);
75
76
spa_list_remove(&this->rt.target.link);
77
78
}
79
80
static int
81
-do_node_add(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
82
+do_node_add(struct spa_loop *loop, bool async, uint32_t seq,
83
+ const void *data, size_t size, void *user_data)
84
{
85
struct pw_impl_node *this = user_data;
86
struct pw_impl_node *driver = this->driver_node;
87
88
- this->added = true;
89
- if (this->source.loop == NULL) {
90
- struct spa_system *data_system = this->context->data_system;
91
+ if (!this->added) {
92
uint64_t dummy;
93
int res;
94
95
/* clear the eventfd in case it was written to while the node was stopped */
96
- res = spa_system_eventfd_read(data_system, this->source.fd, &dummy);
97
+ res = spa_system_eventfd_read(this->data_system, this->source.fd, &dummy);
98
if (SPA_UNLIKELY(res != -EAGAIN && res != 0))
99
pw_log_warn("%p: read failed %m", this);
100
101
- spa_loop_add_source(loop, &this->source);
102
+ this->added = true;
103
+ /* remote nodes have their source added in client-node instead */
104
+ if (!this->remote)
105
+ spa_loop_add_source(loop, &this->source);
106
add_node(this, driver);
107
}
108
return 0;
109
}
110
111
static int
112
-do_node_remove(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
113
+do_node_remove(struct spa_loop *loop, bool async, uint32_t seq,
114
+ const void *data, size_t size, void *user_data)
115
{
116
struct pw_impl_node *this = user_data;
117
- if (this->source.loop != NULL) {
118
- spa_loop_remove_source(loop, &this->source);
119
+ if (this->added) {
120
+ if (!this->remote)
121
+ spa_loop_remove_source(loop, &this->source);
122
remove_node(this);
123
+ this->added = false;
124
}
125
- this->added = false;
126
return 0;
127
}
128
129
130
{
131
struct resource_data *data = object;
132
struct pw_impl_node *node = data->node;
133
+ uint32_t id = SPA_NODE_COMMAND_ID(command);
134
135
- switch (SPA_NODE_COMMAND_ID(command)) {
136
+ pw_log_debug("%p: got command %d (%s)", node, id,
137
+ spa_debug_type_find_name(spa_type_node_command_id, id));
138
+
139
+ switch (id) {
140
case SPA_NODE_COMMAND_Suspend:
141
suspend_node(node);
142
break;
143
144
node->target_rate = node->rt.position->clock.target_rate;
145
node->target_quantum = node->rt.position->clock.target_duration;
146
147
- if (node->source.loop != NULL) {
148
+ if (node->added) {
149
remove_node(node);
150
add_node(node, driver);
151
}
152
153
154
remove_segment_owner(old, node->info.id);
155
156
- if (old != node && old->driving && driver->info.state < PW_NODE_STATE_RUNNING) {
157
- pw_log_info("move quantum:%"PRIu64"->%"PRIu64" rate:%d->%d (%s-%d -> %s-%d)",
158
- driver->target_quantum,
159
- old->target_quantum,
160
- driver->target_rate.denom,
161
- old->target_rate.denom,
162
- old->name, old->info.id,
163
- driver->name, driver->info.id);
164
- driver->target_rate = old->target_rate;
165
- driver->target_quantum = old->target_quantum;
166
- driver->target_pending = true;
167
- }
168
was_driving = node->driving;
169
node->driving = node->driver && driver == node;
170
171
172
else
173
spa_list_remove(&node->driver_link);
174
}
175
+ if (driver && node->driver_node == node)
176
+ node->driving = true;
177
recalc_reason = "driver changed";
178
}
179
180
181
}
182
}
183
184
-static inline int resume_node(struct pw_impl_node *this, int status)
185
+static inline uint64_t get_time_ns(struct spa_system *system)
186
{
187
- struct pw_node_target *t;
188
struct timespec ts;
189
- struct pw_node_activation *activation = this->rt.activation;
190
- struct spa_system *data_system = this->context->data_system;
191
- uint64_t nsec;
192
+ spa_system_clock_gettime(system, CLOCK_MONOTONIC, &ts);
193
+ return SPA_TIMESPEC_TO_NSEC(&ts);
194
+}
195
196
- spa_system_clock_gettime(data_system, CLOCK_MONOTONIC, &ts);
197
- nsec = SPA_TIMESPEC_TO_NSEC(&ts);
198
- activation->status = PW_NODE_ACTIVATION_FINISHED;
199
- activation->finish_time = nsec;
200
+static inline void node_trigger(struct pw_impl_node *this)
201
pipewire-0.3.70.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.71.tar.gz/src/pipewire/impl-port.c
Changed
42
1
2
PW_KEY_PORT_CONTROL,
3
PW_KEY_PORT_ALIAS,
4
PW_KEY_PORT_EXTRA,
5
+ PW_KEY_PORT_IGNORE_LATENCY,
6
NULL
7
};
8
9
10
11
is_monitor = pw_properties_get_bool(port->properties, PW_KEY_PORT_MONITOR, false);
12
13
+ port->ignore_latency = pw_properties_get_bool(port->properties, PW_KEY_PORT_IGNORE_LATENCY, false);
14
+
15
is_control = PW_IMPL_PORT_IS_CONTROL(port);
16
if (is_control) {
17
dir = port->direction == PW_DIRECTION_INPUT ? "control" : "notify";
18
19
if (port->direction == PW_DIRECTION_OUTPUT) {
20
spa_list_for_each(l, &port->links, output_link) {
21
other = l->input;
22
+ if (other->ignore_latency) {
23
+ pw_log_debug("port %d: peer %d: peer latency ignored",
24
+ port->info.id, other->info.id);
25
+ continue;
26
+ }
27
spa_latency_info_combine(&latency, &other->latencyother->direction);
28
pw_log_debug("port %d: peer %d: latency %f-%f %d-%d %"PRIu64"-%"PRIu64,
29
port->info.id, other->info.id,
30
31
} else {
32
spa_list_for_each(l, &port->links, input_link) {
33
other = l->output;
34
+ if (other->ignore_latency) {
35
+ pw_log_debug("port %d: peer %d: peer latency ignored",
36
+ port->info.id, other->info.id);
37
+ continue;
38
+ }
39
spa_latency_info_combine(&latency, &other->latencyother->direction);
40
pw_log_debug("port %d: peer %d: latency %f-%f %d-%d %"PRIu64"-%"PRIu64,
41
port->info.id, other->info.id,
42
pipewire-0.3.70.tar.gz/src/pipewire/keys.h -> pipewire-0.3.71.tar.gz/src/pipewire/keys.h
Changed
21
1
2
#define PW_KEY_PORT_EXTRA "port.extra" /**< api specific extra port info, API name
3
* should be prefixed. "jack:flags:56" */
4
#define PW_KEY_PORT_PASSIVE "port.passive" /**< the ports wants passive links, since 0.3.67 */
5
+#define PW_KEY_PORT_IGNORE_LATENCY "port.ignore-latency" /**< latency ignored by peers, since 0.3.71 */
6
7
/** link properties */
8
#define PW_KEY_LINK_ID "link.id" /**< a link id */
9
10
#define PW_KEY_STREAM_LATENCY_MAX "stream.latency.max" /**< The maximum latency of the stream */
11
#define PW_KEY_STREAM_MONITOR "stream.monitor" /**< Indicates that the stream is monitoring
12
* and might select a less accurate but faster
13
- * conversion algorithm. */
14
+ * conversion algorithm. Monitor streams are also
15
+ * ignored when calculating the latency of their peer
16
+ * ports (since 0.3.71).
17
+ */
18
#define PW_KEY_STREAM_DONT_REMIX "stream.dont-remix" /**< don't remix channels */
19
#define PW_KEY_STREAM_CAPTURE_SINK "stream.capture.sink" /**< Try to capture the sink output instead of
20
* source output */
21
pipewire-0.3.70.tar.gz/src/pipewire/loop.c -> pipewire-0.3.71.tar.gz/src/pipewire/loop.c
Changed
14
1
2
goto error_unload_loop;
3
}
4
this->control = iface;
5
+ if (!spa_interface_callback_check(&this->control->iface,
6
+ struct spa_loop_control_methods, iterate, 0)) {
7
+ res = -EINVAL;
8
+ pw_log_error("%p: loop does not support iterate", this);
9
+ goto error_unload_loop;
10
+ }
11
12
if ((res = spa_handle_get_interface(impl->loop_handle,
13
SPA_TYPE_INTERFACE_LoopUtils,
14
pipewire-0.3.70.tar.gz/src/pipewire/loop.h -> pipewire-0.3.71.tar.gz/src/pipewire/loop.h
Changed
11
1
2
#define pw_loop_get_fd(l) spa_loop_control_get_fd((l)->control)
3
#define pw_loop_add_hook(l,...) spa_loop_control_add_hook((l)->control,__VA_ARGS__)
4
#define pw_loop_enter(l) spa_loop_control_enter((l)->control)
5
-#define pw_loop_iterate(l,...) spa_loop_control_iterate((l)->control,__VA_ARGS__)
6
#define pw_loop_leave(l) spa_loop_control_leave((l)->control)
7
+#define pw_loop_iterate(l,...) spa_loop_control_iterate_fast((l)->control,__VA_ARGS__)
8
9
#define pw_loop_add_io(l,...) spa_loop_utils_add_io((l)->utils,__VA_ARGS__)
10
#define pw_loop_update_io(l,...) spa_loop_utils_update_io((l)->utils,__VA_ARGS__)
11
pipewire-0.3.70.tar.gz/src/pipewire/private.h -> pipewire-0.3.71.tar.gz/src/pipewire/private.h
Changed
128
1
2
#define ensure_loop(loop,...) ({ \
3
int res = pw_loop_check(loop); \
4
if (res != 1) { \
5
- pw_log_warn("%s called from wrong context, check thread and locking: %s", \
6
- __func__, spa_strerror(res)); \
7
+ pw_log_warn("%s called from wrong context, check thread and locking: %s", \
8
+ __func__, res < 0 ? spa_strerror(res) : "Not in loop"); \
9
fprintf(stderr, "*** %s called from wrong context, check thread and locking: %s\n",\
10
- __func__, spa_strerror(res)); \
11
+ __func__, res < 0 ? spa_strerror(res) : "Not in loop"); \
12
/* __VA_ARGS__ */ \
13
} \
14
})
15
16
struct spa_thread_utils *thread_utils;
17
struct pw_loop *main_loop; /**< main loop for control */
18
struct pw_loop *data_loop; /**< data loop for data passing */
19
- struct pw_data_loop *data_loop_impl;
20
struct spa_system *data_system; /**< data system for data passing */
21
struct pw_work_queue *work_queue; /**< work queue */
22
23
24
struct spa_list link;
25
struct pw_impl_node *node;
26
struct pw_node_activation *activation;
27
- int (*signal_func) (void *data);
28
- void *data;
29
+ struct spa_system *system;
30
+ int fd;
31
unsigned int active:1;
32
};
33
34
35
36
struct spa_list sort_link; /**< link used to sort nodes */
37
38
+ struct spa_list peer_list; /* list of peers */
39
+
40
struct spa_node *node; /**< SPA node implementation */
41
struct spa_hook listener;
42
43
44
struct spa_hook_list listener_list;
45
46
struct pw_loop *data_loop; /**< the data loop for this node */
47
+ struct spa_system *data_system;
48
49
struct spa_fraction latency; /**< requested latency */
50
struct spa_fraction max_latency; /**< maximum latency */
51
52
53
struct spa_latency_info latency2; /**< latencies */
54
unsigned int have_latency_param:1;
55
+ unsigned int ignore_latency:1;
56
57
void *owner_data; /**< extra owner data */
58
void *user_data; /**< extra user data */
59
60
unsigned int valid:1;
61
};
62
63
+struct pw_node_peer {
64
+ int ref;
65
+ int active_count;
66
+ struct spa_list link; /**< link in peer list */
67
+ struct pw_impl_node *output; /**< the output node */
68
+ struct pw_node_target target; /**< target of the input node */
69
+};
70
+
71
#define pw_impl_link_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_impl_link_events, m, v, ##__VA_ARGS__)
72
#define pw_impl_link_emit_destroy(l) pw_impl_link_emit(l, destroy, 0)
73
#define pw_impl_link_emit_free(l) pw_impl_link_emit(l, free, 0)
74
75
struct pw_control_link control;
76
struct pw_control_link notify;
77
78
+ struct pw_node_peer *peer;
79
+
80
struct {
81
struct pw_impl_port_mix out_mix; /**< port added to the output mixer */
82
struct pw_impl_port_mix in_mix; /**< port added to the input mixer */
83
- struct pw_node_target target; /**< target to trigger the input node */
84
} rt;
85
86
void *user_data;
87
88
* CONFIGURE state and higher */
89
enum pw_stream_state state; /**< stream state */
90
char *error; /**< error reason when state is in error */
91
+ int error_res; /**< error code when in error */
92
93
struct spa_hook_list listener_list;
94
95
struct pw_proxy *proxy;
96
struct spa_hook proxy_listener;
97
98
+ struct pw_impl_node *node;
99
struct spa_hook node_listener;
100
101
struct spa_list controls;
102
103
* CONFIGURE state and higher */
104
enum pw_filter_state state; /**< filter state */
105
char *error; /**< error reason when state is in error */
106
+ int error_res; /**< error code when in error */
107
108
struct spa_hook_list listener_list;
109
110
struct pw_proxy *proxy;
111
struct spa_hook proxy_listener;
112
113
+ struct pw_impl_node *node;
114
+ struct spa_hook node_listener;
115
+
116
struct spa_list controls;
117
};
118
119
120
121
int pw_impl_node_set_driver(struct pw_impl_node *node, struct pw_impl_node *driver);
122
123
+int pw_impl_node_trigger(struct pw_impl_node *node);
124
+
125
/** Prepare a link
126
* Starts the negotiation of formats and buffers on \a link */
127
int pw_impl_link_prepare(struct pw_impl_link *link);
128
pipewire-0.3.70.tar.gz/src/pipewire/properties.c -> pipewire-0.3.71.tar.gz/src/pipewire/properties.c
Changed
11
1
2
if ((len = spa_json_next(&sub, &value)) < 0)
3
break;
4
5
+ if (!spa_json_is_container(value, len))
6
+ len = value ? strlen(value) : 0;
7
+
8
dump(c, c->indent, &sub, value, len);
9
count++;
10
}
11
pipewire-0.3.70.tar.gz/src/pipewire/stream.c -> pipewire-0.3.71.tar.gz/src/pipewire/stream.c
Changed
201
1
2
struct pw_context *context;
3
struct spa_hook context_listener;
4
5
+ struct pw_loop *main_loop;
6
+ struct pw_loop *data_loop;
7
+
8
enum spa_direction direction;
9
enum pw_stream_flags flags;
10
11
- struct pw_impl_node *node;
12
-
13
struct spa_node impl_node;
14
struct spa_node_methods node_methods;
15
struct spa_hook_list hooks;
16
17
queue->incount = queue->outcount;
18
}
19
20
-static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state state, const char *error)
21
+static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state state,
22
+ int res, const char *error)
23
{
24
enum pw_stream_state old = stream->state;
25
- bool res = old != state;
26
+ bool changed = old != state;
27
28
- if (res) {
29
+ if (changed) {
30
free(stream->error);
31
stream->error = error ? strdup(error) : NULL;
32
+ stream->error_res = res;
33
34
- pw_log_debug("%p: update state from %s -> %s (%s)", stream,
35
+ pw_log_debug("%p: update state from %s -> %s (%d) %s", stream,
36
pw_stream_state_as_string(old),
37
- pw_stream_state_as_string(state), stream->error);
38
+ pw_stream_state_as_string(state), res, stream->error);
39
40
if (state == PW_STREAM_STATE_ERROR)
41
- pw_log_error("%p: error %s", stream, error);
42
+ pw_log_error("%p: error (%d) %s", stream, res, error);
43
44
stream->state = state;
45
pw_stream_emit_state_changed(stream, old, state, error);
46
}
47
- return res;
48
+ return changed;
49
}
50
51
static struct buffer *get_buffer(struct pw_stream *stream, uint32_t id)
52
53
if (impl->process_rt)
54
spa_callbacks_call(&impl->rt_callbacks, struct pw_stream_events, process, 0);
55
else
56
- pw_loop_invoke(impl->context->main_loop,
57
+ pw_loop_invoke(impl->main_loop,
58
do_call_process, 1, NULL, 0, false, impl);
59
}
60
61
62
63
static void call_drained(struct stream *impl)
64
{
65
- pw_loop_invoke(impl->context->main_loop,
66
+ pw_loop_invoke(impl->main_loop,
67
do_call_drained, 1, NULL, 0, false, impl);
68
}
69
70
71
72
static void call_trigger_done(struct stream *impl)
73
{
74
- pw_loop_invoke(impl->context->main_loop,
75
+ pw_loop_invoke(impl->main_loop,
76
do_call_trigger_done, 1, NULL, 0, false, impl);
77
}
78
79
80
else
81
impl->position = NULL;
82
83
- pw_loop_invoke(impl->context->data_loop,
84
+ pw_loop_invoke(impl->data_loop,
85
do_set_position, 1, NULL, 0, true, impl);
86
break;
87
default:
88
89
case SPA_NODE_COMMAND_Suspend:
90
case SPA_NODE_COMMAND_Flush:
91
case SPA_NODE_COMMAND_Pause:
92
- pw_loop_invoke(impl->context->main_loop,
93
+ pw_loop_invoke(impl->main_loop,
94
NULL, 0, NULL, 0, false, impl);
95
if (stream->state == PW_STREAM_STATE_STREAMING) {
96
97
pw_log_debug("%p: pause", stream);
98
- stream_set_state(stream, PW_STREAM_STATE_PAUSED, NULL);
99
+ stream_set_state(stream, PW_STREAM_STATE_PAUSED, 0, NULL);
100
}
101
break;
102
case SPA_NODE_COMMAND_Start:
103
104
call_process(impl);
105
}
106
107
- stream_set_state(stream, PW_STREAM_STATE_STREAMING, NULL);
108
+ stream_set_state(stream, PW_STREAM_STATE_STREAMING, 0, NULL);
109
}
110
break;
111
default:
112
113
pw_stream_emit_param_changed(stream, id, param);
114
115
if (stream->state == PW_STREAM_STATE_ERROR)
116
- return -EIO;
117
+ return stream->error_res;
118
119
emit_node_info(impl, false);
120
emit_port_info(impl, false);
121
122
pw_log_debug("%p: removed", stream);
123
spa_hook_remove(&stream->proxy_listener);
124
stream->node_id = SPA_ID_INVALID;
125
- stream_set_state(stream, PW_STREAM_STATE_UNCONNECTED, NULL);
126
+ stream_set_state(stream, PW_STREAM_STATE_UNCONNECTED, 0, NULL);
127
}
128
129
static void proxy_destroy(void *_data)
130
131
stream->node_id = global_id;
132
if (props)
133
pw_properties_update(stream->properties, props);
134
- stream_set_state(stream, PW_STREAM_STATE_PAUSED, NULL);
135
+ stream_set_state(stream, PW_STREAM_STATE_PAUSED, 0, NULL);
136
}
137
138
static const struct pw_proxy_events proxy_events = {
139
140
static void node_event_destroy(void *data)
141
{
142
struct pw_stream *stream = data;
143
- struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
144
spa_hook_remove(&stream->node_listener);
145
- impl->node = NULL;
146
+ stream->node = NULL;
147
}
148
149
static void node_event_info(void *data, const struct pw_node_info *info)
150
{
151
struct pw_stream *stream = data;
152
- struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
153
uint32_t i;
154
155
if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
156
157
switch (info->paramsi.id) {
158
case SPA_PARAM_PropInfo:
159
case SPA_PARAM_Props:
160
- pw_impl_node_for_each_param(impl->node,
161
+ pw_impl_node_for_each_param(stream->node,
162
0, info->paramsi.id,
163
0, UINT32_MAX,
164
NULL,
165
166
id, seq, res, spa_strerror(res), message);
167
168
if (id == PW_ID_CORE && res == -EPIPE) {
169
- stream_set_state(stream, PW_STREAM_STATE_UNCONNECTED, message);
170
+ stream_set_state(stream, PW_STREAM_STATE_UNCONNECTED, res, message);
171
}
172
}
173
174
175
static void context_drained(void *data, struct pw_impl_node *node)
176
{
177
struct stream *impl = data;
178
- if (impl->node != node)
179
+ if (impl->this.node != node)
180
return;
181
if (impl->draining && impl->drained) {
182
impl->draining = false;
183
184
res = -errno;
185
goto error_properties;
186
}
187
+ impl->main_loop = pw_context_get_main_loop(context);
188
189
this = &impl->this;
190
pw_log_debug("%p: new \"%s\"", impl, name);
191
192
193
impl->disconnecting = true;
194
195
- if (impl->node)
196
- pw_impl_node_set_active(impl->node, false);
197
+ if (stream->node)
198
+ pw_impl_node_set_active(stream->node, false);
199
200
if (stream->proxy) {
201
pipewire-0.3.70.tar.gz/src/tools/pw-profiler.c -> pipewire-0.3.71.tar.gz/src/tools/pw-profiler.c
Changed
10
1
2
d4 > 0 ? d4 : 0,
3
d5 > 0 ? d5 : 0,
4
d6 > 0 ? d6 : 0,
5
- (d5 > 0 && d4 > 0 && d5 > d4) ? d5 - d4 : 0,
6
+ (d5 > 0 && d4 >= 0 && d5 > d4) ? d5 - d4 : 0,
7
(d6 > 0 && d5 > 0 && d6 > d5) ? d6 - d5 : 0,
8
point->followeri.status);
9
}
10
pipewire-0.3.70.tar.gz/test/test-loop.c -> pipewire-0.3.71.tar.gz/test/test-loop.c
Changed
20
1
2
struct spa_hook hook;
3
};
4
5
+static void dmsbd_before(void *data)
6
+{
7
+}
8
+
9
static void dmsbd_after(void *data)
10
{
11
struct dmsbd_data *d = data;
12
13
14
static const struct spa_loop_control_hooks dmsbd_hooks = {
15
SPA_VERSION_LOOP_CONTROL_HOOKS,
16
+ .before = dmsbd_before,
17
.after = dmsbd_after,
18
};
19
20