Reverts alsa-mixer.c changes from 32a3ffc74. The comprehensive ACP
layer fix (bdb82be4e) handles all scenarios including pro-audio
profiles that bypass mixer paths, making this approach redundant.
IEC958 (S/PDIF, HDMI, DisplayPort) switches default to muted in ALSA
drivers, causing no audio output on digital devices.
While UCM configurations and mixer paths can handle IEC958 unmuting,
several scenarios lack coverage:
- Pro-audio profiles (bypass UCM and mixer paths by design)
- Devices without UCM configurations
- Devices with incomplete mixer path definitions
- Cards with multiple HDMI/DP outputs (indexed switches)
This ensures IEC958 switches are enabled during device activation and
port changes. The implementation uses the device mixer when available,
falls back to the card mixer for pro-audio profiles, and enables all
IEC958 switches regardless of index.
Safe for all configurations: the operation is idempotent and provides
defense-in-depth even when UCM or mixer paths handle it correctly.
Tested on AMD Rembrandt GPU with 3 HDMI outputs in pro-audio mode.
When selecting an HDMI/DisplayPort (IEC958) output path, the hardware
mute switch remains in kernel default state (muted), causing no audio
output despite correct software routing.
Root cause: pa_alsa_path_select() only sets mute switches when
mute_during_activation is enabled. No mixer paths enable this setting,
making the switch configuration code unreachable for IEC958 paths.
Solution: Always set mute switches to match device mute status after
path activation, regardless of mute_during_activation setting.
Testing: Added test-alsa-path-select tool to verify the fix.
- Loads mixer path and calls pa_alsa_path_select()
- Verifies switch states match expected values
- Tested on AMD Radeon HDMI and Realtek ALC257 analog
Manual verification:
- Before: IEC958 switch OFF, no audio
- After: IEC958 switch set correctly, audio works
This bug was inherited from PulseAudio's ALSA mixer path code where
HDMI path configurations lack IEC958 unmute sections.
Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3261
See-Also: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/562
See-Also: 33be660e4b
See-Also: https://bugs.launchpad.net/hundredpapercuts/+bug/681996
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
Add an example of a filter sink that requires MemFd memory on the
input port. Show that it gets automatically mapped and that it contains
MemFd memory.
Fixes#4918
Don't just blindly mmap the buffer but only when the data pointer
is NULL. If it was mapped already by the peer or the adapter or the
buffer allocation, we don't want to mmap it again and override the buffer
data pointer.
Also mmap with the permissions on the data. There is not much point in
limiting the permissions for an input port (to read only). We could do
this but then we would not be allowed to modify the existing data
pointer. The problem is that when the stream mmaps the data as READ only
and set the data pointer, if it is then handed to the mixer, it would
assume it is mapped with the permissions and then segfault when it
tries to write to the memory. It's just better to only mmap when the
data is NULL.
We don't need to do this ourselves, the MAP_BUFFERS port flag already
makes sure this is done for use.
We used to have to do this here to ensure the mixer could find the data
pointer and not error out. Now that the mixer can MMAP, this can go.
See #4918
There are really 2 options for the buffer allocation:
1. allocate the buffers skeleton and meta/chunk/data in malloc memory.
This is when the PW_BUFFERS_FLAG_SHARED is unset.
2. allocate buffers skeleton in alloc memory and the meta/chunk/data
in shared memory when the PW_BUFFERS_FLAG_SHARED is set.
Optionally the data can be left unallocated in both cases when the
PW_BUFFERS_FLAG_NO_MEM is set. In this case we also need to pass the
SPA_BUFFER_ALLOC_FLAG_NO_DATA flag to allocator or else it will set the
data pointers to 0 sized memory in the skeleton.
If we use SHARED and we allocated memory, we can also set the MemFd and
mapoffset into our shared mem. We can do this even if the data_type is
MemPtr.
We can decide on the datatype to use earlier, based on the negotiated
flags. In the MemFd case, make sure the buffer data is page aligned in
that case to make things easier. Also force everything in SHARED mem
when the data is in SHARED mem. We also don't need to
PW_BUFFERS_FLAG_SHARED_MEM because we work with the negotiated flags
now to decide if SHARED mem is needed or not.
With this change, a node port could provide a MemFd data_type mask in
the Buffers param and this would negotiate shared mem with the mixer.
Previously, it would only ever allocate malloc memory.
See #4918
When we have a mixer node and we need to negotiate buffers between the
mixer and the node, take the CAN_ALLOC flag into account.
This is for input ports, which can have a mixer. If you make a filter
with a CAN_ALLOC input port, it will now not already contain buffer
data.
See #4918
A fixed channel count makes no sense with an entity based 3D audio format
like MPEG-H, because MPEG-H decoders do not simply decode; they
"spatialize" the entities, meaning that said entities are decoded and
rendered accordingto the needs of the target playback system and its
channel count.
Log something less confusing when connection to remote device drops
unexpectedly.
Silence logging transport Release() error in cases where the transport
was simultaneously deleted.
We don't want to override the converter flags with the follower flags,
just enhance them with specific follower flags. Otherwise we lose the
DYNAMIC_DATA and other port flags from the converter.
See #4918
When using LC3-24kHz, remote device drops connection after a few seconds
if there is no sink playback. Avoid this by sending silence, one TX
packet for each RX packet, if sink hasn't been feeding data within a
timeout.
Find leaf nodes by looking at the number of max in/out ports and the
link group. This should give us nodes that only consume/produce data.
If a leaf node is linked to a driver with only passive links, it will
never be able to be scheduled unless we also make it runnable when the
driver is made runnable from another node.
This can happen when you do:
pw-record -P '{ node.passive=true }' test.wav
and then
pw-record test2.wav
Without this, the first pw-record would never be scheduled. With the
patch it will be scheduled when the second pw-record is started.
Fixes#4915
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.
When we fire the timer event, mark the next timeout as NULL because
nothing else is going to timeout anymore until we rearm the timer.
This has the effect that if we cancel and add the same timer from the
callback that we will reprogram the timer with the new timeout instead
of thinking the item as already programmed.
Configure the headroom to be equal of the minimum allowed period size for
the configuration.
This is desirable when the ALSA driver's hw_ptr is 'jumpy' due to
underplaying hardware architecture, like SOF.
In case of SOF the DSP firmware will burst read at stream start to fill
it's host facing buffer and later settles to a constant pace. The minimal
period size is constrained by the driver to cover the initial burst and
settling time of the hw_ptr.
Guard this mode of working with a new boolean flag, which is only enabled
for SOF cards, kept it disabled for other cards to avoid any unforeseen
side effects.
Even if the use-period-size-min-as-headroom is set to true, the manual
headroom configuration will take precedence to allow experimentation.
Link: https://github.com/thesofproject/linux/issues/5284
Link: https://github.com/thesofproject/sof/issues/9695#issuecomment-2569033847
Link: https://github.com/thesofproject/sof/issues/10172
Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4489
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Now that the server asks for the right amount of samples for DSD, just
give it the right amount of samples without doing some weird scaling.
Make a method to calculate the size (stride) of one sample, which
depends on the interleave and channels of the stream.
See !2540
Replace force_rate with force_quantum. We use force_rate when we need
to play an IEC958 or a DSD format but it does not make sense to just
force the rate without also forcing the duration.
This is also what happens when doing IRQ based scheduling, we then force
both the duration and rate of the graph so we can reuse this logic.
Also when forcing a quantum, take into account the suggested duration
and rate of the graph and scale that with the currently configured rate
for the period size. This gives a quantum that will match the requested
rate better. This is important for the DSD, where rate are very high and
we want the period size to be something reasonable relative to the
selected graph rate.
For batch devices (and when using a timer) we also configure a period
size that is half the duration of the quantum, to make sure we get some
headroom. We however need to force the full duration as the quantum, so
keep track of this scaling and apply when calculating the duration.
Commit cbbf37c3b8 changed the logic of the
Start command. Before this commit, when there was no converter, the
follower would always get the Start command. After the commit, the
follower would only get Start when previously Paused.
This however breaks when we set a format or buffers on the follower
without a converter because those actions might change the state of the
follower to Paused implicitly.
We should simply remove the started check here and always call Start on
the converter and follower, the implementations themselves will keep track
if anything needs to be done.
Fixes#4911
Some drivers (emu10k1) appear to not necessarily support more than 2
periods.
Don't fail start if snd_pcm_hw_params_set_periods_min() fails, then we
just set nearest possible periods and buffer sizes.