wwmm / easyeffects

Limiter, compressor, convolver, equalizer and auto volume and many other plugins for PipeWire applications
GNU General Public License v3.0
6.48k stars 269 forks source link

Incorrect output devices detected when using preset autoloader. #2050

Open JxJxxJxJ opened 1 year ago

JxJxxJxJ commented 1 year ago

EasyEffects Version

7.0.0

What package are you using?

Arch (easyeffects)

Distribution

Arch linux

Describe the bug

I'm trying to set presets for speakers and headphones independently and auto-load them depending on what device is connected.

System detects Speakers and Headphones separately as output devices but EasyEffects gets confused with my sound card I assume.

These are Gnome's sound output devices: imagen

And this is EasyEffects' menu: imagen

Expected Behavior

I'm trying to achieve that EasyEffects detects both output devices so I can bind them to a presets and have proper audio.

Debug Log

G_MESSAGES_DEBUG=easyeffects easyeffects >> easyeffectsdebug.log

easyeffectsdebug.log

pw-dump >> pw-dump.log

pw-dump.log

Additional Information

Pavucontrol tabs (if it's inconvenient I'll post them in English): imagen imagen imagen imagen imagen

I clicked the menus that had at least one option different from the one already selected.

wwmm commented 1 year ago

but EasyEffects gets confused with my sound card I assume.

It is not that it gets confused. EasyEffects is showing the full node.description property that you can see in the pw-dump. Pavucontrol is also showing all of them in its window. But GNOME is clearly removing the profile information PipeWire attaches to the description and it seems to also be hiding devices PipeWire considers to be disconnected.

Filtering nodes based on the profile availability may be a little complicated to do as the information comes from different signals emitted by PipeWire. I would have to take a look at this. But back to your case I think that the entry in EasyEffects menu you have to select is the last one. The one without HDMI in the name. Select it without the headphone plugged and you will create a profile for your speakers. Plug the headphone and repeat the process to create an autoloading profile for the headphone.

The reason is that for this soundcard PipeWire "will reuse the node". It is just the profile that changes when the headphone is plugged. So you have to plug/unplug it depending on the autoloading profile destination.

JxJxxJxJ commented 1 year ago

Thanks for the reply.

I created two preset auto-loading setups imagen as you indicated, but plugging and unplugging headphones doesn't cause the preset to change.

Is that what was intended to happen or I misunderstood it?

wwmm commented 1 year ago

but plugging and unplugging headphones doesn't cause the preset to change.

That is strange considering that in each case a different perfil is set. In the first it is [Out] Headphones and in the second [Out] Speaker. This should be enough to make the autolading of different presets for each device. Unless something similar to #1988 is happening.

Kill easyeffects easyeffects -q and run it again in debug mode G_MESSAGES_DEBUG=easyeffects easyeffects >> easyeffectsdebug.log. Are there messages like output autoloading: the target node name does not match the output device name in the file? If yes then the same weird and difficulty to handle time difference between events that was observed in #1988 is happening on your hardware too.

JxJxxJxJ commented 1 year ago

easyeffects -q

G_MESSAGES_DEBUG=easyeffects easyeffects >> easyeffectsdebug.log

easyeffectsdebug.log

Is there a way to check that auto-loading works?

There are output autoloading: the target node name does not match the output device name lines as well...

Is hardware information specified in the logs? I'm using a ThinkPad laptop X1 Carbon 9th Gen.

JxJxxJxJ commented 1 year ago

Might this help by any chance? imagen From https://thesofproject.github.io/latest/getting_started/intel_debug/introduction.html?highlight=snd%20intel%20dspcfg%20dsp_driver .

JxJxxJxJ commented 1 year ago

In any case, if it's unsolvable: do you know another way to achieve the expected behavior? Could the problem get cleared swapping software/configurations or is it hardware related?

wwmm commented 1 year ago

Is there a way to check that auto-loading works? There are output autoloading: the target node name does not match the output device name lines as well...

This message is the reason why it does not work. When it works the log will show which preset is being autoloaded.

application.cpp:129 device alsa_card.pci-0000_00_1f.3-platform-skl_hda_dsp_generic has changed its output route to: [Out] Speaker application.cpp:149 output autoloading: the target node name does not match the output device name application.cpp:129 device alsa_card.pci-0000_00_1f.3-platform-skl_hda_dsp_generic has changed its output route to: [Out] Headphones application.cpp:149 output autoloading: the target node name does not match the output device name

