[Jack-Devel] Some observations re Jack and systemd

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[Jack-Devel] Some observations re Jack and systemd

Jörn Nettingsmeier-5
Hi everyone,


after scratching my head for a long time to make systemd behave when
running jack as a service, I thought I'd share my findings:

Example service file:

[Unit]
Description=JACK Audio Connection Kit
After=sound.target
After=ntp.service
After=time-sync.target
Before=jackd.target
Requires=jackd.target

[Service]
EnvironmentFile=-/your/config/file/containing/JACKD_OPTIONS
LimitRTPRIO=85
LimitMEMLOCK=700000000
User=nettings
Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket"
ExecStartPre=/bin/sleep 10
ExecStart=/usr/bin/jackd $JACKD_OPTIONS
RestartSec=5
Restart=on-failure

[Install]
WantedBy=multi-user.target


So it's easy to start a service as a user, but that user's environment
is not automatically pulled in. That means even though user nettings
does have the necessary permissions in /etc/security/limits.conf, you
still need to spell them out for systemd.

Another thing to note is that at least on current raspbian, the
time-sync.target is broken. Its promise is to only be triggered after
ntp has worked its magic and the system time is monotonous. However,
I've seen time jumps which combined with cheap USB hardware or the
builtin Raspi sound will hang jack. Hence the ugly sleep.

Final goodness: systemd might try to clean up after you. So when you
have a jackd service started in your name, all is well, until you have
logged in somehow and then closed the last shell, at which point the
janitor from hell will happily clear /dev/shm and with it all your jack
semaphores, leading to instant dumpster fire and silence.

This magic can be avoided by setting
RemoveIPC=no
in /etc/systemd/logind.conf

After clearing these hurdles, I've been quite happy with how systemd
handles jack clients.  The usecase here is a number of clients running
in an embedded appliance, and systemd takes care of restoring them when
I cause them to crash, which is good. Not that they crash, but it's good
to have defense in depth.
Figuring out how to order services is hard because you cannot assume a
service is really ready when systemd has fired it off. So I've used a
ExecStartPre script that blocks until a downstream jack port has
appeared in those cases where I want to start clients in a particular
order (matters most for the one job that needs to connect all the ports,
so I let it wait on a test port for each client it needs to connect).

Old-time SysV user here, and granted, systemd has given me many a WTF
moment, but it does its job. Unfortunately, it does too many other jobs
as well, but hey...


--
Jörn Nettingsmeier
Tuinbouwstraat 180, 1097 ZB Amsterdam, Nederland
Tel. +49 177 7937487

Meister für Veranstaltungstechnik (Bühne/Studio), Tonmeister VDT
http://stackingdwarves.net
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Some observations re Jack and systemd

Chris Caudle
On Fri, December 21, 2018 2:24 pm, Jörn Nettingsmeier wrote:
> Example service file:
>
> [Unit]
> Description=JACK Audio Connection Kit
> After=sound.target
> After=ntp.service
> After=time-sync.target
> Before=jackd.target
> Requires=jackd.target


I assume your service file would be jackd.service, can you explain how the
requires jackd.target works?  I am familiar with service files, but only
vaguely have seen target in reference to systemd (mostly in using
runlevel3.target or runlevel5.target as replacement for old init commands
to change runlevel).

--
Chris Caudle


_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Some observations re Jack and systemd

John Rigg-16
In reply to this post by Jörn Nettingsmeier-5
On Fri, Dec 21, 2018 at 09:24:01PM +0100, Jörn Nettingsmeier wrote:
> after scratching my head for a long time to make systemd behave when  
> running jack as a service, I thought I'd share my findings

Thanks for posting this. I'm still using sysvinit, but this
stuff may (unfortunately) become necessary to know.

John
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Some observations re Jack and systemd

Christian Affolter
In reply to this post by Jörn Nettingsmeier-5
Hi Jörn

