ValveSoftware / steam-runtime

A runtime environment for Steam applications
Other
1.17k stars 86 forks source link

Sound issue - ALSA lib cannot open shared library libasound_module_pcm_pipewire.so #643

Closed llitz closed 5 months ago

llitz commented 5 months ago

Your system information

Gentoo system running with pipewire 1.0.1. $HOME/.asoundrc configured to use pipewire since type pulse doesn't work any longer in this system.

pcm.pipewire {
    type pipewire
}
ctl.pipewire {
    type pipewire
}

pcm.!default {
    type pipewire
}
ctl.!default {
    type pipewire
}

Running with a custom Soldier or Sniper runtime and simply copying the libasound_module_pcm_pipewire.so and libasound_module_ctl_pipewire.so to the proper locations inside alsa-lib enables sound and the proper audio connection shows up on pavucontrol.

Considering this doesn't appear to exist in the current soldier/sniper containers (I imagine because it doesn't exist in Debian), should this library copied from the system before mounting the container?

Steps for reproducing this issue:

pcm.pipewire { type pipewire } ctl.pipewire { type pipewire }

pcm.!default { type pipewire } ctl.!default { type pipewire }

In this system, simply starting Steam will reproduce the issue 100% of the time

smcv commented 5 months ago

$HOME/.asoundrc configured to use pipewire since type pulse doesn't work any longer in this system

My understanding is that if your intention is to use pipewire for audio, then pipewire-pulse and a PulseAudio client library are considered to be an important part of that setup. Many audio middleware libraries support PulseAudio, but do not support Pipewire APIs directly:

For applications that are already using the pulseaudio client libraries we recommend that you keep using it. Some applications (firefox) can also be compiled with different backends but this is not recommended — https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#should-i-uninstall-everything-pulseaudio

Steam itself also relies on PulseAudio compatibility.

One big problem with using libasound_module_pcm_pipewire.so is that it's difficult for a client library to distinguish between two situations, both of which need to continue to work:

  1. Pipewire is installed, and is used for video routing, but is not intended to handle audio, because PulseAudio, JACK, ALSA dmix or some other interface is being used for that (for example a typical Debian 11 GNOME desktop or a typical Debian 12 KDE/Plasma desktop is like this, with PulseAudio as the sound server)
  2. Pipewire is installed, and is intended to handle both audio and video (for example a typical Debian 12 GNOME desktop is like this, and so is your Gentoo system)

In both cases, the Pipewire IPC socket exists, and in the second situation it would be OK to send audio to it, but in the first situation that would be a bug (and would quite possibly result in not hearing any audio).

smcv commented 5 months ago

this doesn't appear to exist in the current soldier/sniper containers (I imagine because it doesn't exist in Debian)

It does exist in Debian, but these Debian-derived containers intentionally don't include it. If we included it and selected it on systems like yours where Pipewire is being used for audio, then that would be fine, but if we accidentally selected it on systems where Pipewire exists but is not being used for audio, that would be a bug.

At the moment, the resolution for this is to say that the recommended audio interface for use by Steam is something that is compatible with PulseAudio - either the original PulseAudio, or pipewire-pulse.

should this library copied from the system before mounting the container?

At the moment, it's intentional that it isn't. We use libraries from the host system for the graphics stack, but not for the audio stack. Every time we pull in a library from the host system, there is a risk of conflicts or regressions, and the more libraries we get from the host system, the more times we have to roll the dice on whether there's a problem.

