Commit graph

8071 commits

Author SHA1 Message Date
Carlos Rafael Giani
2f94a49962 module-rtp-source: Detect and drop packets that are larger than the MTU 2026-07-02 11:55:36 +02:00
Carlos Rafael Giani
20f17c73de module-rtp: Correctly scale device_delay in constant latency mode 2026-07-02 11:55:36 +02:00
Carlos Rafael Giani
6c3fd1f07f module-rtp: Cleanup default raw / raop formats
This places the default formats into a single place, which makes
it easier to keep track of them.
2026-07-02 11:55:36 +02:00
Daniel Scally
551eb0a473 gstpipewiresrc: Add a wait_negotiated() call to create()
Add a wait_negotiated() call to gst_pipewire_src_create(). This works
around a race-condition that we experience where the function is
called after the state is transitioning to paused, and after a
SPA_PARAM_Format with a NULL parameter has been passed. That event
is handled in the pipewire source by setting its negotiated flag to
False, which results in gst_pipewire_src_create() returning
GST_FLOW_NOT_NEGOTIATED, resulting in a failed stream attempt.

With this change, the stream survives the state change.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
2026-07-01 09:21:31 +00:00
Julian Bouzas
8d93b779cd pulse-server: don't consider monitor nodes when finding the default source
If a system does not have any Audio/Source node, clients that want to capture
audio from the default source should fail instead of capturing audio from a
monitor Audio/Sink node.
2026-07-01 09:11:03 +00:00
Charles
fc6e12bed0 gst: don't make stream errors fatal in pipewiresink mode=provide
When a consumer (e.g. Firefox via xdg-desktop-portal) connects to a
pipewiresink mode=provide node and format negotiation fails, the error
reaches the stream as a transient proxy error. The comments in
proxy_error suggest the application should decide whether the error is
permanent.

Before this on_state_changed unconditionally made every proxy error
permanent by calling pw_stream_set_error, which posted
GST_ELEMENT_ERROR and killed the entire provider pipeline. A virtual
camera provider should survive consumer negotiation failures.

In mode=provide, log the error as a warning and continue. Other modes
retain the existing behavior.

To reproduce (with the previous pool fix applied):

Producers:

gst-launch-1.0 -v -e pipewiresrc path=<id> ! \
  video/x-raw,width=1280,height=720,framerate=24/1 ! \
  jpegenc ! rtpjpegpay ! rtpstreampay ! \
  udpsink host=127.0.0.1 port=5000
gst-launch-1.0 -e \
  udpsrc address=127.0.0.1 port=5000 ! queue ! \
  application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! \
  application/x-rtp,encoding-name=JPEG ! rtpjpegdepay ! \
  decodebin ! videorate ! videoconvert ! \
  pipewiresink mode=provide \
  stream-properties="properties,media.class=Video/Source,media.role=Camera" \
  client-name=VirtualCam

Then open Firefox and select VirtualCam as camera source, without this
fix the provider pipeline exits with an error, bringing down any other
clients streaming from it.
2026-07-01 08:42:56 +00:00
Charles
e95cad05ef gst: skip invalid crop metadata in pipewiresrc
META_VideoCrop is present on every buffer negotiated through the
adapter, even when the producer never sets a meaningful crop
region. Before commit c634ef961, gst_buffer_get_video_crop_meta
returned NULL on new GstBuffers so the zero values were never
applied. After that commit, gst_buffer_add_video_crop_meta always
succeeds, and an invalid crop produces black frames.

Without this, the following produces black frames,

Producer:

gst-launch-1.0 videotestsrc is-live=true ! \
  video/x-raw,format=I420,width=1280,height=720,framerate=24/1 ! \
  pipewiresink mode=provide \
  stream-properties="properties,media.class=Video/Source,media.role=Camera" \
  client-name=VirtualCam

Consumer:

