Skip to content
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

Pulseaudio: system-wide installation support #266

Closed
synclpz opened this issue Jul 24, 2020 · 25 comments
Closed

Pulseaudio: system-wide installation support #266

synclpz opened this issue Jul 24, 2020 · 25 comments

Comments

@synclpz
Copy link

synclpz commented Jul 24, 2020

Pulseaudio can be run system-wide, in which case it runs aspulse user. This is useful for allowing different sessions/headless sessions to access the same pulseaudio daemon.

x11docker asks pactl to create a socket for communicating with container client but this socket resides in <cwd>/.cache/x11docker/<image-name-container-id>/share and providing <cwd> is something like /home/someuser it appears inaccessible for pulseaudio running as pulse. So pactl fails and x11docker falls back to enable ALSA integration.

I suggest making an ability to provide path for pulseaudio socket or just create it under /tmp.

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

May be creating a socket in /tmp/<random-number>.pulseaudio.soket and then symlinking it to $Sharefolder/$Pulseaudiosocket would work?

@mviereck
Copy link
Owner

Thank you for reporting this!

I assume user pulse cannot access files from other users, and therefore fails.
Your suggestion with a symlink might work. However, I think of possibilities to keep the socket within x11docker cache to avoid file spreading.
I just checked, the socket already allows arbitrary access:

srwxrwxrwx 1 lauscher lauscher     0 Jul 24 22:32 pulseaudio.socket

Likely pulse cannot access the user owned folders below /home.

Let me think about this. If you have further ideas, please let me know!

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

Yes, socket allows arbitrary access, but pactl can not create it under /home/somebody/.cache/.../share when pulseaudio is run as pulse and not as somebody.

At least I'm gonna fork it now and make a nasty patch with:

Pulseaudiosocket="x11docker.$$.pulseaudio.socket"
Pulseaudiosockethost="/tmp/$Pulseaudiosocket"
unpriv "pactl load-module module-native-protocol-unix socket=$Pulseaudiosockethost 2>&1" >>$Messagelogfile && {
        ln -s "$Pulseaudiosockethost $Pulseaudiosocket" 
        store_runoption env "PULSE_SERVER=unix:$(convertpath share $Pulseaudiosocket)"
        store_runoption env "PULSE_COOKIE=$(convertpath share $Pulseaudiocookie)"
      }
  # remove cache files
  [ "$Preservecachefiles" = "no" ] && grep -q cache <<<$Cachefolder && grep -q x11docker <<<$Cachefolder && [ "x11docker" != "$(basename "$Cachefolder")" ] && unpriv "rm -f -R '$Cachefolder'"
  rm "$Pulseaudiosockethost" -f

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

Oh, just found out that it does not unload module from pulseaudio upon exit...

@mviereck
Copy link
Owner

Oh, just found out that it does not unload module from pulseaudio upon exit...

IIRC there was a bug when unloading the module and pulseaudio crashed or freezed entirely. I remember that I once dropped unloading the module and just deleted the socket to make it unuseable.

One idea: Maybe system-wide pulseaudio works with --pulseaudio=tcp

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

Yes it works with tcp, thats how I found it does not unload modules :) I have 12 instances of module-native-protocol-tcp.
BUT! --pulseaudio=tcp does not work when I use --hostnet lol. Still no idea why.

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

Hmm, system-wide setup of pulseaudio recommends disabling module loading at runtime, so the better idea is to specify system-wide socket /var/run/pulse/native and not to create one for each container I think.

E.g. set this up with --pulseaudio=system,/var/run/pulse/native OR just find default socket by pactl info | grep 'Server String' | cut -f 3 -d' '

@mviereck
Copy link
Owner

--pulseaudio=tcp does not work when I use --hostnet

Fixed, thanks for the observation. x11docker now sets the host IP to 127.0.0.1 if using --hostnet.

system-wide setup of pulseaudio recommends disabling module loading at runtime

Is there a good reason for this? What issues causes it otherwise? Some setups only work over TCP and need a module, e.g. --runtime=kata-runtime.

OR just find default socket by pactl info | grep 'Server String' | cut -f 3 -d' '

That might be a way for the default socket setup. Could you show me your full output of pactl info?

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