ALSA and Pipewire are both difficult cases here because they have a plugin architecture, with an arbitrary number of plugins that pull in arbitrary library dependencies, which would need special code to handle (and increase the chance that we encounter one of the weird cases that break things). JACK is also difficult (#438) because some of its dependencies (libdb) are specifically awkward to deal with.

If we did make libasound_module_pcm_pipewire.so available inside the container, it would be more likely to be by using the runtime's version (0.3.65, backported from Debian 12) than by using the copy from your host system.

llitz commented 5 months ago

I apprecite your explanation and understand the reasoning for not making it the default.

It would be nice if we could enable the libraries but only use them if forced by an external variable, this way we could keep the current behavior of pulse only while allowing other systems (that can be better for other users) to work.

The only reason I noticed this is because the emulated pulseaudio by pipewire is having some conflicts with wine using the pulseaudio driver when all the devices are configured to "Pro Audio". Even just running winecfg with regular wine triggers this:

0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux2
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux3
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux4
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux5
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux6
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux7
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux2
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux3
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux4
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux5
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux6
0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux7

Edit: changing from pro audio to regular stereo still doesn't fix proton for me (with type pulse in .asoundrc and no pcm_pipewire.so). I have this:

ALSA lib pulse.c:242:(pulse_connect) PulseAudio: Unable to connect: Connection refused

~~

smcv commented 5 months ago

It would be nice if we could enable the libraries but only use them if forced by an external variable

Many things would be nice, but we can't support an unlimited number of configuration options - just to be able to run it on all the operating systems it already works on, the container runtime framework is already pushing the limits of how much complexity we can cope with, so we have to pick our battles carefully. I'm not saying this as a definite "no", but it's unlikely to become a high priority any time soon.

0200:fixme:pulse:pulse_channel_map_to_channel_mask Unhandled channel aux2

This is a low-severity warning, not an error, so it doesn't necessarily indicate any serious problem.

smcv commented 5 months ago

ALSA lib pulse.c:242:(pulse_connect) PulseAudio: Unable to connect: Connection refused

This is a problem, which is worth investigating.

Do PulseAudio clients on the host system work correctly? (pactl info would be a good example, or any SDL game with SDL_AUDIODRIVER=pulse, for example.)

If not, then that's the thing to investigate and fix, perhaps by using your distro's support channels.

Or, if "ordinary, boring" PulseAudio clients are working well on the host system, but not working inside a Steam Linux Runtime container, then fixing that is likely to be a much higher priority for us than making Pipewire-but-no-PulseAudio work. To do that, we'll need to look at what socket your pipewire-pulse is listening on, and compare with how the container runtime framework discovers a PulseAudio(-compatible) server.

smcv commented 5 months ago

This looks relevant:

pressure-vessel-wrap[27775]: D: Found pulseaudio socket from configuration file '/home/mb/.config/pulse/client.conf': /tmp/pulse-socket
pressure-vessel-wrap[27775]: D: Could not find pulseaudio socket

If you've configured PulseAudio clients to connect to /tmp/pulse-socket, but your pipewire-pulse is listening somewhere different (typically $XDG_RUNTIME_DIR/pulse/native), then PulseAudio is not going to work correctly.

Having ~/.config/pulse/client.conf is not usually necessary, so my first suggestion would be moving it out of the way; or if there is other configuration in there that you know you want, commenting out the line that asks for /tmp/pulse-socket.

[edited: original message specified a wrong PulseAudio-compatible socket]

llitz commented 5 months ago

Thanks for taking the time to go through the logs.

I found the issue because I couldn't find the pulse socket within the container, only the pipewire one. Just setting PULSE_SERVER to the proper path before opening STEAM "fixed" the issue.

Because pressure-vessel isn't able to find the pulse socket on account of that file being incorrect (I didn't see that error popping up) it falls back to the pipewire socket (/run/user/${UID}/pipewire-0) instead of trying the well known pulse daemon location (/run/user/${UID}/pulse/native).

pactl info seems to ignore the incorrect ~/.config/pulse/client.conf and properly connect to /run/user/${UID}/pulse/native

While my issue can be closed, I imagine this isn't impossible to happen in the future to others as migration from pulseaudio to pipewire seems to be the current flow.

Perhaps if it fails, should we try connecting to the well-known pulse socket location, like pactl seems to do?

The pipewire daemon has some very low level compatibility with pulse, or used to have, so it kind of connects, but fails because of protocol differences.

smcv commented 5 months ago

pressure-vessel's PulseAudio socket discovery is the same as Flatpak's (literally the same code). It doesn't have much opportunity to probe whether a path works or doesn't work, because it doesn't actually connect to the socket at all (it doesn't know how to speak the PulseAudio IPC protocol); so if there is a wrong socket in a high-precedence source of configuration, you'll end up with it trying to use that wrong socket, even if the correct socket is actually available at a lower-precedence location. The same is true for other AF_UNIX socket protocols (X11, Wayland, D-Bus, Pipewire and so on).