gst-launch-1.0 pipewiresrc path=<id> ! videoconvert ! autovideosink
2026-07-01 08:42:56 +00:00
Torkel Niklasson
0a413c866c gst: deviceprovider: tear down node proxies before releasing core
Destroy the bound node proxies in probe() and stop() while the loop is
locked, before releasing the core. This removes the node listeners so no
node_event_info can fire after the core is gone, fixing the root cause of
the resync() NULL-deref crash and a node-proxy leak.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-30 14:21:08 +00:00
Elliot Chen
7ee2416bdd pipewiresrc: fix caps negotiation failure in some cases when changing state from playing to paused
basesrc will do caps negotiation if pad is reconfigured. Should check and
wait if caps negotiation is currently in progress before corking the stream.

Return true when flushing to avoid caps negotiation failure.
2026-06-30 14:20:10 +00:00
Wim Taymans
3c14693bed client-node: clear mix when clearing the node
Even if we don't have a transport we should clear the mix info if there
is any available.

Fixes #5348
2026-06-30 16:17:12 +02:00
Wim Taymans
187b9154a6 filter-chain: pass context to filter-graph
Pass the IO_Position and IO_Latency to the filter graph in the
context.
2026-06-30 12:52:32 +02:00
Wim Taymans
5e521d3532 filter-graph: pass context to plugins
Make it possible to pass context to plugins and nodes in the
filter-chain.

We can use this to make filters aware of the graph clock or
latency, for example.
2026-06-30 12:24:54 +02:00
Wim Taymans
a988df47a2 docs: escape angle brackets in conf.c and fix page_core_api references
- conf.c: escape <key>, <value>, <action> placeholders in doc comment
- context.h, permission.h: fix \ref page_core_api to \ref api_pw_core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-26 12:46:00 +02:00
Wim Taymans
9710f02837 docs: escape angle brackets and fix @filename and \ref in doc comments
Escape <portname>, <tensorname>, <paramname>, <port>, <rules> and
similar angle-bracket placeholders that doxygen interprets as HTML
tags. Also escape @filename (unknown doxygen command) and fix the
pw_stream::process() reference in thread-loop.h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-26 12:43:56 +02:00
Wim Taymans
f055949cb5 docs: fix broken doxygen references and escape HTML tags
- modules.dox: remove references to non-existent sendspin modules
- access.dox: remove reference to deprecated pipewire-media-session
- dma-buf.dox: fix \ref EnumFormat to \ref SPA_PARAM_EnumFormat,
  fix \ref struct to struct \ref for spa_meta_sync_timeline
