[alsa-devel] Surround speaker connection on Acer 8951G

Takashi Iwai tiwai at suse.de
Fri Aug 30 14:22:42 CEST 2019


On Fri, 30 Aug 2019 13:45:10 +0200,
Sergey 'Jin' Bostandzhyan wrote:
> 
> 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? 

UCM profile is read directly PulseAudio.  If a profile matches, PA
uses the UCM profile instead of its mixer own parser.

> 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.

With UCM profile, basically it's "out-of-the-box" for the normal use
case.

> > > 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.

Right, and it's impossible with the current code base because the
headphone profile and 5.1 profile can't coexist.

> > > 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?

If it can be really implementable, that's fine.  If you give a patch
that is simple enough, I'll happily apply it.

Other than that, the approach with UCM profile would be simpler.  It
won't need anything else than what you already showed (pincfg and
GPIO) in the driver side.

> 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.

Forget about the whole auto-mute inside the driver.  This won't work
without the intrusive changes.

The UCM doesn't need the auto-mute behavior inside the driver.  It can
switch the profile by itself.  And PulseAudio drives it properly when
a UCM profile is set up.  That's all.

You can still change the individual channel volumes/mutes if you want,
too.  The only caveat is that there is no individual headphone volume;
it's controlled as surround.

The only remaining question is whether the specific Jack control
notifies via ALSA control API properly.  You can run like
  % /usr/sbin/alsactl monitor
and see which control gets notified when you plug the headhpone jack.
Just give which jack control corresponds to the actual headphone
jack.  Then it can be put into the UCM profile.

> > 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.

The GPIO_DIRECTION specifies whether input or output, and the actual
value is passed via GPIO_DATA.  Both have to be specified, not only
one.

> 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)

This needs the paired SET_GPIO_DATA for a proper operation.  Your
analysis implicit assumes some default value that is already set by
the hardware.


> > > 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?

... only if the patch is acceptable.  I'm not going to this way by
myself, but I'll be happily apply if a reasonable patch is provided.

> 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?

This isn't easy, as repeatedly mentioned, since the parser assumes
only one role for each pin except for the input/output switching.
In your case the pin shares for two outputs to be switched, and this
isn't implemented at all.


thanks,

Takashi


More information about the Alsa-devel mailing list