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
GST_SECOND * t.rate.num can turn into a negative gint, resulting in
assertions like:
_gst_util_uint64_scale_int: assertion 'num >= 0' failed
Just use the 64bit version instead.
Instead of always renegotiating a new format and buffers when the
driver changes, only renegotiate when the converter notifies us
of an EnumFormat change. It's possible that changing the driver does
not actually change the result of EnumFormat and then we would simply
renegotiate to the same format and buffers for nothing.
In the audioconvert, check if the target_rate of the new driver has
changed. We keep the last value in our own clock so that we don't
renegotiate when we are removed from a driver (which sets our own
clock as the position). The target rate influences the result of the
EnumFormat params when we are resampling and so we need to emit a
EnumFormat change.
Makes it possible to define audio channels and position with a
predefined layout string.
It is easier and less error prone to say "5.1" than to spell out
[ FL FR FC LFE RL RR ].
AUX channels have a special syntax. AUX<N> will make <N> AUX
channels. Easier to say AUX128 than to write an array with the
128 AUX channels.
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.
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.
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.
spa_json_init assumes that we start in an object and always requires a
key/value pair. If the last part is a key, it returns and error and does
not want to return the key value.
This causes problems when parsing AUX0,AUX1,AUX2 or any relaxed array
withand odd number of elements.
Make a new spa_json_init_relax that takes the type of the container
we're assuming we're in and set the state of the parser to array when we
are parsing a relaxed array.
Fixes#4944
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.
The behavior before b8eeb2db45 was that spa_audio_info_raw_update()
always sets audio.channels when audio.position is updated. The new
behavior does not set audio.channels when parsing audio.position.
This breaks things e.g. when combine-sink and loopback nodes are created
with only audio.position specified.
Restore the previous behavior.
Remove the SPA_AUDIO_MAX_POSITION define and use the
SPA_AUDIO_MAX_CHANNELS again.
Make a compile time define to override the default max channels of 64.
Make sure we compile the SPA library with the default 64 channels. If
you use the SPA library on a spa_audio_info you will get 64 channel
support, like before. If you want more channels, you will need to make
a padded structure or redefine the MAX_CHANNELS before you use the
spa_audio_info structures. You can use the padded structure with the
new functions that take the structure size.
With the extra checks in the parsing code, we avoid making a
valid spa_audio_info with too many channels that don't fit in the
structure. This means that code that receives a spa_audio_info can
assume there is enough padding for all the channels.
Add functions that take the size of the spa_audio_info struct in various
functions. We can use this to determine how many channels and channel
positions we can store.
Error out if we try to use more channels than we can fit positions. This
is probably the safest thing to do because most code will blindly try to
get the positions without checking the channel count.
Make sure we also propagate errors to the callers.