- pipewire.conf.5.md: add explicit {#synopsis} anchor for internal links
- pipewire-client.conf.5.md: fix audio_converter to audio_adapter ref
- pipewire-jack.conf.5.md: escape <id> HTML tags
- pipewire-props.7.md: fix monitor-prop__ to props__ for card profiles ref
- pipewire-pulse.1.md: fix pipewire-env ref to full anchor name
- pipewire.1.md: fix \ref CPU to \ref spa_cpu

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-26 12:42:01 +02:00
Wim Taymans
c4b767cba1 docs: rename pulse module files to fix doxygen \file name collisions
Prefix all pulse module source files with pulse- to give them unique
basenames, avoiding ambiguous \file suffix matching in doxygen when
identically-named files exist under src/modules/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-26 12:37:39 +02:00
Elliot Chen
9b2ff82aea pipewiresrc: unlock loop when failing to wait negotiated 2026-06-26 09:57:23 +00:00
Wim Taymans
7dc35030dc filter-graph: add normalize option for sofa
Add an option to enable the use of the sofa loudness function to
normalize the IR.

See #5322
2026-06-25 16:24:38 +02:00
Wim Taymans
d97a9bf44b pulse-server: actually print properties of module
When inspecting the loaded modules, actually list the properties that
were used when loading the module instead of the informational generic
ones from the info.

Pulsaudio also does not list the Usage properties when listing modules.
2026-06-25 09:21:27 +02:00
Wim Taymans
9bcbd7b586 pulse: generate Usage from module_args definition
Add some more fields like the type, default value and possible enum
values for the module_args.

Use this to generate the Usage in describe-module and the docs.

This should give more consistent and correct Usage output in all
modules.
2026-06-24 18:59:19 +02:00
AMG
9f7eb63486 refactor: pr 2026-06-24 16:32:43 +00:00
AMG
b4b4e03816 pw-container: Add socket path parameter 2026-06-24 16:32:43 +00:00
Julian Bouzas
62e98466fa conf: fix matching of property values with colons
Use spa_json_begin_array() instead of the relaxed variant when parsing
property values in pw_conf_find_match().

This prevents plain string values containing ':' (such as object.path)
from being incorrectly tokenized while preserving support for actual
JSON array properties.
2026-06-24 10:52:49 -04:00
Wim Taymans
7dac6a71d5 conf: avoid using close_range when undefined
Only call close_range when CLOSE_RANGE_UNSHARE is defined.

Fixes compilation on alpine.
2026-06-23 18:36:52 +02:00
Julian Bouzas
187187e41f pipewire-pulse: Expose profile preference setting as a message
Makes it easier for libpulse-based clients to modify this setting if they want.
2026-06-23 08:58:12 -04:00
Carlos Rafael Giani
d8f5ed0c13 module-rtp-sink: Add ability to add / remove receivers through commands
This makes it possible to dynamically add / remove receivers, which is
necesary for sending to multiple receivers. Mixed multi- and unicast
receivers are possible. Example pw-cli calls (56 is the ID of the RTP
sink node):

pw-cli c 56 User '{ extra="{ \"command.id\" : \"add-receiver\" , \"destination.ip\" : \"10.42.0.1\", \"destination.port\" : 55001 }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"remove-receiver\", \"destination.ip\" : \"10.42.0.1\" }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"clear-receivers\" }" }'

Commands and their arguments:

* "add-receiver" : Adds a receiver to the sink's list. If the given
  IP address <-> port combination was already added, the command is
  logged, but otherwise ignored. Arguments:
  - "destination.ip" : IP address to send data to. Can be a uni- or
    multicast address, but must be a valid address.
  - "destination.port" : Port to send data to. Must be valid.
  - "local.ifname", "source.ip", "net.ttl", "net.dscp", "net.loop" :
    These are all optional, and work just like in the RTP sink
    module's properties.

* "remove-receiver" : Removes a receiver from the sink's list. The
  receiver is identified by the given IP address. A port can optionally
  be specified as well. If it isn't, then the first receiver with that IP
  address is removed. If no matching receiver is in the sink's list,
  this command does nothing. Arguments:
  - "destination.ip" : IP address to send data to. Can be a uni- or
    multicast address, but must be a valid address.
  - "destination.port" : Port to send data to. This is optional. But, if
    it is set, it must be a valid port number.

* "clear-receivers" : Removes all receivers from the sink's list. If the
  list is empty, this does nothing. This command has no arguments.

If the RTP sink module is created with the "destination.ip" and
"destination.port" properties set, it behaves as if "add-receiver" were
called right after the module was initialized. This means that if none
of these commands are used, the module behaves just as it did prior to
this patch. Note that the "remove-receivers" command can remove this
initial receiver as well.

If no receivers are added, the module continues to work normally.
Adding and removing receivers mid-operation is supported.

NOTE: "destination.ip") handling in stream_props_changed() is removed,
since it never really did anything other than change the param value.
2026-06-23 10:47:36 +00:00
Wim Taymans
f2ccfe12c2 pw-cli: return errno-style error codes from command handlers
So that callers have more information to report useful error
messages.
2026-06-23 11:25:27 +02:00
Wim Taymans
9c5ea39f4e tools: return error when there was an error
Fixes #4286
2026-06-23 11:13:50 +02:00
Wim Taymans
208348ff2a conf: use close_range() before execvp()
Avoids leaking fds to the new program.
2026-06-22 14:35:11 +02:00
zuozhiwei
541d627482 module-rtp: release data_loop on rtp_stream_new error path
rtp_stream_new() acquires a data loop with pw_context_acquire_loop() but
the out: error path never calls pw_context_release_loop(), leaking the loop
reference on every failure after acquisition.

