wwmm / easyeffects

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

Explicit sink selection / Global "Excluded App List" ? #3188

Open LebedevRI opened 2 weeks ago

LebedevRI commented 2 weeks ago

EasyEffects Version

7.1.6

What package are you using?

Other (specify below)

Distribution

debian sid

Describe the bug

With complicated pipewire configs, there may be a situation that there is a number of preexisting nodes, that already form some kind of a processing graph: config-pipewire.tar.xz.txt image

The idea is that "sink" is the default sink (that internally receives some final, absolutely mandatory, processing, and actually outputs to the audio card.). And everything (audio players, browser, etc) should output to that default `"sink", and never touch any other sink.

However, when starting EE, it tries to intercept all inputs to all Sinks: image image

That is kind of expected, i suppose. (I'm not sure if those extra sinks can be hidden on pipewire side.) The problem is, that completely messes up the preexisting graph, misconnects parts of it and maybe possibly creating cycles in it.

Even if i manually uncheck "Enable" and check "Exclude" for each of these inputs in EE "Output" -> "Players" list (see screenshot), that setting appears to be per-preset?

Expected Behavior

At the very least, i would love if there could be a setting (in EE's -> "PipeWire" -> "General" tab?) to explicitly tell it to ONLY intercept sources (players) that go to the chosen output. By chosen output, i mean the output that is referenced by the "Use Default Output" / "Name" preferences on that page.

Debug Log

No response

Additional Information

No response

LebedevRI commented 2 weeks ago

That is kind of expected, i suppose.

Forgot to elaborate: my general problem with that behavior is that it takes Sources that were never outputting to the Sink (to which EE then outputs the processed stream), and connects them.

I could imagine that there may theoretically be situations in which that is the desired behavior, but i really can't imagine that it should ever be the default behavior.

wwmm commented 2 weeks ago

I'm not sure if those extra sinks can be hidden on pipewire side

The reason why they are in EE players tab is that they are not sinks in the way we usually would expect. Like Pulseaudio PipeWire creates loopback devices through playback and recording streams. So for EE they are like any ordinary player/recorder stream. If you load a null-sink you will notice that it won't be visible in EE tab.

As usual there is a good and a bad side in having loopback devices implemented as streams. The bad side you have already seen. The good side is that people are able to apply effects to loopback devices... For example people that redirect smartphone audio to the PC through a loopback device can apply effects this way.

Forgot to elaborate: my general problem with that behavior is that it takes Sources that were never outputting to the Sink (to which EE then outputs the processed stream), and connects them

What you want seems similar to #1335 but for the output effects pipeline. It makes sense just like in the other issue. The problem is that PipeWire does not make it easy to actually implement it and I could never find a good solution. I wonder if the incomplete solution I was able to put in place for #1335 will help in your case.

My idea there was to use PW_KEY_TARGET_OBJECT https://github.com/wwmm/easyeffects/blob/3471aa440995ed3e1ab2383e77b6c1a6c44fa12c/src/pipe_manager.cpp#L313. The problem is that this tag may not be defined. It usually is only when the user selects a custom device in the players configuration. Maybe the targets set in PipeWire's configuration have the same effect.

LebedevRI commented 2 weeks ago

The good side is that people are able to apply effects to loopback devices... For example people that redirect smartphone audio to the PC through a loopback device can apply effects this way.

Right, sure. I'm just saying that it's already a solved problem outside of EE, you can edit the PW graph via qpwgrap / carla / etc, and even pavucontrol allows to specify where each Playback stream should go.

My idea there was to use PW_KEY_TARGET_OBJECT

https://github.com/wwmm/easyeffects/blob/3471aa440995ed3e1ab2383e77b6c1a6c44fa12c/src/pipe_manager.cpp#L313

. The problem is that this tag may not be defined. It usually is only when the user selects a custom device in the players configuration. Maybe the targets set in PipeWire's configuration have the same effect.

Right. That would solve it for me for sure, but i don't quite follow why the solution would be so special-cased. Why look for that specific tag specifically? It seems a bit backwards: i would think the solution would be to introspect the actual PW graph (& listen to it's updates), find the node ("Sink") to which we will be outputting, find all the nodes that feed into that "Sink", and proxy them through EE pipeline.

wwmm commented 2 weeks ago

Why look for that specific tag specifically? It seems a bit backwards: i would think the solution would be to introspect the actual PW graph (& listen to it's updates), find the node ("Sink") to which we will be outputting,find all the nodes that feed into that "Sink", and proxy them through EE pipeline.

This would work if all that information were available when we are notified about the node existence. But this isn't the workflow. It is totally valid in PipeWire to have a node that is not connected to anything. So when we are first notified about a node the information that comes does not include that this node will eventually be linked to a particular device. But at the same time this information comes we have to decide what to do with this node and we ask ourselves "Do we move it to our virtual device or not?". We can't keep waiting forever for a signal that may never come.

The reason why the approach you have in mind is not viable is because both on PipeWire and Pulseaudio the client reacts to server signals. It does not keep polling for information in an infinity loop. The server sets the tags when it considers it has to. And sometimes it may consider it does not have to. Once it does something it broadcasts a signal. There isn't a function call to "introspect the PW graph". We have to keep our own list of everything that we may need based on the signals that come.

wwmm commented 2 weeks ago

The reason why PW_KEY_TARGET_OBJECT helps is because when this tag is set its value comes together with the first signal about the node existence. So we can make a decision without having to wait for a signal that may or may not be emitted.

wwmm commented 1 week ago

@LebedevRI I've updated our master branch with the "fix" discussed before. Let me know if it was enough.

LebedevRI commented 1 week ago

@wwmm thank you! As long as you've checked that it succeeds in what it claims to do, it should be enough.

wwmm commented 1 week ago

@wwmm thank you! As long as you've checked that it succeeds in what it claims to do, it should be enough.

I only tested in VLC because I think it is the only player I have installed that allows selection of the output device. If I set a different device before creating the stream it works as intended.