Commit graph

7542 commits

Author SHA1 Message Date
Christian F.K. Schaller
ef4ff8cfd0 test: add AVB protocol test suite with loopback transport
Add a test suite for the AVB (Audio Video Bridging) protocol stack that
runs entirely in software, requiring no hardware, root privileges, or
running PipeWire daemon.

The loopback transport (avb-transport-loopback.h) replaces raw AF_PACKET
sockets with in-memory packet capture, using a synthetic MAC address and
eventfd for protocol handlers that need a valid fd.

Test utilities (test-avb-utils.h) provide helpers for creating test
servers, injecting packets, advancing time, and building ADP packets.

Tests cover:
- ADP entity available/departing/discover/timeout
- MRP attribute lifecycle (create, begin, join)
- Milan v1.2 mode server creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
a73988d38d module-avb: add transport abstraction for pluggable network backends
Introduce struct avb_transport_ops vtable with setup/send_packet/
make_socket/destroy callbacks. The existing raw AF_PACKET socket code
becomes the default "raw" transport. avdecc_server_new() defaults to
avb_transport_raw if no transport is set, and avdecc_server_free()
delegates cleanup through the transport ops.

This enables alternative transports (e.g. loopback for testing) without
modifying protocol handler code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
d9821d09c7 module-avb: fix Milan lock entity error response and re-lock timeout
Fix two bugs in handle_cmd_lock_entity_milan_v12():

1. When server_find_descriptor() returns NULL, reply_status() was called
   with the AEM packet pointer instead of the full ethernet frame,
   corrupting the response ethernet header.

2. When refreshing an existing lock, the expire timeout was extended by
   raw seconds (60) instead of nanoseconds (60 * SPA_NSEC_PER_SEC),
   causing the lock to expire almost immediately after re-lock.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
4e62826e01 module-avb: fix legacy AECP handlers reading payload at wrong offset
handle_acquire_entity_avb_legacy() and handle_lock_entity_avb_legacy()
incorrectly treated the full ethernet frame pointer as the AEM packet
pointer, causing p->payload to read descriptor_type and descriptor_id
from the wrong offset. Fix by properly skipping the ethernet header,
matching the pattern used by all other AEM command handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
3f386ecd34 module-avb: fix ACMP error responses sent with wrong message type
In handle_connect_tx_command() and handle_disconnect_tx_command(),
AVB_PACKET_ACMP_SET_MESSAGE_TYPE() is called after the goto done
target. When find_stream() fails and jumps to done, the response
is sent with the original command message type (e.g., CONNECT_TX_COMMAND)
instead of the correct response type (CONNECT_TX_RESPONSE).

Move the SET_MESSAGE_TYPE call before find_stream() so error responses
are always sent with the correct response message type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
1d0c51f057 module-avb: fix MRP NEW messages never being transmitted
AVB_MRP_SEND_NEW was defined as 0, making it indistinguishable from
"no pending send" in the MSRP and MVRP event handlers which check
`if (!pending_send)`. This meant that when an attribute was first
declared (applicant state VN or AN), the NEW message was silently
dropped instead of being transmitted on the network.

Fix by shifting all AVB_MRP_SEND_* values to start at 1, so that 0
unambiguously means "no send pending". Update the MSRP and MVRP
encoders to subtract 1 when encoding to the IEEE 802.1Q wire format
(which uses 0-based event values).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
ef8f820d4a module-avb: fix potential NULL pointer dereference in MSRP/MVRP notify
The msrp_notify() and mvrp_notify() functions call dispatch table
notify callbacks without checking for NULL. In MSRP, the
TALKER_FAILED attribute type has a NULL notify callback, which would
crash if a talker-failed attribute received a registrar state change
notification (e.g. RX_NEW triggering NOTIFY_NEW).

