Hi Takashi,
On Thu, Aug 29, 2019 at 01:29:13PM +0200, Takashi Iwai wrote:
One possible way with the current code (and your latest patch) would be to create a UCM profile. The driver should still provide the jack detection on the pin 0x1b as "Surround Jack", and this can be used as the headphone jack detection.
I gogled it up and I did find HDAudio-Gigabyte-ALC1220DualCodecs as an example, so basically the solution in this case would be split between the driver and alsa-lib?
Right.
I did some digging yesterday and found out that documentation on the UCM profiles is sparse. I cloned your alsa-lib repo from github and looked at the available profiles. One thing that is not clear to me: the configurations have entries for JackControl and JackHWMute, however unless I totally missed it - those strings are not being parsed anywhere in the code? I first looked at parser.c as suggested by the man page and later grepped through the whole tree - nothing.
From various examples which I found when searching for answers I could see,
that in most cases the desired _verb section of the profile is activated via a udev rule, but I was not able to find anything that would be hooked to jack sense to switch between devices?
I know it could be done via acpid, is this the way it is meant to be used or am I missing something, especially in regard to those JackHWMute strings?
How exactly is card longname which can be set in the driver connected to all this, I understand there is no automatic mechanism and that everyone needs to set up their custom udev scripts anyway?
I more or less got things to behave using a custom profile with device sections for Speakers and Headphones, which basically mutes everything except surround in Headphone mode, so technically I could hook it up to acpid and be done with it. To be honest, I'd be more happy with an "out of the box" experience, which leads me back to the driver.
Are there any disadvantages to muting the other channels directly in the driver? Or would it be a viable option to extend the auto-parser to handle the remaining channels?
It's not so trivial to extend. The logic of driver parser assumes the single purpose pins, and if they appear doubly, the behavior becomes confusing. For example, if you just add the same pin to both speaker_pins[] and hp_pins[], all speaker_pins[] get muted by the auto-mute, hence you'll mute the headphone again. OTOH, if you don't list up the pin in speaker_pins[], it won't be used for speakers for multi-channels, obviously.
This confirms what I have seen when trying things out last week, the pin could be either a speaker or a headphone, but not both, meaning I would either "lose" the ability to use 5.1 profiles or the system would not "see" the headphones as headphones.
Personally, I would prefer a solution at one place, but I follow your lead here, if you say that UCM is the way to go, then so be it.
We can give it a try. If it doesn't work as expected, we'd need more extension in the driver side.
Would you accept a model-quirk solution that is purely in the driver, which monitors jack presence on 0x1b and simply mutes the remaining speakers directly?
This way it could simply work as expected without an additional userspace setup of alsaucm, udev, acpid.
I played around with jack detection and I had the feeling that it did not work reliably, or maybe I misunderstood something?
[...]
I kept watching dmesg, when nothing is playing the plugged in/unplugged messages appear correctly, but if I start speaker test and replug during the playback, nothing is printed.
Check rather "Speaker Surround Jack" state upon plugging the headphone. Does it change reliably?
Check - where exactly? I did the following test: - ran speaker test - watched dmesg -wH with my printouts + ran alsa_listen in another terminal
While alsa_listen was correctly showing: jack/lineout LINEOUT plug jack/lineout LINEOUT unplug
dmesg remained silent. I figured that I may be hooking to the wrong function, in the code I pasted earlier I was hooking up to the hp_automute_hook, so I changed it to line_automute_hook, but the behavior is the same:
when something is playing, the automute hook is not being triggered upon plugging/unplugging. When nothing is playing, its being called reliably and the printouts are in sync with acpi_listen.
Which leads me to the following question: is the automute hook the right place for jack sensing in the driver at all? I did search for examples, but I failed at figuring out the proper way to hook up to jack state changes, or rather, I coul dsee that hda_jack_callback is being hooked to automute everywhere.
To make it clearer: at this point its not about the "correct state" of the jack, but rather about being triggered at all when something gets physically plugged into or unplugged from the port during an ongoing playback.
Note that even if you set such flags manually like the above, it won't work, because of the reasons I already mentioned.
Right, makes sense. In my debug code I was mostly misusing spec->gen.hp_jack_present as a "free" variable for remembering the state.
Turned out it was indeed a GPIO, I won't describe all the things I tried, in the end it was a lucky click on the dir_out checkbox in hda-analyzer while I was debugging the shared pin issue :)
The below HDA_FIXUP_VERBS does the trick, so I do have all 6 speakers working, finally!
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}
Actually this must be paired with the corresponding bit of GPIO_DATA, too. Is the bit 0x02 of GPIO_DATA set or cleared? Usually setting it turns on the amp, but sometimes inverted.
If I understood everything correctly, then the bit is set, meaning that the GPIO signal is configured as output. I'll be honest, I exported the hda-analyzer setting as a python script (nice feature btw) and deducted the fixup verb setting from there (relevant part of the hda-analyzer export below):
def set(nid, verb, param): verb = (nid << 24) | (verb << 8) | param res = ioctl(FD, IOCTL_VERB_WRITE, struct.pack('II', verb, 0))
set(0x01, 0x717, 0x02) # 0x01071702 (SET_GPIO_DIRECTION)
The only thing that is not quite clear to me is - does LFE still have its own pin and I was just not able to find it, but managed to unmute it via the GPIO? Or is the LFE speaker somehow "intenrally managed"? It works correctly though, alsa mixer is also capable of controlling LFE volume separately so it's fine, everything is also working with pulseaudio and a 5.1 profile on top.
It's usually just the external amp controlled via GPIO, and the signal must go through the pin 0x18 as well as the center channel, I suppose.
Ah, I see, I could try confirming if 0x18 is indeed the LFE speaker or not by "disconnecting" it in the pin configuration, I'd like to know for sure :)
To sum it up:
would you be OK with the "mute remaning channels upon jack sense in the driver" approach?
If the above is a yes, could you please point me to the right way of getting triggered upon jack state changes in the driver, since automute hooks seem not to trigger while something is playing?
Kind regards, Sergey