Could you show me your full output of pactl info?

Server String: /var/run/pulse/native
Library Protocol Version: 33
Server Protocol Version: 33
Is Local: yes
Client Index: 175
Tile Size: 65472
User Name: pulse
Host Name: home
Server Name: pulseaudio
Server Version: 13.99.1
Default Sample Specification: s16le 2ch 44100Hz
Default Channel Map: front-left,front-right
Default Sink: alsa_output.pci-0000_01_00.1.hdmi-stereo-extra3
Default Source: alsa_input.firewire-0x00148603bd2bb5a1.multichannel-input
Cookie: 9864:d186

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

Is there a good reason for this?

They say, it might be exploited if any local user with access to pulseaudio (being added to pulse-access group) is able to alter system-wide config and modules, hence theoretically have access to any audio/data/sinks/etc used by other users.

https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/WhatIsWrongWithSystemWide/

But I'm building a home server with several applications running simultaneously which must be able to share the same audio output, so I decided to use pulseaudio this peculiar way.

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

I just found out that pactl's output is system-language dependent... So grep might not work on non-english locales.

E.g. https://forum.manjaro.org/t/pulseaudio-controller-fails-to-assign-select-the-output-device/112442/3

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

I think the better is to not alter default behavior and let user choose --pulseaudio=system or even --pulseaudio=system,/path/to/socket in case of we are not able to extract it from pactl due to locale or someth.

@mviereck
Copy link
Owner

mviereck commented Jul 24, 2020

I just found out that pactl's output is system-language dependent... So grep might not work on non-english locales.

This is an issue with many commands. It can be solved setting the C locale before the command:
LC_ALL=C pactl [...]

x11docker could check for User Name: pulse and automatically use the TCP setup in that case. That would be a straightforward solution with low code change. (Edit: Done)

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

automatically use the TCP setup in that case

That would be ok as a default behavior, I think

@mviereck
Copy link
Owner

mviereck commented Jul 24, 2020

That would be ok as a default behavior, I think

Is done and uploaded yet.

I might try out to use Server String from pactl. But if I remember correctly, there has been an issue, too. Maybe with the cookie, or because the container has a different IP..

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

I tried to implement system option I described, but this way fails as symlink stays just a symlink in container too:

victor@home:~$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS
     NAMES
6d43c5b3f301        erichough/kodi      "env /usr/local/bin/…"   3 minutes ago       Up 3 minutes
     x11docker_X107_erichough-kodi_29970254284
victor@home:~$ docker exec -it 6d43c5b3f301 bash
victor@home:/tmp$ ll /x11docker/
total 168
drwxrwxr-x 2 victor victor   4096 Jul 25 01:32 ./
drwxr-xr-x 1 root   root     4096 Jul 25 01:32 ../
-rw-r--r-- 1 victor victor    102 Jul 25 01:32 Xauthority.client
-rw-rw-rw- 1 victor victor    347 Jul 25 01:32 container.environment
-rw-rw-rw- 1 victor victor   1251 Jul 25 01:32 container.log
-rw-r--r-- 1 victor victor   5382 Jul 25 01:32 containerrc
-rw-r--r-- 1 victor victor   6666 Jul 25 01:32 containerrootrc
-rw-r--r-- 1 victor victor   1535 Jul 25 01:32 libc.localtime
prw-rw-rw- 1 victor victor      0 Jul 25 01:32 message.fifo|
lrwxrwxrwx 1 victor victor     21 Jul 25 01:32 pulseaudio.socket -> /var/run/pulse/native
-rw-rw-rw- 1 victor victor      0 Jul 25 01:32 stderr
-rw-rw-rw- 1 victor victor    609 Jul 25 01:33 stdout
-rw-rw-rw- 1 victor victor    902 Jul 25 01:32 store.info
-rw-r--r-- 1 victor victor      0 Jul 25 01:32 timetosaygoodbye
prw-rw-r-- 1 victor victor      0 Jul 25 01:32 timetosaygoodbye.fifo|
-rw-rw-rw- 1 victor victor 122028 Jul 25 01:33 x11docker.log
victor@home:/tmp$ ll /var/run/pulse/native
ls: cannot access '/var/run/pulse/native': No such file or directory
victor@home:/tmp$

