New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Volume scale broken after changing the output device #801
Comments
This definitely didn't used to be the case. Can you check an older version of exaile (4?) to see if this behavior is present? |
Latest version I got working is 4.1.0. In this version it is the same. Volume control works after click on stop and start again. It fails only if I change the device during playback. |
If a prior version wasn't broken, then it seems to me better to use |
You are right, but actually I got only 4.1.0 running. There it is the same. |
Updated summary (I hope this is more clear. Sorry for the misleading summary above): It works as expected if I
It does not work if I
Unfortunately I'm not able to run Exaile 4.0.x because of outdated packages. But I think there should be no difference, because the code is from 2015. I could imagine, that this thing wasn't noticed before. |
67fda42 will need to be reverted, as it completely breaks switching audio streams for me. If you use the gstreamer graphviz debugging stuff mentioned in the devel docs (you can use this in the simple console) from xl.player import PLAYER
from gi.repository import Gst
Gst.debug_bin_to_dot_file(PLAYER._engine.main_stream.playbin, Gst.DebugGraphDetails.ALL, "filename") You can see from the output image that the playbin and the playsink both have the correct volume after the sink change, but the audiosink is stuck at whatever volume the parent had. Referring to https://github.com/GStreamer/gst-plugins-base/blob/ce937bcb21412d7b3539a2da0509cc96260562f8/gst/playback/gstplaysink.c#L2808, it looks like the playsink is looking for an element that implements GstStreamVolume, and then selects that as the element to send volume controls to. However, that's the element that we are replacing -- so likely when we switch the element out, it's still sending volume commands to the old sink, which isn't going to work. I spent a very long time rewriting Exaile's audio engine and testing it, and I find it difficult to believe that I didn't catch this case. However, it seems that at least in some cases (see https://github.com/GStreamer/gst-plugins-base/blob/ce937bcb21412d7b3539a2da0509cc96260562f8/gst/playback/gstplaysink.c#L2870) the playsink will create its own volume element and use that instead -- in which case it might work on some computers and not on others with a different audio configuration (or differ based on whether alsa or pulseaudio is used). Maybe that's why I didn't catch it. In any case, it's definitely broken right now, thanks for finding that. Now, how do we fix it? It doesn't seem like there's a way to tell the playsink to send volume to a different element... which, makes sense I suppose, since it isn't designed to allow you to change the sink at runtime. After all, this is why we have our DynamicAudioSink element. I think we have two options:
I doubt that there is a pre-existing element that does what we need, so the second option is probably our best bet. It might be worth looking at Quod Libet or other gst/python applications to see if they already have an element that does this sort of thing too. ... though I just went and glanced at QL, and they basically implement their own playbin in python, so they don't have to deal with this problem in the same way. Unfortunately, I have to go to bed now, but I'll think about this. |
Thank you for investigating so deep! 67fda42 is reverted. |
There's a comment in the dynamic sink with a link about how the pipeline connection/disconnection works, it's really useful to read if you want to understand more about gstreamer: https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=python#dynamically-changing-the-pipeline I feel like I read somewhere that they had implemented dynamic sink switching in playbin3, in which case none of this nonsense would be needed anymore. I haven't looked into that however, and I'm not sure if it's supported in the oldest version of gstreamer that we currently support. Thanks for your help! |
Hm, apparently # TODO: doesn't seem to be a way to just import GstIdentity
identity = Gst.ElementFactory.make('identity')
GstIdentity = type(identity)
del identity
class VolumeForwardingElement(GstIdentity, GstAudio.StreamVolume):
elem: typing.Optional[GstAudio.StreamVolume] = None
@GObject.Property(type=bool, default=False)
def mute(self) -> bool:
print("getting")
if self.elem is not None:
return self.elem.props.mute
return False
@mute.setter
def mute(self, v: bool):
print("setting", v)
if self.elem is not None:
self.elem.props.mute = v
@GObject.Property(type=float, default=0.0)
def volume(self) -> float:
print("getting")
if self.elem is not None:
return self.elem.props.volume
return 0.0
@volume.setter
def volume(self, v: float):
print("setting", v)
if self.elem is not None:
self.elem.props.volume = v
GObject.type_register(VolumeForwardingElement) If I add it to the bin, and call .. maybe we could add another bin inside the bin? I'm done with this for tonight. |
I had a look at Quod Libet and found https://github.com/quodlibet/quodlibet/blob/master/quodlibet/player/gstbe/player.py#L472. So I changed only this in AudioStream class. Seems to work for now. May this be a possible way? |
Right after starting exaile I can scale the volume with the volume scaler and see the change on pulseaudio.
After I change the output device via Settings > Playback > Audio Device it is broken. When I scale in exaile nothing happens to pulseaudio.
Steps to Reproduce (for bugs)
Environment
The text was updated successfully, but these errors were encountered: