Because our midi messages already have a size, we don't need the 0xf0
continuation terminator. Also having the terminator optionally requires
you to check and strip it if it's there.
The easiest algorithm is to check the first byte for start (0xf0) or
continuation (0xf7) and the last byte for end (0xf7) and that should be
enough to process the messages without having to ever stip the last
byte.
Bring the port to INIT before going to CONFIGURE when we do the suspend
logic.
This is to ensure that there always is a state change to emit the state
change notification. This was, the link can detect the suspend case and
cancel any pending results.
One of the problem with suspend is that the state changes on the ports
are done from different places; the port and link. This causes issues
like:
1. do_negotiate calls pw_port_set_param(Format,..) with the negotiated
format. This returns async and the link queues a complete_ready
callback.
2. The node is suspended, pw_impl_port_set_param(Format, NULL) is called
to clear the port format. This bypasses the link.
3. The reply from step 2 arrives and triggers complete_ready, this
brings the port state to READY and the link state to ALLOCATING.
4. The link continues allocating and sets buffers on the port. This then
fails because the last format set was NULL.
Ideally all port states should be managed in one place and the async
port state changes should be kept in the port itself as well but this
will need some more work.
Fixes#3547
Thse should not be portal clients and can go directly to rtkit.
The reason is that there is a locking problem in the portal rt
implementation that cause timeouts for some reason.
Retrieve the connecting client's supplementary group list via
SO_PEERGROUPS and store it as the "pipewire.sec.gids" property.
This allows access-control policies in wireplumber to match on
all groups and not just the primary.
A passive port is not automatically activated anymore by an active peer
node, it now needs the "follow" mode to follow the state of the peer without
activating it.
Keep the flag dont_inhibit_auto_suspend around and use it do decide when
to send suspend messages to the client.
We don't always want to send suspend messages when the stream state changes
because that could happen because the stream was, for example, relinked.
The intention of the suspend message is mostly for monitor streams that
use the dont-inhibit flag and want to follow the suspend state of the
sink.
See #5273
Instead of just setting the port state directly, go through the
port_update_state() function. This will make suspend_node() also
emit the port state change event to the links. This then causes
the link to reset to INIT, which cancels pending complete_ready work
items and prevents them from changing the port to READY without a
valid format.
One possible situation where this could happen is when a suspend
happens while the port was waiting for a set_param(Format) reply from
the client-node.
See #3547
This is meant to workaround a particular SoF firmware crash that requires the
device to be closed and re-opened to recover. This works in combination
with a WirePlumber monitor function that will destroy the node after
it enters this error state and will re-create it.
Add coverage for channel pressure, system common messages (F1, F2, F3),
system realtime, MIDI 1.0 program change and channel pressure decoding,
sysex continue status, and roundtrip tests for program change, channel
pressure, song position, and system realtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix spa_ump_to_midi() MIDI 2.0 pitch bend (0xE0) to extract both LSB
and MSB from the 32-bit value in word 2, giving full 14-bit resolution.
Previously the LSB came from a reserved field and was always zero.
Mask the program number with 0x7f for consistency with bank byte
masking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix spa_ump_to_midi() MIDI 2.0 channel pressure (0xD0) to emit the
status byte before the data byte. The fallthrough from default caused
the status to be missing, producing 1 byte instead of 2.
Mask bank MSB and LSB with 0x7f in MIDI 2.0 program change conversion
to ensure valid MIDI 1.0 data bytes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix spa_ump_from_midi() to correctly encode short sysex messages as
Complete (0x0) instead of Start (0x1) when the entire message fits in
one UMP packet. Handle bare F7 termination when no data bytes follow.
Support 0xF7 as a sysex continuation marker and optional trailing 0xF0
as a continuation boundary.
Add unit tests for UMP/MIDI conversion covering note on, program change,
sysex complete/multi-packet/continue, system realtime, F7 continuation,
bare F7 end/complete/orphan, and trailing F0 scenarios.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This is not strictly required because our control events have a size and
don't need the 0xf0 trailing byte to find the boundary.
It also makes it easier to just use the midifile events directly without
having to add the 0xf0.
Pass the max size of the buffer to the fill function.
Use this for writing midi events in the buffer. We can use the total
buffer size for midi events.
The n_frames is to limit the amount of midi events *in time*, not in
bytes.
When writing sysex, bypass the encoder and simply place the sysex
message in the seq queue. Make sure strip off the 0xf7 and 0xf0
continuation bytes.
When reading sysex, bypass the decoder and append/prepend the
continuation bytes.
This way, we can make the decoder buffer size back to something small
(large enough for one simple midi event) and we can handle arbitrary
sysex message lengths.