I think it is the first time I see both cases failing. Open the autoloading profile files inside ~/.config/easyeffects/autoload/output/ in a text editor and show me what is inside of them.

Might this help by any chance?

No. If the problem is timing between events the issue is between us and PipeWire. On some hardware PipeWire seems to emit some signals we need before or to close to some signals we have to read first. I do not know how to handle this yet.

In the past I have seen cases where the node name has characters that do not match the the way the properties bus-id and bus-path are being set. I will try to see in your previous pw-dump file how they are being set for this soundcard.

wwmm commented 1 year ago

I will try to see in your previous pw-dump file how they are being set for this soundcard.

The bus-path and bus-id do not seem to be the problem. I think it is happening the same as in #1988. I have to find a way to force a dangerous synchronization between some sections of our code to deal with the fact we have to listen to 2 signals that PipeWire may emit almost at the same time...

JxJxxJxJ commented 1 year ago

ls ~/.config/easyeffects/autoload/output/

'alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFihw_sofhdadspsink:[Out] Headphones.json' 'alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFihw_sofhdadspsink:[Out] Speaker.json'

cat ~/.config/easyeffects/autoload/output/*.json >> output.log

output.log

Here you have. Also, in Speakers-Preset-Dolby it's only some .irs files, in Headphones-Preset it's nothing at the moment. Those are the auto-generated profile files.

wwmm commented 1 year ago

Does this look good?

Yes.

do you know another way to achieve the expected behavior? Could the problem get cleared swapping software/configurations or is it hardware related?

Unfortunately the only way is forcing the synchronization I talked about before. What can only be done changing EasyEffects code. In this comment https://github.com/wwmm/easyeffects/issues/1988#issuecomment-1321149708 I talked a little about it. We have to listen to a signal that tells the current device profile (headphones, speakers, etc). Once it comes we have to match this hardware profile to the soundcard node. What is probably happening on some hardware is that PipeWire sends the signal about the new active hardware profile almost at the same time that the one about the node destruction/recreation comes. As a result when we try to read our node list to find out which one corresponds to the hardware profile the node is temporarily not there anymore. PipeWire will recreate it in the future but by this time the check has already failed. IF that is not the reason for the failure I have no idea about what else it could be.

JxJxxJxJ commented 1 year ago

I see. Unfortunate. Except that if at least the problem is identified it's good news.

Is there a way to maybe through a script detect when this changes imagen and bind it to an EasyEffects "load-profile" call?

wwmm commented 1 year ago

Is there a way to maybe through a script detect when this changes

I never tried to do the operations we do in EasyEffects through a script. But we are just using standard PipeWire API. So it may be possible to do it in a script. The first thing I would try is to see if there is a way to get profile changes parsing the output of the command pw-cli or pw-mon. Or maybe even calling pw-dump every 1 or 5 seconds in a brute force attempt to know if the profile has changed. It is not going to be easy but it may work.

In any case there are 2 types of PipeWire objects that are needed for this: nodes and devices. In gnome and pavucontrol you usually see the nodes. But the profiles are attached to device objects. You have to listen to Device profile changes and then search for the currently used node to decide if you want to load something or not. This process needs this kind of checks because it does not make sense to load a preset if the device that changed profile is not the one EasyEffects is playing to.

JxJxxJxJ commented 1 year ago

Got it. If I make it work will give an update. Thanks for your help

wwmm commented 1 year ago

I have updated our master branch with some minimal mutex usage to see if it makes any difference to this issue. But I am not 100% sure it will be enough.

wwmm commented 1 year ago

I have updated our master branch with some minimal mutex usage to see if it makes any difference to this issue.

This caused random freezes in some situations. So I had to remove this lock. Solving this synchronization problem is not going to be so simple =/

JxJxxJxJ commented 1 year ago

Oh, sad to hear.

I was just going to try it out. It's ok, I wish you the best of luck, it'll be great if this is able to get fixed be sure of that :)

violetmage commented 1 year ago

@wwmm maybe make a seperate issue to track progress on this event timing / race condition problem?

wwmm commented 1 year ago

maybe make a seperate issue to track progress on this event timing / race condition problem?

At least for me this issue is enough. The main problem is that I ran out of ideas to solve this. There is no guarantee the synchronization I attempted before will fix the issue. But at the same time it definitely introduced app freezing. And to make things harder this problem does not happen on my hardware. So I am shooting in the dark hoping things will be fixed on other people hardware.

Ideally I would like to have all the information we need in a single PipeWire signal. But unfortunately we have to listen to two signals that are totally independent of each other =/