In your case, it seems that there's an old/stale/wrong default-server=/tmp/pulse-socket in ~/.config/pulse/client.conf. If /tmp/pulse-socket is not actually the socket that you intend to be using, then please remove that configuration or comment it out, which will avoid it breaking pressure-vessel or other things.

In principle, pressure-vessel could test whether the socket exists (it can't usefully test whether it works, but it can test whether it exists, and maybe that's enough?), and it could try lower-precedence configuration sources if a higher-precedence configuration source names a socket that turns out not to exist? Would that be more like the behaviour of the real libpulse? If that's going to happen, it would ideally happen in Flatpak first. Hopefully we won't get too many bug reports complaining "I set this configuration but it was ignored" if we do that...

Because pressure-vessel isn't able to find the pulse socket on account of that file being incorrect (I didn't see that error popping up) it falls back to the pipewire socket (/run/user/${UID}/pipewire-0) instead of trying the well known pulse daemon location (/run/user/${UID}/pulse/native).

What is the "it" in this sentence? pressure-vessel, or a PulseAudio client, or what?

As far as I'm aware, pressure-vessel doesn't fall back from the PulseAudio socket to the Pipewire socket: it tried to find a PulseAudio socket in your configuration, your configuration said "use /tmp/pulse-socket", and pressure-vessel obeyed the configuration to the best of its ability. Because the socket didn't exist, it ended up not setting up a PulseAudio socket for the container at all.

It does also attempt to share the native Pipewire socket with the container, but that's a parallel thing, not a fallback - for each protocol that we know is important (X11, Wayland, D-Bus, PulseAudio, Pipewire, ...), we try to replicate the same socket discovery that the "real" client library would use, and then share the resulting socket with the container. For users of Pipewire, the container will typically have both PulseAudio and Pipewire sockets available, libpulse will use the former, and libpipewire will use the latter.

The pipewire daemon has some very low level compatibility with pulse, or used to have

Really? That's the first I've heard of it. They both use an AF_UNIX socket, so clients of one can attempt to connect to the other, but I thought the similarities end there - a bit like the way HTTP and SSH both listen on a TCP port, but if you connect a client of one protocol to a server for the other, nothing useful is going to happen.

llitz commented 5 months ago

Because pressure-vessel isn't able to find the pulse socket on account of that file being incorrect (I didn't see that error popping up) it falls back to the pipewire socket (/run/user/${UID}/pipewire-0) instead of trying the well known pulse daemon location (/run/user/${UID}/pulse/native).

What is the "it" in this sentence? pressure-vessel, or a PulseAudio client, or what?

When the default-server in ~/.config/pulse/client.conf is incorrect, the pulse-server is never created inside the container. (pressure-vessel)

then, If ~/.asoundrc has type pipewire, the library doesn't exist and it fails. Direct alsa is tried as a next resource, it may or may not work depending if something is locking the device or not.

or, If ~/.asoundrc has type pulse, it will use the correct library, *_pcm_pulse.so but, at least in my case, it will fail because libpulse will try to connect to /run/user/${UID}/pipewire-0. I haven't been able to understand why libpulse tries to connect to the pipewire socket

pressure-server will ignore ~/.config/pulse/client.conf if PULSE_SERVER is properly configured on the host side (that was my initial workaround, earlier today)

I only see the two possible improvements, one which might lead to more complications as you mentioned previously:

1 - Have *_pcm_pipewire.so available in the container (not an option at this moment as it can lead to more issues) 2 - Don't give up on pulse so easily. For example, pactl info always returns the proper socket location, even though everything is configured incorrect (which made it all the worse to detect the issue). 3 - Alternatively, don't touch it, this ticket will be here in perpetuity and might help others. We might be able to simply add the information to the docs saying "if a pulse socket is not properly detected by pressure-vessel, the container will not have /run/pressure-vessel/pulse/native and audio will fail. Check /etc/pulse/client.conf, ${HOME}/.config/pulse/client.conf, or PULSE_SERVER environment variable"

Really? That's the first I've heard of it. They both use an AF_UNIX socket, so clients of one can attempt to connect to the other, but I thought the similarities end there - a bit like the way HTTP and SSH both listen on a TCP port, but if you connect a client of one protocol to a server for the other, nothing useful is going to happen.

That's what I recall from a long time ago, but I could be misremembering. Either way, it is exactly like http and ssh right now.