JACKdbus - Desktop integration - backend-switching

Prototype of automatic backend-switching for JACK2 using dbus.

You may know this Mac/OSX feature: one plugs or unplugs an external audio-interfaces and the system automatically switches the sound to the new device. - It may not always be what you want, but it is an very handy feature especially for mobile systems. and here's how to set this up for JACK on GNU/Linux..

Overview

First, we need a mechanism to switch the “JACK backend” in order to switch between audio-interfaces. The task includes taking care of re-connecting physical I/O ports in case they're different on each device.

Second, said mechanism needs to be triggered automatically when a new device is connected or if a device goes away. Here's a short annotated demo-video:

(If Flash is installed JavaScript is activated, you can watch a video inside this web page.)

(well yes, I should have ripped out that USB cord more visibly.. sorry, next time. I might use a real camera too, then.)

Prerequisites

Download:

Note: dbus-triggerd and a jack2 debian packages (source and i386) are available from

deb http://rg42.org/deb/ sid main

Installation and testing

  1. get jack2, patch, compile and install (or get the debian package).
  2. compile and install dbus-triggerd (or get the debian package).
  3. download and install myjackctl.sh to PATH (~/bin or /usr/local/bin), chmod +x.
  4. open a window to watch tail -f ~/.log/jack/jackdbus.log
killall -9 jackd jackdbus # clean start
jack_control eps verbose true        # tell jackdbus to be verbose
myjackctl.sh alsa hw:0 1024  48000 3 # launch jackd on first ALSA interface -p1024 -r48000 -n3
myjackctl.sh alsa hw:1               # switch to second ALSA interface

Launch some jack clients, players etc and repeat testing with myjackctl.sh.

Automating it with dbus-triggerd

dbus-triggerd is a tool to trigger shell-commands upon receiving a given dbus-signal.

It can be used to invoke myjackctl.sh in order to change the JACK-backend if

  • a new audio-interface is connected (system-dbus org.freedesktop.Hal.Manager,member=DeviceAdded) → use the newly connected device.
  • an audio-interface is disconnected (system-dbus org.freedesktop.Hal.Manager,member=DeviceRemoved) → switch to a fallback audio-interface.
  • JACK daemon signals device-error (session-dbus org.jackaudio.JackControl,member=DeviceError) → switch to a fallback audio-interface.

The two last are redundant and exclusive. JACKd still needs a patch to send a DeviceError. Using HAL's DeviceRemoved may be problematic for setups with more than two sound-cards if the removed device was not currently the one used by JACK.

Example to launch dbus-triggerd:

#!/bin/sh
make || exit
killall dbus-triggerd

### switch to sound 'hw:0' on any DeviceError
# This requires a patched JACK2, that sends a DeviceError
./dbus-triggerd $@ "type='signal',path=/org/jackaudio/Controller,interface=org.jackaudio.JackControl,member=DeviceError" --shell "myjackctl.sh alsa hw:0" &

# This an alternative to the above, using the HAL message
#dbus-triggerd $@ --system "type='signal',path=/org/freedesktop/Hal/Manager,interface=org.freedesktop.Hal.Manager,member=DeviceRemoved,arg0=/org/freedesktop/Hal/devices/usb_device_582_74_noserial_if0_sound_card_2" --shell "myjackctl.sh alsa hw:0" &

### switch to external USB sound device 'hw:2' when it's connected
./dbus-triggerd $@ --system "type='signal',path=/org/freedesktop/Hal/Manager,interface=org.freedesktop.Hal.Manager,member=DeviceAdded,arg0=/org/freedesktop/Hal/devices/usb_device_582_74_noserial_if0_sound_card_2" --shell "myjackctl.sh alsa hw:2" &

Implementation

Here be dragons…

The mechanism for backend-switching is implemented by a shell-script myjackctl.sh (which call dbus-send) that controls jack2d by exchanging dbus-messages.

myjackctl.sh is started with different command-line parameters on-demand by dbus-triggerd.

  • org.freedesktop.Hal.Manager,member=DeviceAdded
  • org.jackaudio.JackControl,member=DeviceError (requires patch to jack2)
  • (or) org.freedesktop.Hal.Manager,member=DeviceRemoved

Note that myjackctl.sh uses the org.jackaudio.PatchBay dbus-API which is broken in jack2-r4120 (see ticket below) and fixed by Nedko in jack2-r4366.

Future: Instead of patching jack2 to send additional messages (here: org.jackaudio.JackControl,member=DeviceError), the trigger functionality should be built into jackd, but requires a callback to the control API to be added to JACK.

The shell hook-script (myjackctl.sh) could be implemented easier and more flexible using python (jack-control API bindings) or similar language more suitable to parse and provide audio-port mapping and configuration.

References

 
blog/jack2dbus.txt · Last modified: 09.05.2012 16:49 by rgareus