System Jack Service

What if we want to set jack to be system service? I know, I know, I read all the fine manuals and a reason behind avoiding system sound daemon, whether it is pulse or jack. But hey - this is my PC, don't tell me what I cannot do!

After all this is HTPC and all services are focused on media. What? Yes, htpc, not a sound production laptop, or HPC media server. And nothing can stop me from doing whatever I want to make my life more cozy.

We will be starting Jack via DBus. Normally if you start trying jack_control command in the console it will start barfing about missing X and as a consequence inability to create DBus session. This is blatant lie. In fact it just cannot find proper mechanism to initialize session, falls back to X session, and finally dies. To make it happen it is sufficient to initialize session manually: execute dbus-launch and export its variables to the shell environment. Once done you can use jack_control to manage jackdbus daemon.

This is something we can put into upstart service description to start the daemon on startup. Only need to add one missing point. jackdbus being user session daemon is really expecting HOME env var to be set - to initialize config under XDG user config. With that in mind we draw something like this:

description "Starts and stops jackd2 system service.
Even though general idea is flowd it can be usefull in
some cases like system-wide jack-alsa bridge via loop"
author "Ruslan N. Marchenko <me@ruff.mobi>"

start on runlevel [2345] or local-filesystems
stop on runlevel [!2345]
emits audio-bus

console log

env HOME=/root

pre-start script
if [ ! -f /run/dbus/.env ]; then
  eval `dbus-launch --auto-syntax`
  echo "export DBUS_SESSION_BUS_PID=$DBUS_SESSION_BUS_PID" > /run/dbus/.env
  echo "export DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS" >> /run/dbus/.env
  chmod 600 /run/dbus/.env
end script

post-start script
. /run/dbus/.env
jack_control start
if [ -f /etc/default/jackd ]; then
  awk '/^[esdri]/{system("jack_control "$0)}' /etc/default/jackd
  awk '/^ /{system("jack_load "$0)}' /etc/default/jackd
  awk '/^>/{  
        system("jack_connect "$2":capture_1 "$3":playback_1");
        system("jack_connect "$2":capture_2 "$3":playback_2");
  }' /etc/default/jackd
end script

post-stop script
. /run/dbus/.env
if [ -f /etc/default/jackd ]; then
  awk '/^ /{system("jack_unload "$1)}' /etc/default/jackd
jack_control exit
end script

First we define service settings: start on system startup, stop politely, even send own event, if anyone cares (no one does). Next we setting HOME to root's home dir. This is system wide service, let root configure and control it. Pre-start section is initializing DBus session. Here we're using persistent session settings stored in volatile memory filesystem. On boot it will not exist, once created we stick to spawned dbus session till system reboots. Keep that in mind if you decide for some reason clean up dbus sessions. Further on, you can add '[ -f /run/dbus/.env ] && source /run/dbus/.env' line in ~/.profile to get DBus session populated to your interactive session. Be aware though - jack's native api calls, like alsa jack plugin, or LADI apps will be possible to execute only from this root session! So it really only does make sense on personless home-server for case like pulling together alsa-loop bridge and, maybe, network protocol stack.

We're using only pre/post scripts since actual daemon is kept by dbus and upstart has nothing to control/respawn. So once session is initialized in pre-start section, post-start section is starting actual daemon and does some additional fine tuning. Finally post-stop stanza is amed to make graceful shutdown.

I've moved additional setup into /etc/default/jackd file so that I can setup my adaptors and other bells and whistles. Comments in file are self-decriptive:

# jack_control command file. All lines not starting
# with # ant representing valid jack_control commands
# will be executed by jack_control. Lines starting
# with space will be processed by jack_load. Lines
# starting with > are port groups to connect.
iload netmanager
 jab1 audioadapter -- '-dhw:JABridge -Chw:JABridge,1,0 -Phw:JABridge,1,1 -i2 -o2'
 hdmi audioadapter -- '-dhw:Generic -Chw:Generic,1 -Phw:VT82xx,0 -i2 -o2'
> jab1 system
> jab1 hdmi
 net netadapter
> jab1 net

Once daemon is started you can switch to root with sudo, import dbus session from .env file and do jack configuration via jack_control command. Aparently, next step would be to set system pulse server on top of jack bus.

Sun Feb 3 02:14:31 2013 Upd.: Sat Feb 9 21:31:57 2013
© ruff 2011