Add NULL checks before calling the dispatch notify callbacks, matching
the defensive pattern used in the encode path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
bdaecfebb8 module-avb: fix heap corruption in server_destroy_descriptors
server_add_descriptor() allocates the descriptor and its data in a
single calloc (d->ptr = SPA_PTROFF(d, sizeof(struct descriptor))),
so d->ptr points inside the same allocation as d. Calling free(d->ptr)
frees an interior pointer, corrupting the heap. Only free(d) is needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Wim Taymans
20d648aaad filter-chain: don't corrupt the enumerated properties
When we add a Format property after we dereffed all the other params in
the builder, we might relocate the builder memory and invalidate all
previously dereffed params, causing corruption.

Instead, first add all the params to the builder and then deref the
params.

There is a special case when we have both a capture and playback
stream. The capture stream will receive all filter params and the
playback stream will just receive its Format param.

Fixes #5202
2026-04-08 17:49:41 +02:00
Wim Taymans
0f00ad19cb tools: clean up the preset filter code 2026-04-08 15:01:11 +02:00
pallaswept
bf7f2a5d88 pw-top: filter by status 2026-04-08 12:47:08 +00:00
Wim Taymans
49073cf527 port: improve parsing of passive modes
Make a function to parse the passive mode and use that in ports and
nodes. Improve the node passive mode parsing a little.

Also make Duplex nodes follow-suspend.
2026-04-08 14:07:57 +02:00
Wim Taymans
446e36807f port: debug passive modes better 2026-04-08 13:21:24 +02:00
Wim Taymans
7012594926 dlopen: improve prefix check some more
If we pass a path /usr/libevil/mycode.so, it might have a prefix of
/usr/lib but we should still reject it. Do thi by checking that after
the prefix match, we start a new directory.
2026-04-08 12:00:04 +02:00
Wim Taymans
0e0c325194 fix some uninitialized variables warnings 2026-04-08 11:29:36 +02:00
Wim Taymans
abd8c8f666 test: fix pod size
It's at least 24 bytes, 8 for struct header, 8 for int header and 8 for
int data.
2026-04-08 11:28:04 +02:00
Wim Taymans
1a3df16e27 mem: handle overflow in pw_map_range_init()
Integer overflows can result in map_range_init() to return wrong offset
or size that can result in access to invalid or unmapped memory.

Check for the overflows and return an EOVERFLOW error.

Found by Claude Code.
2026-04-08 09:47:57 +02:00
Wim Taymans
d7be4353ad tools: avoid strcat in pw-cat
We might overflow the path buffer when we strcat the provided filename
into it, which might crash or cause unexpected behaviour.

Instead use spa_scnprintf which avoids overflow and properly truncates
and null-terminates the string.

Found by Claude Code.
2026-04-07 18:44:43 +02:00
Wim Taymans
337801717e test: add unit test for fds mismatch 2026-04-07 18:31:56 +02:00
Wim Taymans
c9ecbf9fab protocol-native: check msg fds against available fds
Check that the number of fds for the message does not exceed the number
of received fds with SCM_RIGHTS.

The check was simply doing an array bounds check. This could still lead
to out-of-sync fds or usage of uninitialized/invalid fds when the
message header claims more fds than there were passed with SCM_RIGHTS.

Found by Claude Code.
2026-04-07 18:20:26 +02:00
Wim Taymans
50aacea749 plugins: allow some absolute paths
Allow abosulte paths as long as they start with one of the search paths.
2026-04-07 09:44:22 +02:00
Wim Taymans
785bf36b9b docs: remove support for absolute paths from docs 2026-04-06 14:47:21 +02:00
Wim Taymans
8fd7982087 only dlopen from the defined search paths
Don't accept absolute library paths and skip the ../ in paths to avoid
opening arbitrary libraries from unexpected places.
2026-04-06 14:20:56 +02:00
Wim Taymans
6b0248d68c Revert "impl-node: Don't suspend when links are busy"
This reverts commit bb0efd777f.

It is unclear what the problem was before this commit. If there are any
pending operations, the suspend should simply cancel them.

