alsa-project/alsa-ucm-conf

UCM doesn't set mixer for speaker if it fails to set mixer for microphones

halobarrlets opened this issue · 12 comments

I have laptop Dell XPS 17 9720 SKU 0AFE which has microphones and webcam on top of the display connected to motherboard with cable. I need to have webcam and microphones disabled so I've disconnected the cable from motherboard.
Because microphones are disconnected firmware fails to initialize them but speakers are initialized properly.
With pulseaudio disabled and manually setting amixer I can play audio with speakers using aplay:

user@user:~$ amixer -c0 cset name='Speaker Switch' 1
numid=38,iface=MIXER,name='Speaker Switch'
  ; type=BOOLEAN,access=rw------,values=1
  : values=on
user@user:~$ amixer -c0 cset name='rt1316-1 DAC Switch' 
numid=75,iface=MIXER,name='rt1316-1 DAC Switch'
  ; type=BOOLEAN,access=rw------,values=2
  : values=on,on
user@user:~$ amixer -c0 cset name='rt1316-2 DAC Switch' 1
numid=76,iface=MIXER,name='rt1316-2 DAC Switch'
  ; type=BOOLEAN,access=rw------,values=2
  : values=on,on
user@user:~$ aplay -Dhw:0,2 test.wav

But with pulseaudio enabled it fails to load mixer because of missing microphones:
systemctl --user status pulseaudio

systemd[1160]: Starting pulseaudio.service - Sound Service...
pulseaudio[1176]: Failed to get the verb HiFi
pulseaudio[1176]: No UCM verb is valid for hw:0
pulseaudio[1176]: Unable to load mixer: Invalid argument
systemd[1160]: Started pulseaudio.service - Sound Service.

Thanks to @bardliao the problem was narrowed down to the problem with UCM from this issue thesofproject/linux#4580 (comment) so I'm reporting this issue here.
Is it possible to fix this issue so UCM won't fail completely if one of the audio devices (microphones) is missing and will still initialize the available devices (speaker, jack output)? So that I can use speakers even without microphones?

I'm using Debian unstable with latest kernel 6.5.0-rc6+ from https://github.com/thesofproject/linux and firmware-sof-signed 2.2.6-1.
Here are the logs:
alsa-info.txt
dmesg-cable-connected.txt
dmesg-cable-disconnected.txt
amixer contents -c0
amixer-contents-cable-connected.txt
amixer-contents-cable-disconnected.txt

UCM already deals with RT715 as an optional component based on the 'component' string, see the result of 'amixer -Dhw:0 info'.

I think the problem here is that you have a RT715 codec that has a Schroedinger behavior. It's there (ACPI-wise) but not there (regmap) and there (card/component).

Yes, the component is present:

Card hw:0 'sofsoundwire'/'Intel Soundwire SOF'
  Mixer name	: 'Intel Alderlake-P HDMI'
  Components	: 'HDA:8086281c,80860101,00100000 cfg-spk:4 cfg-amp:2 hs:rt711-sdca spk:rt1316 mic:rt715-sdca'
  Controls      : 80
  Simple ctrls  : 51

Is it possible to make a decision on whatever codec is present or not by checking all 3 of the states?
if (ACPI_is_present && regmap_is_present && component_is_present)

in your case the link with rt715-sdca is disabled, so the component information is wrong, and that causes UCM to be confused.

IIRC we add this component string based on the soc-acpi-match information, so my money is on something wrong in your acpi-match changes.

Just to clarify, this issue is about using kernel without this patch thesofproject/linux#4580 (comment) so soc-acpi-match is matched for sof-adl-rt711-l0-rt1316-l12-rt714-l3.tplg with rt715 link.
I'm asking if it's possible to fix the UCM behavior so it'll set mixer for all components that are successfully initialized even if there are components that failed to initialize?

This issue is not about the specific case with missing microphones in this laptop but a general one where one or more components are failing to initialize for whatever reason (disconnected/hardware fault/new machine that comes without this component/something else).
For available components to work without audio failing completely the solution is either to create all possible topologies for every variation of available component configuration (in case of sof-adl-rt711-l0-rt1316-l12-rt714-l3.tplg with 4 links it'll require 8 different topologies) or make a universal solution where only one topology with all possible components is required (sof-adl-rt711-l0-rt1316-l12-rt714-l3.tplg) and to handle the missing components so it won't lead to audio failing completely and available components will work.

It's just impossible to track every cause of failure and conceal it.
What if the left speaker is blown, do you want a downmix of L+R on the right speaker?
We made a conscious decision to fail big and fail early. There's no plan to change this direction in light of limited support resources.

Note that this has nothing to do with SoundWire, you would get exactly the same problems on different cards by disconnecting I2S/I2C components.

It's just impossible to track every cause of failure and conceal it.
What if the left speaker is blown, do you want a downmix of L+R on the right speaker?

I don't know the exact architecture so I was just thinking that it wouldn't take a lot of work to make the firmware to make the list of successfully initialized components and pass it further to higher level software so it'll be able to know which components it can use.
And don't make any further actions like downmix of L+R to one speaker and leave this for user to fix with balancing the sound 100% to the working speaker or something.

Note that this has nothing to do with SoundWire, you would get exactly the same problems on different cards by disconnecting I2S/I2C components.

I had this laptop without SoundWire previously:
https://wiki.archlinux.org/title/HP_Spectre_x360_(2020)
And I disconnected webcam and microphones cable for it as well but I didn't have this problem with speakers.
Maybe something changed in recent kernel/sof so it will have the same problem now but I can't check it as I don't have it anymore.

If the software architecture won't allow this to be fixed easily so I guess we can close this issue as "won't fix".

the problem is that the hardware reports attached on the bus in a completely asynchronous way, and we can't really decide what there or not there. Likewise userspace makes all kinds of decisions and isn't really able to deal with components that may or may not be present.

You're not completely wrong on the ask, it's just very hard technically to do.

As far as I understand, kernel detects topology, for example, sof-adl-rt711-l0-rt1316-l12-rt714-l3.tplg and then it waits for all 4 components to initialize before it'll report to userspace that all components are initialized and can be used? In that case isn't there some timeout waiting for all expected components to be initialized? Then isn't it possible to just report to userspace the list of components that were initialized correctly after this timeout?

no, this is not how things work. There's a concept of deferred probe where the components need to be registered with the ALSA framework, and then the hardware can report present later even.

And timeouts are really not how the Linux drivers should work. At any point of time, the device/driver can be bound or unbound, that's part of the requirements. we had to go through hoops to make sure the card was properly created even when a driver was probed "later".

Yes, it makes sense. I was mistaken into thinking about timeout after seeing that pulseaudio failed to load mixer. I've looked into it and it failed because UCM sof-soundwire config was expecting specific configuration and failed if it didn't find microphones. If I edit the sof-soundwire UCM configs and remove microphones from them then audio works.

I'm afraid. This customization is not expected thus the software modification is purely on the user side. Perhaps, you can modify the kernel driver (add module option or so to avoid the microphone configuration / reporting to the user space).