diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index 7fc749a7e..276b6c553 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -1615,6 +1615,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; @@ -1681,6 +1734,9 @@ static int device_enable(pa_card *impl, pa_alsa_mapping *mapping, pa_alsa_device } } + /* Enable IEC958 switches for digital outputs */ + sync_iec958_controls(dev); + return 0; } @@ -2179,6 +2235,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);