See #5207
2026-04-06 10:39:15 +02:00
Martin Geier
54c517b2d9 module-rtp: Add more logging for debugging timer related issues 2026-03-30 23:45:34 +02:00
Carlos Rafael Giani
0121bdc475 module-rtp: Lower missing timeout log line from warn to trace
A warning is not warranted in this case, and this log line can spam
the logs, so set it to trace.
2026-03-30 23:45:34 +02:00
Carlos Rafael Giani
5b86e3d418 module-rtp-source: Only enable IGMP recovery when using multicast
IGMP recovery makes no sense with unicast IP addresses.
2026-03-30 23:45:34 +02:00
Carlos Rafael Giani
3080bca85a module-rtp-source: Fix unicast by-address packet filtering
Using connect() on a UDP receiver creates a strict filter based on
the sender's _source_ port, not the sender's destination port. The
source port specifies at what sender port the packet exits the sender.
The destination port specifies at what receiver port the packet enters
the receiver. But, the RTP sink uses an ephemeral (= random) port as the
source port. Consequently, connect() at the receiver will cause a
comparison of that ephemeral port with the fixated one (which is actually
the number of the _destination_ port). This incorrect filtering causes
all packets to be dropped.

Use bind() to filter for the local destination port, and use recvmsg()
with manual IP comparison to filter for the sender's identity.
2026-03-30 23:45:34 +02:00
Carlos Rafael Giani
41b5bc662e network-utils: pw_net_are_addresses_equal() function 2026-03-30 23:45:33 +02:00
Wim Taymans
18c97222c4 channelmix: make up/downmix levels configurable
Add channelmix.center-level, channelmix.surround-level and
channelmix.lfe-level to control how center, surround and LFE is
up/downmixed.

Fixes #5198
2026-03-30 17:50:48 +02:00
Wim Taymans
60062432b8 module-rtp: handle the send_packet/feedback as callbacks
They are emited from the streaming thread and therefore can be emitted
concurrently with the events on the main thread. This can cause crashes
when the hook list is iterated.

Instead, make those events into callbacks that are more efficient,
and threadsafe.
2026-03-26 09:34:45 +01:00
Wim Taymans
50fcf64058 tools: add -C | --monitor to pw-cat
It sets the stream.capture.sink property which makes a record stream
capture from a sink monitor instead.
2026-03-25 18:06:17 +01:00
Wim Taymans
9eeb2f1930 mixer: handle control.ump property
Add a control.ump port property. When true, the port wants UMP and the
mixer will convert to it. When false, the port supports both UMP and
Midi1 and no conversions will happen. When unset, the mixer will always
convert UMP to midi1.

Remove the CONTROL_types property from the filter. This causes problems
because this is the format negotiated with peers, which might not
support the types but can still be linked because the mixer will
convert.

The control.ump port property is supposed to be a temporary fix until we
can negotiate the mixer ports properly with the CONTROL_types.

Remove UMP handling from bluetooth midi, just use the raw Midi1 events
now that the mixer will give those and we are supposed to output our
unconverted format.

Fix midi events in-place in netjack because we can.

Update docs and pw-mididump to note that we are back to midi1 as the
default format.

With this, most of the midi<->UMP conversion should be gone again and we
should be able to avoid conversion problems in ALSA and PipeWire.

Fixes #5183
2026-03-25 11:59:43 +01:00
Wim Taymans
7fe191bc10 buffers: handle 0 result from Buffers param enumeration
Since abf37dbdde the param enumeration in
the client-node can return 0 when the parameter is supported but there
are no params uploaded.

When negotiating buffers we need to assume a 0 result as a NULL filter
as well or else we will error.
2026-03-25 11:59:43 +01:00
Wim Taymans
ea28343166 midi: don't convert Midi in nodes
Avoid doing conversions in the nodes between Midi formats, just assume
the imput is what we expect and output what we naturally produce.

For ALSA this means we produce and consume Midi1 or Midi2 depending on the
configurtation.

