Commit graph

3615 commits

Author SHA1 Message Date
Carlos Rafael Giani
1096d63468 module-rtp-source: implement IGMP recovery for multicast subscription loss
Add IGMP recovery mechanism that monitors RTP packet reception and
triggers multicast group refresh when no packets are received if
a deadline is reached. The deadline is configurable via a new stream
property "igmp.deadline.sec" (in seconds), with the default value
being 30 seconds (and a minimum of 5 seconds).

A timer checks regularly if the deadline was reached. That timer's
interval is set by the igmp.check.interval.sec property (in seconds),
with the default value being 5 seconds (and a minimum of 1 second).

When the deadline is reached, the mechanism performs IGMP leave/rejoin
operations to refresh multicast group membership. This ensures RTP
data continues to be received when network conditions cause IGMP
membership to expire or become stale due to router timeouts or
network issues.
2025-10-27 22:40:22 +01:00
Carlos Rafael Giani
955c9ae837 module-rtp: Get the current stream time in a reusable manner
That way, redundant pw_stream_get_nsec() and clock_gettime()
calls can be avoided.
2025-10-27 22:40:22 +01:00
Carlos Rafael Giani
3e0f4daf60 module-rtp-sap: implement IGMP recovery for multicast subscription loss
Add IGMP recovery mechanism that monitors SAP packet reception and
triggers multicast group refresh when no packets are received if
a deadline is reached. The deadline is set to half of the cleanup
interval, with a minimum of 1 second.

When the deadline is reached, the mechanism performs IGMP leave/rejoin
operations to refresh multicast group membership. This ensures SAP
announcements continue to be received when network conditions cause
IGMP membership to expire or become stale due to router timeouts or
network issues.
2025-10-27 22:40:22 +01:00
Carlos Rafael Giani
5d21e12658 module-rtp-source: Use make_socket() error value instead of errno
make_socket() already returns the negative errno.
2025-10-27 22:14:09 +01:00
Carlos Rafael Giani
f1ffd5e5e8 module-rtp-source: Read cleanup.sec property from stream properties
This allows for setting the cleanup.sec value in the create-stream
block in the module-rtp-sap configuration.
2025-10-27 22:14:09 +01:00
Carlos Rafael Giani
80e7302a05 module-rtp-sap: Add retry code for when start_sap() fails due to ENODEV 2025-10-27 22:14:09 +01:00
Carlos Rafael Giani
b57bd00be0 module-rtp-sap: Improve names for clearer code 2025-10-27 22:14:09 +01:00
Rui Matos
c1e737bbe4 module-rtp: Attempt to reconnect the ptp management socket
This should gracefully recover the cases where the other end of the
socket isn't ready yet when we start or terminates and gets restarted.
2025-10-27 18:08:00 +01:00
Jonas Holmberg
76a31a47c2 module-echo-cancel: Avoid discontinuity
Keep the samples in the ringbuffer that are needed the next cycle to
avoid discontinuity when the aec blocksize is not equal to or divisible
by quantum.
2025-10-27 14:39:29 +01:00
Wim Taymans
0276bb5b06 modules: ringbuffer avail is signed 2025-10-27 11:43:04 +01:00
Jonas Holmberg
614186a590 module-echo-cancel: Sync capture and sink buffers
Call process() when capture and sink ringbuffers contain data from the
same graph cycle and only process the latest block from them to avoid
adding latency that can accumulate if one of the streams gets more than
one buffer before the other gets its first buffer when starting up.
2025-10-27 08:43:08 +01:00
Wim Taymans
aa0272f6f3 treewide: remove some obsolete channel checks
The spa_audio_info can not be parsed with too many channels so there
is always enough space for the positions.
2025-10-24 10:31:45 +02:00
Wim Taymans
78219471ff spa: remove some obsolete functions
The spa_audio_info array now always holds enough positions for all
channels and we don't need to wrap around.
2025-10-24 09:35:59 +02:00
Wim Taymans
5e1e3fca1e modules: handle format parsing errors 2025-10-23 18:01:35 +02:00
Wim Taymans
11f1298f53 spa: make a function to make a channel short name
Make a function that can generate and parse a short name for
the positions that are not in the type list, like the AUX channels.
2025-10-22 13:04:53 +02:00
Wim Taymans
dbc5c81e4a spa: avoid using SPA_AUDIO_MAX_CHANNELS
Use SPA_N_ELEMENTS instead of the array we try to handle.
2025-10-21 16:05:33 +02:00
Wim Taymans
818d1435ce treewide: access the position information using helpers
Make sure we don't access out of bounds and that we use the helpers
wherever we can to access the position information.
2025-10-21 13:06:25 +02:00
Wim Taymans
8bbca3b8f3 spa: add spa_audio_parse_position_n
Add a function that accepts the size of the position array when reading
the audio positions. This makes it possible to decouple the position
array size from SPA_AUDIO_MAX_CHANNELS.

