Merge branch 'fix-iec958-unmute-on-activation' into 'master'

Fix HDMI/DisplayPort Audio by Enabling IEC958 Switches

Closes #3261

See merge request pipewire/pipewire!2556
This commit is contained in:
Daniel Nouri 2025-10-27 17:40:16 +00:00
commit f02a132f2b

View file

@ -1686,6 +1686,59 @@ static int device_disable(pa_card *impl, pa_alsa_mapping *mapping, pa_alsa_devic
return 0;
}
/* Synchronize IEC958 digital output/input switch states.
*
* IEC958 switches default to muted in ALSA drivers. Cards with multiple
* HDMI/DP outputs have indexed switches (IEC958,0 IEC958,1 etc). We enable
* all switches since we cannot reliably map device numbers to indices.
*/
static void sync_iec958_controls(pa_alsa_device *d)
{
snd_mixer_t *mixer_handle;
snd_mixer_elem_t *elem;
pa_card *impl;
int r;
mixer_handle = d->mixer_handle;
/* Pro-audio profiles don't have per-device mixers, use card mixer */
if (!mixer_handle) {
impl = d->card;
if (!impl || impl->card.index == ACP_INVALID_INDEX)
return;
mixer_handle = pa_alsa_open_mixer(impl->ucm.mixers, impl->card.index, true);
if (!mixer_handle)
return;
}
/* Enable all IEC958 switches */
for (elem = snd_mixer_first_elem(mixer_handle); elem;
elem = snd_mixer_elem_next(elem)) {
if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
continue;
const char *name = snd_mixer_selem_get_name(elem);
if (!name || !pa_startswith(name, "IEC958"))
continue;
if (snd_mixer_selem_has_playback_switch(elem)) {
r = snd_mixer_selem_set_playback_switch_all(elem, 1);
if (r < 0)
pa_log_warn("Failed to enable IEC958 playback switch: %s",
pa_alsa_strerror(r));
}
if (snd_mixer_selem_has_capture_switch(elem)) {
r = snd_mixer_selem_set_capture_switch_all(elem, 1);
if (r < 0)
pa_log_warn("Failed to enable IEC958 capture switch: %s",
pa_alsa_strerror(r));
}
}
}
static int device_enable(pa_card *impl, pa_alsa_mapping *mapping, pa_alsa_device *dev)
{
const char *mod_name;
@ -1777,6 +1830,9 @@ static int device_enable(pa_card *impl, pa_alsa_mapping *mapping, pa_alsa_device
break;
}
/* Enable IEC958 switches for digital outputs */
sync_iec958_controls(dev);
return 0;
}
@ -2277,6 +2333,7 @@ int acp_device_set_port(struct acp_device *dev, uint32_t port_index, uint32_t fl
pa_sink_suspend(s, false, PA_SUSPEND_UNAVAILABLE);
#endif
}
sync_iec958_controls(d);
if (impl->events && impl->events->port_changed)
impl->events->port_changed(impl->user_data,
old ? old->port.index : 0, p->port.index);