Mirror rtp_stream_destroy() and other modules that pair acquire with release.
2026-06-22 10:14:02 +00:00
Wim Taymans
db569ab566 buffers: fix the params iteration logic
A 0 result from the iteration with a NULL filter means the end of the
iteration, if we get this for the first item, we assume there was no
item (same as unknown item)

A 0 result for the iteration with filter means nothing matches the
filter and so the filter should not be included in the result. A result
of -ENOENT means the param is unknown and the filter should be included
in the result.

Fixes #5313
2026-06-19 14:26:42 +02:00
Wim Taymans
31e48d56f9 pulse-server: use the client properties for the zeroramp.gap 2026-06-19 10:05:56 +02:00
Wim Taymans
b21cad1eab impl-node: trigger a graph recalc on active node with driver
When adding the freeze/thaw recalc graph calls, triggering the actual
recalc of the graph (when an active node with a driver was removed) was
removed.

The thaw only actually recalcs the graph when something set the
recalc_pending flag so we still need something to set this. Normally
this would be because of some of the ports or links that got destroyed
but if not, the original recalc trigger needs to remain as a fallback.
2026-06-19 08:59:15 +02:00
Wim Taymans
6dafdd1b7a context: add freeze/thaw recalc
Some operations like deactivating nodes deactivates all links to the
node and this causes a graph recalc for each link.

It's actually a bit more problematic with suspend, which first
deactivates the links and then suspends the ports. The suspension of the
ports cause a recalc, which for the not yet suspended ports makes the
link active again, causing issues then when the port is suspended later.

Make recalc a counter and only recalc when the counter is 0. If the
counter is not 0, set the pending recalc, which will trigger when the
counter goes to 0.

With this, we can add a freeze/thaw operation on the recalc and delay
recalculation until all ports and links are handled.

We can also group some other operations with a freeze/thaw pair, such as
the destruction of ports, which destroys all links. Also the destruction
of nodes can freeze the recalc until all ports are destroyed.
2026-06-18 17:59:13 +02:00
Wim Taymans
13c5e3c756 pulse-server: add a pulse.zeroramp.gap property
Add a new pulse.zeroramp.gap property that will enable gap detection and
fade-in/fade-out on gaps on playback streams.

Make a rule to enable this on chrome, which does not do a cork/pause
when a stream is paused but sends out silence. With the gap detection
enabled, this allows the audioconvert to perform fades to avoid pops and
clocks from sudden DC changes at the gaps.

Fixes #4745
2026-06-17 17:17:54 +02:00
Wim Taymans
8971c488f3 audioconvert: add zeroramp and gap detection to audioconvert
Make a new zeroramp.duration and zeroramp.gap property on audioconver.
It detects N samples of silence before triggering a fade-in or fade-out
of the given zeroramp.duration.

The zeroramp.duration is by default 5ms and zeroramp.gap is set to 0.

When the zeroramp.gap is set to 0, the audioconver will not do any gap
detection but it will only do fade-out from the last sample when the IO
Buffer area is removed from a port.

This by default makes the audio adapter perform a fade-out when the last
input of the port mixer was removed and the mixer is no longer scheduled
and the IO Area removed from the audioconverter input port.
2026-06-17 17:11:42 +02:00
Wim Taymans
c2083336a4 impl-port: pass the zeroramp.duration to the mixer
Pass the zeroramp.duration property from the node to the port and then
to the mixer so that it can be configured.

Add the zeroramp.duration to the docs.
2026-06-17 17:08:50 +02:00
Wim Taymans
9a19091ac7 buffers: tweak some limits
Allow max 64 metadatas on a buffer
2026-06-16 18:24:14 +02:00
Torkel Niklasson
1a638fba60 module-client-node: Remove unused MAX defines
Cleanup of previous commit based on merge request !2865
2026-06-16 17:55:22 +02:00
Torkel Niklasson
650a96b8aa module-client-node: allocate port mix buffers dynamically
Each port mix embedded its buffer table in struct mix as a fixed array
buffers[MAX_BUFFERS] (MAX_BUFFERS == 64), and every struct buffer in turn
embedded datas[MAX_DATAS] (MAX_DATAS == 256) and metas[MAX_METAS]. This
reserved ~674 KB per mix in create_mix() regardless of the actual buffer,
data and meta counts, multiplied by every port mix (one per link end).

Turn buffers, datas and metas into pointers and allocate the buffer table
together with the per-buffer data and meta pools in a single calloc in
do_port_use_buffers(), sized to the real number of buffers and their
n_datas/n_metas, and release it in clear_buffers(). create_mix() now starts
with an empty (NULL) table, so an idle mix costs only the struct header.
This mirrors the dynamic-allocation approach already used for the
audioconvert and audiomixer port buffers and removes the dominant heap and
mmap consumer in the client-node graph.

Co-authored-by: Copilot <copilot@github.com>
2026-06-16 16:11:06 +02:00
Carlos Rafael Giani
f904168433 module-rtp: Copy sess.ts-direct in RTP sink and add direct ts documentation
In the past, it made no difference whether or not an RTP sink's
sess.ts-direct property was set to true. This changed in commit
6bf81ebe59 . Now, sess.ts-direct must be
set to true if an associated RTP source is using direct timestamp mode.
That's because when the RTP sink's direct timestamp mode is not enabled,
it will set the new internal ts_align offset to a nonzero value, which
then corrupts timestamps and causes out of sync playback in the RTP
sources.

Also, copy the sess.ts-direct property from the global RTP sink props
to the stream props to match the behavior of the RTP source module.
2026-06-14 22:05:30 +02:00
Carlos Rafael Giani
e85e8d8c31 module-rtp: Minor cleanup
* Rename do_disconnect to do_disconnect_core, since the original name
  is ambiguous (it can be interpreted as being about disconnecting
  a network socket).
* impl->session_name is not used at all, so remove it.
2026-06-14 22:05:30 +02:00
Carlos Rafael Giani
222c8753d1 module-rtp: Convert received packet SSRC from network to host byte order 2026-06-14 22:05:30 +02:00
Carlos Rafael Giani
8f8183e266 module-rtp: Move incoming RTP packet checks to rtp_stream_receive_packet()
This fixes code duplication, since the checks are the same regardless
of payload type. hlen is also calculated the same across payload types,
so it is moved as well. The impl->receive_rtp() function pointer then
solely addresses the actual payload processing.
2026-06-14 22:05:30 +02:00
Carlos Rafael Giani
61e78b25ef module-rtp: Clarify audio info variables and modify info for Opus and MIDI
Rename format_info to rtp_format_info to make the purpose of that struct
and the associated variable clearer.

Document what info and stream_info are there for, since their purpose
is not immediately obvious.

Using find_audio_format_info() for Opus and MIDI makes no sense, since
both of these only have one info each, which is always found, so one might
as well just use that single, always-matching RTP format info directly.
This means that the audio_format_info array remains there solely for PCM,
so rename it to rtp_pcm_audio_format_info.
2026-06-14 22:05:30 +02:00
Martin Geier
7f7fc2f77a module-rtp: allow dynamically enable or disable announcements 2026-06-14 22:05:30 +02:00
Martin Geier
f935eb255c module-rtp: make audio buffer size configurable
Add new sess.buffer-size property that can override default 1<<22b buffer
size.
2026-06-14 12:01:34 +02:00
Carlos Rafael Giani
e7563b19b6 module-rtp: Add calculate_seqnum_delta() utility function 2026-06-14 12:01:34 +02:00
Wim Taymans
b5555cc3f6 port-config: add internalFormat to PortConfig
Use the Format for all possible formats on the
EnumPortConfig and the configured external format on PortConfig.

Make a new internalFormat that contains the configured format of the
adapter follower.

Make pw-top use the PortConfig internalFormat in the FORMAT view and fall
back to Format, when not available (for older clients).
2026-06-12 17:50:46 +02:00
Wim Taymans
d780f4f535 Reapply "pw-top: use PortConfig to get the node format"
This reverts commit 91bc0adc07.
2026-06-12 14:36:09 +02:00