Also use SPA_N_ELEMENTS to pass the number of array elements to
functions instead of a fixed constant. This makes it easier to change
the array size later to a different constant without having to patch up
all the places where the size is used.
2025-10-21 09:59:13 +02:00
Wim Taymans
13b8c23767 Don't use SPA_AUDIO_MAX_CHANNELS directly
Make a MAX_CHANNELS define and use that one in code. This makes it
easier to change the constant later.
2025-10-21 09:43:06 +02:00
Wim Taymans
f453b1545d audio: don't use SPA_AUDIO_MAX_CHANNELS in some places
When we know the max size of the array, just use this instead of the
SPA_AUDIO_MAX_CHANNELS constant.
2025-10-20 18:31:17 +02:00
Wim Taymans
fb49759d1f module-echo-cancel: drop samples when source not ready
When we can't dequeue a buffer from the source stream, drop the samples
instead of leaving them queued in the ringbuffer.
2025-10-17 14:51:14 +02:00
Wim Taymans
a75cea96fb modules: port modules to timer-queue
Instead of using timerfd, use the context timer-queue to schedule
timeouts. This saves fds and removes some redundant code.

Make the rtp-source timeout and standby code a bit better by using
atomic operations.
2025-10-15 16:57:24 +02:00
Wim Taymans
b220f85790 module-rtp-sap: reorganize generation of SDP
Move the code to recalculate the hash and version into make_sdp. Add a
boolean argument to the make_sdp function. Recalculate the hash and
version when we are making a new SDP and leave the old values if we
are making an SDP to compare against the current one.
2025-10-15 14:08:24 +02:00
Wim Taymans
c40e0d1d98 module-rtp: unset ptp_fd or else we might close it 2025-10-15 14:05:29 +02:00
Wim Taymans
7d781e696f profiler: avoid null dereference
Avoid shadowing some variables from the parent block.

The node of a target can be NULL when the target is running in another
instance. We already do some checks for this but make sure we never
deref the NULL pointer.

Fixes #4922
2025-10-06 14:38:38 +02:00
Niklas Carlsson
3f9ae1ee10 filter-graph: allow 8 channels in max plugin
Mimic the same channel behavior as for other plugins that allows
for 8 channels, such as Mixer and Mult.
2025-09-29 14:11:27 +00:00
Wim Taymans
468a9ac954 pulse-server: add the peer ip to client properties
When clients connect with IP, add the peer IP address to properties. We
might use this later to make a better stream node.name than a copy of the
client application name.
2025-09-29 09:39:57 +02:00
Wim Taymans
fdc74df383 modules: use timer-queue in avahi-poll
Pass the pw_context to get to the shared queue and loop.
Patch up the users of avahi-poll.

Fixes #4913
2025-09-26 13:39:49 +02:00
Wim Taymans
9be06c46b7 pulse-server: fix case statement 2025-09-26 11:43:52 +02:00
Wim Taymans
17cad8e7ef pulse-server: add a help message
Shows all available messages on /core because I keep forgetting.
2025-09-26 10:57:04 +02:00
Wim Taymans
5a894270e6 pulse-server: add a pipewire-pulse:list-modules message
It list all available module names, which you can then describe further.
Make a little module_info iterator function for this.
2025-09-26 10:55:10 +02:00
Wim Taymans
ecac86b0ca avahi: handle fd allocation errors
When we fail to allocate an io source or a timerfd, return NULL instead
of crashing later on.

