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