thanks for sharing this.

Some time ago I've also had to write systemd service units for running a
headless jackd in combination with "rotter" for a recording solution.

The service file is available at [1] and the documentation at [2] in
case you're interested. It supports multiple jackd instances (it was
written as a generic systemd service unit template) and uses the
"jack_wait" command to wait for jackd to be up and running. It was
designed to be as generic as possible an let the local administrator
configure certain settings using systemd service instance overrides (see
[3] for an example with alsa).

Best regards,
Chris

[1]
https://github.com/radiorabe/centos-rpm-rotter/blob/master/jackd%40.service
[2]
https://github.com/radiorabe/centos-rpm-rotter#systemd-service-unit-templates-explained
[3]
https://github.com/radiorabe/centos-rpm-rotter#running-rotter-through-systemd


On 21.12.2018 21:24, Jörn Nettingsmeier wrote:

> Hi everyone,
>
>
> after scratching my head for a long time to make systemd behave when
> running jack as a service, I thought I'd share my findings:
>
> Example service file:
>
> [Unit]
> Description=JACK Audio Connection Kit
> After=sound.target
> After=ntp.service
> After=time-sync.target
> Before=jackd.target
> Requires=jackd.target
>
> [Service]
> EnvironmentFile=-/your/config/file/containing/JACKD_OPTIONS
> LimitRTPRIO=85
> LimitMEMLOCK=700000000
> User=nettings
> Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket"
>
> ExecStartPre=/bin/sleep 10
> ExecStart=/usr/bin/jackd $JACKD_OPTIONS
> RestartSec=5
> Restart=on-failure
>
> [Install]
> WantedBy=multi-user.target
>
>
> So it's easy to start a service as a user, but that user's environment
> is not automatically pulled in. That means even though user nettings
> does have the necessary permissions in /etc/security/limits.conf, you
> still need to spell them out for systemd.
>
> Another thing to note is that at least on current raspbian, the
> time-sync.target is broken. Its promise is to only be triggered after
> ntp has worked its magic and the system time is monotonous. However,
> I've seen time jumps which combined with cheap USB hardware or the
> builtin Raspi sound will hang jack. Hence the ugly sleep.
>
> Final goodness: systemd might try to clean up after you. So when you
> have a jackd service started in your name, all is well, until you have
> logged in somehow and then closed the last shell, at which point the
> janitor from hell will happily clear /dev/shm and with it all your jack
> semaphores, leading to instant dumpster fire and silence.
>
> This magic can be avoided by setting
> RemoveIPC=no
> in /etc/systemd/logind.conf
>
> After clearing these hurdles, I've been quite happy with how systemd
> handles jack clients.  The usecase here is a number of clients running
> in an embedded appliance, and systemd takes care of restoring them when
> I cause them to crash, which is good. Not that they crash, but it's good
> to have defense in depth.
> Figuring out how to order services is hard because you cannot assume a
> service is really ready when systemd has fired it off. So I've used a
> ExecStartPre script that blocks until a downstream jack port has
> appeared in those cases where I want to start clients in a particular
> order (matters most for the one job that needs to connect all the ports,
> so I let it wait on a test port for each client it needs to connect).
>
> Old-time SysV user here, and granted, systemd has given me many a WTF
> moment, but it does its job. Unfortunately, it does too many other jobs
> as well, but hey...
>
>

_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Some observations re Jack and systemd

Jörn Nettingsmeier-5
In reply to this post by Jörn Nettingsmeier-5
[replying on the list]
Hi,

On 12/22/18 5:15 PM, [hidden email] wrote:
> Hey Jörn!
>
> Thanks a lot for sharing this! I will try this tomorrow since I tried to do something similar but always had audible “xruns” / popping (even with setting buffersize to 256).
>
> One question: -/your/config/file/containing/JACKD_OPTIONS <— what’s the content of this file?

It's a file where I keep all changes that are specific to a particular
Raspi box, so that my service files are generic. If you're only
interested in your one studio machine, you might as well not use it and
hardcode the necessary jack options below.

Caveat: while you might think systemd can parse shell syntax, it really
doesn't, its parser is very simple. So you have to make to with simple
KEY=value
pairs, even multiline variables will make it choke.


--
Jörn Nettingsmeier
Tuinbouwstraat 180, 1097 ZB Amsterdam, Nederland
Tel. +49 177 7937487

Meister für Veranstaltungstechnik (Bühne/Studio), Tonmeister VDT
http://stackingdwarves.net
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Some observations re Jack and systemd

Jörn Nettingsmeier-5
In reply to this post by Christian Affolter
On 12/22/18 12:54 PM, Christian Affolter wrote:

> Hi Jörn
>
> thanks for sharing this.
>
> Some time ago I've also had to write systemd service units for running a
> headless jackd in combination with "rotter" for a recording solution.
>
> The service file is available at [1] and the documentation at [2] in
> case you're interested. It supports multiple jackd instances (it was
> written as a generic systemd service unit template) and uses the
> "jack_wait" command to wait for jackd to be up and running. It was
> designed to be as generic as possible an let the local administrator
> configure certain settings using systemd service instance overrides (see
> [3] for an example with alsa).


Hey, nice, thanks. You are using a few features I didn't know yet,
looking forward to checking them out. Especially "BindsTo" looks like it
could be very useful (I found it explained in man systemd.units) - looks
like any jack client service should be bound to Jack pretty much
unconditionally unless it would survive the server going away and coming
back somehow.


--
Jörn Nettingsmeier
Tuinbouwstraat 180, 1097 ZB Amsterdam, Nederland
Tel. +49 177 7937487

Meister für Veranstaltungstechnik (Bühne/Studio), Tonmeister VDT
http://stackingdwarves.net
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Some observations re Jack and systemd

Jörn Nettingsmeier-5
In reply to this post by Chris Caudle
On 12/21/18 10:08 PM, Chris Caudle wrote:

> On Fri, December 21, 2018 2:24 pm, Jörn Nettingsmeier wrote:
>> Example service file:
>>
>> [Unit]
>> Description=JACK Audio Connection Kit
>> After=sound.target
>> After=ntp.service
>> After=time-sync.target
>> Before=jackd.target
>> Requires=jackd.target
>
>
> I assume your service file would be jackd.service, can you explain how the
> requires jackd.target works?  I am familiar with service files, but only
> vaguely have seen target in reference to systemd (mostly in using
> runlevel3.target or runlevel5.target as replacement for old init commands
> to change runlevel).
>

To be honest, I don't have a full understanding yet. Looking at the
behaviour of standard targets of the distro has helped me, and there's
man systemd.special.

The quick summary is this:
A target itself knows nothing and does nothing interesting.

Mine looks like:
[Unit]
Description=jackd sound server target
After=sound.target jackd.service
Requires=sound.target jackd.service

So all it does is it needs other things, _and_ they need to happen
first, hence the duplication in After= and Requires=.
(It took me a while to understand that for systemd, "Requires=" doesn't
mean it has to be there when this unit is started, only that it will be
activated eventually...)

My jackd.target knows it can only become active after the sound.target
is reached and the jackd.service is active.

The semantics I gleaned from man systemd.special are these:

For a "passive" target like this, only the provider(s) of the necessary
services should pull it in (in systemd lingo, this means "Requires=" or
at least "Wants="). In this case, that's jackd.service.
Other services that need jack.target to be reached should not pull it
in, but only order themselves after it (using "After=").


--
Jörn Nettingsmeier
Tuinbouwstraat 180, 1097 ZB Amsterdam, Nederland
Tel. +49 177 7937487

Meister für Veranstaltungstechnik (Bühne/Studio), Tonmeister VDT
http://stackingdwarves.net
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org