All of the other modules (ffado, RTP, netjack and VBAN) really only
produce and consume MIDI1.

Set the default MIDI format to MIDI1 in ALSA.

Whith this change, almost everything now produces and consumes MIDI1
again (previously the buffer format was forced to MIDI2).

The problem is that MIDI2 to and from MIDI1 conversion has problems in
some cases in PipeWire and ALSA and breaks compatibility with some
hardware.

The idea is to let elements produce their prefered format and that the
control mixer also negotiates and converts to the node prefered format.
There is then a mix of MIDI2 and MIDI1 on ports but with the control
port adapting, this should not be a problem.

There is one remaining problem to make this work, the port format is
taken from the node port and not the mixer port, which would then expose
the prefered format on the port and force negotiation to it with the
peer instead of in the mixer.

See #5183
2026-03-25 11:59:43 +01:00
Wim Taymans
d47b4974ce impl-node: add () around &&
To fix a compiler warning.
2026-03-23 11:55:05 +01:00
Martin Geier
52b23384e0 impl-node: correctly synchronize suspend state with remote node
Previously, if a remote node was set to running and immediately reverted
to suspended state, the remote node stayed in running state. This occurred
because suspend_node sent suspend command only when the locally cached
state was "idle" or "running."

Modified to send suspend to a node whenever its pending state is not
"suspended," ensuring the command is sent during state transitions.

Fixes #5026

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2026-03-23 11:41:09 +01:00
Wim Taymans
b16a2e41e8 scheduler: remove sync group from runnable calculations
The sync group is only to group nodes when sync is enabled.
2026-03-18 13:19:04 +01:00
Wim Taymans
6bf81ebe59 modules: align rtp_timestamps for sender
When the driver changes, the clock position can also change and there
would be a discont in the rtp_timestamp.

This is not usually a problem except in RAOP mode where the base rtp
timestamp is negotiated and anything that deviates too much is to be
discarded.

If we are not using direct_timestamp for the sender, make sure we always
keep the rtp_time aligned to avoid this problem.

See #5167
2026-03-17 14:05:09 +01:00
Wim Taymans
f4587ea434 modules: improve debug in RTP 2026-03-17 14:05:09 +01:00
Wim Taymans
8db1153519 modules: remove some unused fields 2026-03-17 14:05:09 +01:00
Robert Rosengren
e5809ee052 pipewiresrc: fix wait_negotiated from change_state
Going from PLAYING to PAUSED will have basesrc calling unlock and
setting flushing to false. Going back to PLAYING may then fail in
wait_negotiated, as unlock_stop will be called after change_state.

Fix by remove the flushing check, since already in that "state".
2026-03-16 17:08:44 +00:00
Wim Taymans
b1b5653393 sendspin: negotiate the first raw format
Flac and Opus are not supported yet.
2026-03-13 12:03:11 +01:00
Wim Taymans
95eac7b4e5 scheduler: add comment about the FOLLOW_SUSPEND special case 2026-03-12 18:12:42 +01:00
Wim Taymans
e4e5f62d44 impl-node: accept more node.passive values
So that we can set separate values for in and out ports.

The node.passive=follow mode is a good idea for a filter.
2026-03-12 17:25:36 +01:00
Wim Taymans
3e209f6d20 modules: try to improve code readability some more 2026-03-12 14:57:23 +01:00
Wim Taymans
41520f1022 modules: remove a warning 2026-03-12 14:44:34 +01:00
Wim Taymans
ca91b368c1 impl-port: make a follow-suspend port mode
It's like the follow mode but when you link 2 follow-suspend ports
together, they will activate eachother.

This is to make Source -> Sink links work.
2026-03-12 14:40:04 +01:00
Wim Taymans
45e3af5cdc impl-port: make passive mode as an enum
Hopefully easier to understand.
2026-03-12 13:46:49 +01:00
Wim Taymans
ad195b289a modules: try to document the passive ports better 2026-03-12 12:13:43 +01:00