So it won't work this way, because symlinks work only on host. See https://stackoverflow.com/questions/38485607/mount-host-directory-with-a-symbolic-link-inside-in-docker-container

@mviereck
Copy link
Owner

To check for now, you could also add --share /var/run/pulse/native to have a target for the symlink.

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

To check for now

Of course it works this way.

NB: after your latest patch container hostname when --hostnet now resolves to my machine hostname instead of container id (see the prompt after docker exec). This may have some side-effects...

@synclpz
Copy link
Author

synclpz commented Jul 24, 2020

#267

@mviereck
Copy link
Owner

after your latest patch container hostname when --hostnet now resolves to my machine hostname instead of container id (see the prompt after docker exec). This may have some side-effects...

I just checked, this is regular docker behaviour and is not related to the patch. The same happens without x11docker and setting docker run --net=host.

Thank you for the pull request! It looks well integrated.
I have some questions:

  • What is the advantage of using the socket, compared to the default tcp connection? Theoretically the socket is more performant, but likely there is no notable difference.
  • When should one need to specify the socket path? pactl provides it already.
  • Does your pulseaudio setup somehow use cookies? Or are cookies disabled to ease access? I remember some authentication issues when I developed the --pulseaudio option and tried to use the socket from pactl info. E.g. your PR might fail without --hostnet.

I just fear that the PR might add complexity and new issues that I could not debug myself without setting up pulseaudio the same way.

@synclpz
Copy link
Author

synclpz commented Jul 28, 2020

I just checked, this is regular docker behaviour and is not related to the patch. The same happens without x11docker and setting docker run --net=host.

Didn't know that, thanks.

What is the advantage of using the socket, compared to the default tcp connection? Theoretically the socket is more performant, but likely there is no notable difference.

I'm trying to mitigate the need to load-module. And also just "why not" :) I don't know about TCP method, but system-wide socket as long as I see in docs (https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/SystemWide/) requires user to be in pulse-access group to work. So you need to provide valid --user or use USER xxxx in Dockerfile which corresponds to right host user allowed to access pulseaudio.

I just tested my container with an unknown UID and it fails to connect to pulseaudio server.

When should one need to specify the socket path? pactl provides it already.

Knowing that pactl is not specifically intended for scripting we may expect some breaking changes in its output, so I decided to add ability to explicitly specify socket address just in case the default flow breaks unexpectedly.

Does your pulseaudio setup somehow use cookies? Or are cookies disabled to ease access?

As I tested, there's no need for cookie in system-wide setup, pulseaudio checks if connecting user is in pulse-access group.

I remember some authentication issues when I developed the --pulseaudio option and tried to use the socket from pactl info. E.g. your PR might fail without --hostnet.

Tested without --hostnet, it works perfectly.

@mviereck
Copy link
Owner

requires user to be in pulse-access group to work. So you need to provide valid --user or use USER xxxx in Dockerfile which corresponds to right host user allowed to access pulseaudio.
I just tested my container with an unknown UID and it fails to connect to pulseaudio server.

It might work for unknown UIDs with --group-add pulse-access.

I'm trying to mitigate the need to load-module

It might be worth to try out unload-module again. Maybe the pulseaudio bugs are fixed meanwhile.

pulseaudio checks if connecting user is in pulse-access group.

Likely pulseaudio does not check itself, but the socket file has belongs to pulse-access.

@synclpz
Copy link
Author

synclpz commented Jul 31, 2020

Right you are. I was wondering about the magic around how pulseaudio checks client access, I thought it was something in it's native protocol :)

@mviereck
Copy link
Owner

I've commited a change that unloads the pulseaudio module on exit.
My current tests on Debian bullseye/testing show no pulseaudio bugs after unload-module yet. Hopefully they are fixed in other distributions and releases, too.

IIRC pulseaudio clients that are connected over a module cannot load modules on their own. I'll have to re-check that.

@mviereck
Copy link
Owner

I finally decided not to merge your PR:

  • The new default TCP setup for system-wide pulseaudio works well.
  • The PR with system socket support would add complexity.
  • The unload-module issue is solved.

Your PR was well integrated, and your investigation and report helped to improve and fix x11docker. Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants