[systemd-devel] Session management for Systemd-native PulseAudio apps [was: Re: Packaging systemd user-instance service files]

Ahmed S. Darwish darwish.07 at gmail.com
Fri Jul 24 17:56:52 PDT 2015


Hi Colin,

Thanks __a lot__ for your very informative reply!

I was just going to cross-post this issue to the relevant
PulseAudio channels, but it seems the PulseAudio folks are
already here ;-)

The main issue is indeed the combination of "Systemd + PA" user
session management. Kindly find the necessary details below.

On Mon, Jul 20, 2015 at 11:05:10AM +0100, Colin Guthrie wrote:
> Ahmed S. Darwish wrote on 18/07/15 01:44:
> > On Sat, Jul 18, 2015 at 12:17:51AM +0300, Mantas Mikulėnas wrote:
> >> On Fri, Jul 17, 2015 at 9:38 PM, Ahmed S. Darwish wrote:

[...]

> >>
> >>
> >> No, but you don't need to. Just install the file to /usr/lib/systemd/user,
> >> and that's it. It'll be available to all users.
> >>
> >> If you want to forcefully enable the service for all users, then also
> >> symlink it into /usr/lib/systemd/user/default.target.wants/, which is
> >> almost exactly what `systemctl enable` does (except system-wide).
> >> That'll make it start on login for everyone.
> >>
> > 
> > Excellent! `systemctl --user enable' always did the symbolic
> > link under `$HOME/.config/systemd/user/'; I mistakenly thought
> > that it must be done _only_ this way for each and every user.
> > 
> > Now I understand; it seems it was done that way just not to affect
> > other users of the system. It couldn't be done any other way due
> > to the system permissions of /usr/lib/systemd/user
> 
> Note, that this *forces* it on every user, you can also enable it for
> every user as part of package installation by running "systemctl
> --global enable <yourservice>"
>
> The --global flag means "globally for all users" (it only applies to the
> user instance, so the --user part is not needed).
> 
> This writes the enablement symlink into
> /etc/systemd/user/default.target.wants/ (or whatever your service file
> states as it's WantedBy= directive).
>

Indeed, this is much cleaner. Thanks for the tip ;-)

> Ultimately this is a packaging issue, so I would suggest that your "make
> install" does not write anything here, but your document things for
> packagers that *iff* they want the package to be enabled by all users,
> then they run "systemctl --global enable <yourservice>" on initial
> package installation (or better run "systemctl --global preset
> <yourservice>" to allow package preset system to take on board the
> distro-wide defaults from *.preset files (see "man 5 systemd.preset")
> 
> This is ultimately what PulseAudio itself does/recommends when started
> from the user session as you are trying to do, so I'd suggest you follow
> suit.
>

Hmm, I was not aware of systemd.preset(5) before. This looks like
the correct approach indeed when packaging this for Debian and/or
RPM Fusion. Thanks again ;-)

And now to the core issue:

> >> But the general rule is, do not start user-session processes from system
> >> tasks.
> > 
> > Having the service installed `per-user' was something that was
> > unfortunately forced. I will still inspect what will happen when
> > two logged-in users lead to two instances of the daemon running :-(
> 
> Ultimately, if your daemon connects to PA, then you could react
> appropriately. e.g. if PA is suspended because the user no longer has
> access to the h/w devices, this information will be made available via
> PA APIs and your daemon can react accordingly.
>
> e.g. if you have two users, and one user wants this service and one does
> not, then you can react accordingly. e.g. one user may expose their
> sharing services as "Bob's Laptop" which may be getting used by some
> systems, but when Alice, logs in (via fast user switch) then it might
> expose also "Alice's Laptop" and let a different set of devices connect
> to it.
> 
> This is kinda how things are meant to work, but it does expose some
> issues in PA that cross some interesting boundaries. Ultimately people
> want to use things in different ways... here, you probably don't want to
> think about "Bob's Laptop" vs. "Alice's Laptop"... I'm guessing you just
> want to think about "the Laptop that Bob normally uses, but Alice
> sometimes logs into" and you want to play sound to it be able to play
> sound on it at all times. This is understandable, but until very
> recently, the security problems and management rules of device access
> make this a very hard problem to solve in PA.
>

Exactly! The service I'm trying to make Systemd-native is an Apple
AirTunes audio server. An AirTunes server mirros an iOS device
audio output over the local network.

Such a server is usually used to listen to music from a supposedly
higher quality PC speakers than the ones shipped inside an iPhone
or an iPad. Service discovery is done using multicast DNS (Avahi).

Now when one or more AirTunes service is available over the local
WiFi network, the iOS device displays an `AirPlay' button. This
button displays all __machines__ on the local network that have
the AirTunes facility.

So the concept of a "user session" does not sync well with this
service. The user is more interested in discovering "machines"
declaring their audio service over the local network rather than
"user sessions" declaring their services.

Moreover, the application I'm trying to Systemd-ize exclusively
uses the 'simple' set of PulseAudio APIs. It just uses a combi-
nation of:

	pa_simple_new()
	pa_simple_write()
	pa_simple_drain()
	pa_simple_free()

function calls. [1]

Now when I run this over Ubuntu 15.04, the service first runs
under the `lightdm' login session, and I can mirror audio from
an iPad to the PC succesfully. But then, if I login with my main
machine user, the audio disappears :-(

Of course the technical reason is that my service, and the PA
instance it's using, runs under the `lightdm' session:

	$ ps aux | grep shair
	lightdm   4529  1.5  0.2 529192  9328 ? Ssl  00:28   0:00 /usr/local/bin/shairport-sync

And a new version cannot be started under the just-logged-in
session; the current code does not support running multiple
instances in parallel.

But interestingly, this would be problematic _even if_ the daemon
was modified to run multiple instances succesfully! In such a
case, and from a user perspective, after I login on my PC, I have
to re-open my iPhone or iPad, press the AirPlay button again, and
switch to the new `shairport-sync' instance of the logged-in user
-- a very cumbersome process.

And if two users was logged in parallel, two `machines' will be
displayed from the iOS AirPlay button. And in that case, no
indication will be available on which `session' is the one where
I can _really_ listen to audio from --  only one of them will
just "work".

> .. With the advent of kdbus,
> some of these security problems can be solved more efficiently now so
> perhaps one day we'll see a newer version of PA based on kdbus which
> splits into a system component and a per-user component (various changes
> are required for proper application sandboxing too) or some other
> mechanism that would allow you to do this "device level" configuration.
>

For services like the one I'm dealing with now, this looks _very_
desirable indeed! PulseAudio "just worked" for me, so I never got
into its internals, but it seems a need for such a feature is
also evidenced by the large HowTOs on the internet describing how
to run PA as a system-wide daemon. [2]

> I don't honestly know, but there will need to be some serious
> development done there at some point in the not too distant future. Who
> will be able to step up and do that work is sadly unknown at this time
> (to the best of my knowledge anyway).
>

This is quite interesting.

The usecase of streaming audio from an iOS device to a Linux
"machine" over the local network (instead of a user sesssion)
is of deep personal interest. I stream Rdio to my Linux box
over the network all the time :-)

What is your preferred medium for discussing this further?

> Until then, the best situation is that a given device:
> 
> 1. will typically belong to one user (I'd say most of the time, there is
> only one user account anyway)
> 2. said user would auto-login and thus when the machine is on, the user
> is logged in an PA is started
>  or
> 2b. said user has "lingering" enabled (see "man 1 loginctl" and the
> "enable-linger" verb) and thus starts a per-user dbus/PA/yourservice
> even when the user has not yet logged in (i.e. waiting on gdm login
> screen for username+password).
>

Hmm, "lingering" .. very interesting. After reading the man page,
this almost did it indeed.

I've just done a ``loginctl enable-linger'' on my system. And now
in the next reboot, my service runs indeed under the main system
user (`darwish') instead of `lightdm'.

Unfortunately this has led to further problems, which kind of
exist by the very definition of `enable-linger':

1) The service runs indeed under the user `darwish', even without
   login, and the iOS device shows the `AirPlay' button. But the
   directed audio does not work now except after login :-(

   So the iOS device (correctly) shows that it's forwarding audio
   to my PC, but actually nothing comes out of the speakers
   except after I login. Not very intuitive -- and a little bit
   misleading.

2) If I logged in to another user instead of `darwish', the iOS
   device will also (correctly) shows that it's forwarding audio
   to my PC, but nothing will come out of the speakers.

   In multi-user setups, this would be quite odd.

3) It would not be nice to do a ``loginctl enable-linger'' from a
   small Github project Makefile installation script. This
   changes the system behaviour in very deep terms.

Unless I'm mistaken, it seems that the futuristic "PA + kdbus"
solution is more user friendly to everyone involved.

[Sidenote: it's interesting that the authors of the daemon I'm
porintg to Systemd advise users to use the ALSA backed instead
of the PA backend by default: PA installations usually fail due
to similar session "Connection Refused" problems. So it seems
that the "PA + kdbus" solution will be also a win for PA in
terms of an even more "working out of the box" experience.

The reason I'm sticking with PA though, is that if I'm going to
'modernize' the server and use Systemd in the first place, then
let's go the whole way and use PA as the default audio backend
in the process. End Sidenote]

> This solves the problem for the vast majority of users who want to use
> your stuff on their own devices. Alice may still sometimes login to
> Bob's computer and your application should still gracefully handle that
> (ultimately if PA says it cannot access the audio device, you should
> propagate that information to any remote clients - this will be as true
> with any newer structure as it is now, so may as well code defensively
> for that now!), but for the common case, everything just works.
>
> 
> > Can we disable multiple instances of the daemon in a systemd-native
> > way, even when the service is run per user? 
> 
> No. Ultimately your daemon should just be capable of handling it's
> access to audio h/w disappearing. Whether this means it just disconnects
> clients and stops listening on the network, or whether it can pause/cork
> itself neatly (I guess it depends on the remote protocol) is up to you,
> but ultimately it should be handled for various reasons, not just this
> one (e.g. say the user goes on a VoIP call. They likely want to
> cork/pause any streams playing under those circumstances too - while
> this isn't exactly the same, it's another situation where PA will tell
> you to stop playing).
>

Hmm, I just thought that making this small PulseAudio application
Systemd-native would be just a "Small Matter of Programming" ;-) [3]

> > Yes, this question
> > implies a possible problem in the design, but again, having the
> > service per-user is the only choice we have so far.
> > 
> > Thanks a lot Mantas for your help!
> 
> 
> I hope my reply has shed some light on the situation for you.
>

Well, you've done way more than that :-)

> I'll try and clarify anything that doesn't make sense, if you ask for
> clarifications.
>

Again, thanks a lot!! You reply was very helpful indeed.

Regards,
Ahmed S. Darwish
http://darwish.chasingpointers.com/

[1] https://github.com/mikebrady/shairport-sync/blob/master/audio_pulse.c
[2] https://google.com/search?q=pulseaudio+system
[3] http://www.catb.org/jargon/html/S/SMOP.html


More information about the systemd-devel mailing list