See #4913
2025-09-26 10:52:40 +02:00
Wim Taymans
06214b6087 pulse-server: map some more errno to errors
Mostly EADDRINUSE to ERR_BUSY, which happens when loading TCP when
it's already loaded on the address.
2025-09-26 10:50:52 +02:00
Carlos Rafael Giani
65e49b38d1 module-rtp: Add process.latency.from.sess prop to set process latency 2025-09-24 22:54:06 +02:00
Carlos Rafael Giani
63df661eff module-rtp: Handle Latency and ProcessLatency in stream 2025-09-24 22:54:06 +02:00
Wim Taymans
06efc8ffb6 pulse-server: clear timer when stream is created
Make a function when the stream is created so that we can clear the
create_tag and the timer.
2025-09-18 14:22:00 +02:00
Wim Taymans
ca713c08ee pulse-server: use the new timer-queue for timeouts
Use the timer queue for scheduling stream and object data timeouts.

This avoids allocating timerfds for these timeouts and the timer queue
can handle many timeouts more efficiently.
2025-09-18 13:55:43 +02:00
Wim Taymans
361a0de85a pulse-server: make timer function static and fix formatting 2025-09-17 19:18:27 +02:00
Arun Raghavan
cfde4c1b17 pulse: Handle timed out streams
If we don't get a link on a stream, we might never send a create stream
reply. The client handles this fine by timing out after 30s and dropping
the stream, but the server holds on to the pw_stream forever (or until
the client quits).

Let's add a timer to clean up such streams on the server.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4901
2025-09-17 11:48:27 -04:00
Wim Taymans
336b2dbbc2 modules: remove output latency handling in raop sink
pw_stream now handles the other (output) latency for us, it will keep
the param and report it. If we are not interested in upstream latency we
don't have to parse and store it and we can just be concerned with the
latency we report on our input port (input latency).
2025-09-16 09:29:43 +02:00
Wim Taymans
f89428d9f8 tools: print async node state in pw-top
Pass the node async state in the profiler and use this in pw-top to draw
the node with = instead of a + in the tree when it's async.
2025-09-15 12:29:57 +02:00
Wim Taymans
1bf5ca28d8 modules: nmake dynamic ports work in link-factory
Just making a port and adding it to a node does not make it a working
port..

Make a new node function to get a new free port, this will actually call
the implementation spa_node_add_port(), which will add the new port
which we can then pick up and use.

See #4876
2025-09-03 10:38:59 +02:00
Wim Taymans
370d190572 pulse: improve stream suspended state handling
Only send out SUSPENDED event when there is a change in the suspended
state. This avoids sending out unsuspend events when we simply uncork.

Implement the fail_on_suspend flag for capture and playback streams.
Instead of suspending those streams, we need to kill them.
2025-09-01 12:55:51 +02:00
Wim Taymans
6c110a3b18 raop: write ALAC end tag
Fixes #4853
2025-08-28 12:17:52 +02:00
Carlos Rafael Giani
caf72fd9bc module-rtp: Synchronize access to timer_running flag 2025-08-25 10:33:50 +00:00
Carlos Rafael Giani
37e597ff0a module-rtp: Replace "started" boolean with internal state enum
The started boolean is insufficient to fully cover the possible internal
states. For this reason, it needs to be replaced by an enum that covers
these states.

Also, due to potential access by both the dataloop and the mainloop,
access to that internal state needs to be synchronized.

Finally, a variable "internal_state" makes for code that is easier to
read, since it emphasizes that this is state that is fully internal
inside the stream (and is not visible to the rtp-sink and rtp-source
modules for example).
2025-08-25 10:33:50 +00:00
Carlos Rafael Giani
3476e77714 module-rtp: Replace state_changed callbacks
The state_changed callbacks fulfill multiple roles, which is both a problem
regarding separation of concerns and regarding code clarity. De facto,
these callbacks cover error reporting, opening connections, and closing
connection, all in one, depending on a state that is arguably an internal
stream detail. The code in these callbacks tie these internal states to
assumptions that opening/closing callbacks is directly tied to specific
state changes in a common way, which is not always true. For example,
stopping the stream may not _actually_ stop it if a background send timer
is still running.

The notion of a "state_changed" callback is also problematic because the
pw_streams that are used in rtp-sink and rtp-source also have a callback
for state changes, causing confusion.

Solve this by replacing state_changed with three new callbacks:

1. report_error : Used for reporting nonrecoverable errors to the caller.
   Note that currently, no one does such error reporting, but the feature
   does exist, so this callback is introduced to preserve said feature.
2. open_connection : Used for opening a connection. Its optional return
   value informs about success or failure.
3. close_connection : Used for opening a connection. Its optional return
   value informs about success or failure.

Importantly, these callbacks do not export any internal stream state. This
improves encapsulation, and also makes it possible to invoke these
callbacks in situations that may not neatly map to a state change. One
example could be to close the connection as part of a stream_start call
to close any connection(s) left over from a previous run. (Followup commits
will in fact introduce such measures.)
2025-08-25 10:33:50 +00:00
Carlos Rafael Giani
2f22c1d595 module-rtp: Stop any ongoing timer when starting stream 2025-08-25 10:33:50 +00:00
Barnabás Pőcze
882737b077 pipewire: module-link-factory: cancel async work in link's destroy event
When a link enters the "ERROR" state, it is scheduled for destruction in
`module-link-factory.c:link_state_changed()`, which queues `destroy_link()`
to be executed on the context's work queue.

However, if the link is destroyed by means of `pw_impl_link_destroy()`
directly after that, then `link_destroy()` unregisters the associated
`pw_global`'s event hook, resulting in `global_destroy()` not being called
when `pw_impl_link_destroy()` proceeds to call `pw_global_destroy()` some
time later. This causes the scheduled async work to not be cancelled. When
it runs later, it will trigger a use-after-free since the `link_data` object
is directly tied to the `pw_impl_link` object.

For example, if the link is destroyed when the client disconnects:

==259313==ERROR: AddressSanitizer: heap-use-after-free on address 0x7ce753028af0 at pc 0x7f475354a565 bp 0x7ffd71501930 sp 0x7ffd71501920
READ of size 8 at 0x7ce753028af0 thread T0
    #0 0x7f475354a564 in destroy_link ../src/modules/module-link-factory.c:253
    #1 0x7f475575a234 in process_work_queue ../src/pipewire/work-queue.c:67
    #2 0x7b47504e7f24 in source_event_func ../spa/plugins/support/loop.c:1011
    [...]

0x7ce753028af0 is located 1136 bytes inside of 1208-byte region [0x7ce753028680,0x7ce753028b38)
freed by thread T0 here:
    #0 0x7f475631f79d in free /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:51
    #1 0x7f4755594a44 in pw_impl_link_destroy ../src/pipewire/impl-link.c:1742
    #2 0x7f475569dc11 in do_destroy_link ../src/pipewire/impl-port.c:1386
    #3 0x7f47556a428b in pw_impl_port_for_each_link ../src/pipewire/impl-port.c:1673
    #4 0x7f475569dc3e in pw_impl_port_unlink ../src/pipewire/impl-port.c:1392
    #5 0x7f47556a02d8 in pw_impl_port_destroy ../src/pipewire/impl-port.c:1453
    #6 0x7f4755634f79 in pw_impl_node_destroy ../src/pipewire/impl-node.c:2447
    #7 0x7b474f722ba8 in client_node_resource_destroy ../src/modules/module-client-node/client-node.c:1253
    #8 0x7f47556d7c6c in pw_resource_destroy ../src/pipewire/resource.c:325
    #9 0x7f475545f07d in destroy_resource ../src/pipewire/impl-client.c:627
    #10 0x7f47554550cd in pw_map_for_each ../src/pipewire/map.h:222
    #11 0x7f4755460aa4 in pw_impl_client_destroy ../src/pipewire/impl-client.c:681
    #12 0x7b474fb0658b in handle_client_error ../src/modules/module-protocol-native.c:471
    [...]

Fix this by cancelling the work queue item in `link_destroy()`, which should
always run, regardless of the ordering of events.

Fixes #4691
2025-08-20 23:21:26 +02:00
Wim Taymans
e35a8554f8 control: improve UMP to Midi conversiom
Improve the spa_ump_to_midi function so that it can consume multiple UMP
messages and produce multiple midi messages.

Some UMP messages (like program changes) need to be translated into up
to 3 midi messages. Do this byt adding a state to the function and by
making it consume the input bytes, just like the spa_ump_from_midi
function.

Adapt code to this new world. This is a little API break..
2025-08-19 18:33:59 +02:00