diff -U 3 -H -b -d -r -N -- jack1.old/Makefile.am jack1/Makefile.am
--- jack1.old/Makefile.am	2013-10-06 16:46:26.000000000 +0100
+++ jack1/Makefile.am	2013-10-06 17:44:19.753394871 +0100
@@ -28,6 +28,11 @@
 
 dist-hook: dist-check-doxygen
 
+if HAVE_DBUS
+install-data-hook:
+	@if test "`ps h -C jackdbus`" ; then echo; echo; echo 'WARNING: jackdbus seems to be running, you may want to deactivate current service using "jack_control exit".'; echo; echo; fi
+endif
+
 libjackincludedir = $(includedir)/jack
 
 libjackinclude_HEADERS =   \
diff -U 3 -H -b -d -r -N -- jack1.old/configure.ac jack1/configure.ac
--- jack1.old/configure.ac	2013-10-06 16:46:26.000000000 +0100
+++ jack1/configure.ac	2013-10-06 17:44:19.755394846 +0100
@@ -727,6 +727,43 @@
 # PKG_CHECK_MODULES inside a --disable-whatever check, you need to
 # do it somewhere *below* this comment.
 
+AC_ARG_ENABLE(dbus, [  --disable-dbus          don't build D-Bus integration ],
+			TRY_DBUS=$enableval , TRY_DBUS=yes ) 
+HAVE_DBUS=false
+if test "x$TRY_DBUS" = "xyes"
+then
+	PKG_CHECK_MODULES(DBUS, dbus-1, [AC_DEFINE([HAVE_DBUS], 1, [Defined if D-Bus support needs to be built.]) HAVE_DBUS=true], [true])
+fi
+
+AM_CONDITIONAL(HAVE_DBUS, $HAVE_DBUS)
+
+AC_ARG_ENABLE(pkg-config-dbus-service-dir,
+	[  --enable-pkg-config-dbus-service-dir    force D-Bus service install dir to be one returned by pkg-config ],
+	DBUS_SERVICES_DIR_FORCE_REAL=$enableval , DBUS_SERVICES_DIR_FORCE_REAL=no ) 
+
+if test "x$HAVE_DBUS" = "xtrue"
+then
+	DBUS_SERVICES_DIR_REAL=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`
+	if test "x$DBUS_SERVICES_DIR_FORCE_REAL" = "xyes"
+	then
+		AC_MSG_WARN([overriding D-Bus service install dir])
+		DBUS_SERVICES_DIR="$DBUS_SERVICES_DIR_REAL"
+	else
+		AS_AC_EXPAND(DATADIR, $datadir)
+		DBUS_SERVICES_DIR="$DATADIR/dbus-1/services"
+	fi
+	AC_SUBST(DBUS_SERVICES_DIR)
+	AC_DEFINE_UNQUOTED(DBUS_SERVICES_DIR, "$DBUS_SERVICES_DIR", [Where services dir for DBUS is])
+fi
+
+HAVE_LIBXML2=false
+PKG_CHECK_MODULES(LIBXML2, libxml-2.0, [AC_DEFINE([HAVE_LIBXML2], 1, [Defined if libxml2 is present.]) HAVE_LIBXML2=true], [true])
+AM_CONDITIONAL(HAVE_LIBXML2, $HAVE_LIBXML2)
+
+AC_CHECK_LIB(expat, XML_ParserCreate_MM,
+             [ AC_CHECK_HEADERS(expat.h, HAVE_EXPAT=true, HAVE_EXPAT=false) ],
+             HAVE_EXPAT=false)
+
 # Check which backend drivers can be built.  The last one successfully
 # configured becomes the default JACK driver; so the order of
 # precedence is: alsa, sun, oss, coreaudio, portaudio, dummy.
@@ -893,6 +930,39 @@
 AM_CONDITIONAL(STRIPPED_JACKD, $STRIPPED_JACKD)
 AM_CONDITIONAL(HAVE_PPOLL, $HAVE_PPOLL)
 
+SETTINGS_PERSISTENCE_WARNING=
+SETTINGS_PERSISTENCE_USE_LIBXML2=false
+SETTINGS_PERSISTENCE_USE_EXPAT=false
+SETTINGS_PERSISTENCE_DISABLED=true
+
+if test x$HAVE_EXPAT = xtrue
+then
+  SETTINGS_PERSISTENCE=expat
+  SETTINGS_PERSISTENCE_USE_EXPAT=true
+  SETTINGS_PERSISTENCE_DISABLED=false
+  AC_DEFINE_UNQUOTED(SETTINGS_PERSISTENCE_USE_EXPAT, 1, [Whether expat is used as settings persistence backend])
+else
+  if test x$HAVE_LIBXML2 = xtrue
+  then
+    if test x$HAVE_FIREWIRE = xtrue
+    then
+      SETTINGS_PERSISTENCE=no
+      SETTINGS_PERSISTENCE_WARNING="libxml2 usage is incompatible with FireWire (FFADO) driver. If you want settings persistence, install expat or disable FireWire (FFADO) driver."
+    else
+      SETTINGS_PERSISTENCE=libxml2
+      SETTINGS_PERSISTENCE_USE_LIBXML2=true
+      SETTINGS_PERSISTENCE_DISABLED=false
+      AC_DEFINE_UNQUOTED(SETTINGS_PERSISTENCE_USE_LIBXML2, 1, [Whether libxml2 is used as settings persistence backend])
+    fi
+  else
+    SETTINGS_PERSISTENCE=no
+  fi
+fi
+
+AM_CONDITIONAL(SETTINGS_PERSISTENCE_USE_LIBXML2, $SETTINGS_PERSISTENCE_USE_LIBXML2)
+AM_CONDITIONAL(SETTINGS_PERSISTENCE_USE_EXPAT, $SETTINGS_PERSISTENCE_USE_EXPAT)
+AM_CONDITIONAL(SETTINGS_PERSISTENCE_DISABLED, $SETTINGS_PERSISTENCE_DISABLED)
+
 AC_OUTPUT(
 Makefile
 config/Makefile
@@ -962,9 +1032,28 @@
 echo \| Default driver backend................................ : $JACK_DEFAULT_DRIVER
 echo \| Shared memory interface............................... : $JACK_SHM_TYPE
 echo \| IPC Temporary directory............................... : $DEFAULT_TMP_DIR
+echo \| D-Bus integration .................................... : $HAVE_DBUS
+dnl echo \| D-Bus CFLAGS ......................................... : $DBUS_CFLAGS
+dnl echo \| D-Bus LIBS ........................................... : $DBUS_LIBS
+if test "x$HAVE_DBUS" = "xtrue"
+then
+echo \| D-Bus service install dir............................. : $DBUS_SERVICES_DIR
+echo \| Settings persistence.................................. : $SETTINGS_PERSISTENCE
+fi
 echo \| Install prefix........................................ : $prefix
 echo \| Default tmp dir....................................... : $DEFAULT_TMP_DIR
 echo
 
+if test "x$HAVE_DBUS" = "xtrue" -a "x$DBUS_SERVICES_DIR_REAL" != "x$DBUS_SERVICES_DIR"
+then
+	AC_MSG_WARN([D-Bus session services directory as reported by pkg-config is $DBUS_SERVICES_DIR_REAL])
+	AC_MSG_WARN([but service file will be installed in $DBUS_SERVICES_DIR])
+	AC_MSG_WARN([You may need to adjust your D-Bus configuration after installing jackdbus])
+	AC_MSG_WARN([You can override dbus service install dir])
+	AC_MSG_WARN([with --enable-pkg-config-dbus-service-dir option to this script])
+fi
 
- 
+if test "$SETTINGS_PERSISTENCE_WARNING"
+then
+	AC_MSG_WARN($SETTINGS_PERSISTENCE_WARNING)
+fi
diff -U 3 -H -b -d -r -N -- jack1.old/include/Makefile.am jack1/include/Makefile.am
--- jack1.old/include/Makefile.am	2013-10-06 16:46:26.000000000 +0100
+++ jack1/include/Makefile.am	2013-10-06 17:44:19.755394846 +0100
@@ -9,6 +9,7 @@
 	engine.h		\
 	hardware.h 		\
 	internal.h 		\
+	list.h			\
 	intsimd.h 		\
 	memops.h		\
 	messagebuffer.h		\
diff -U 3 -H -b -d -r -N -- jack1.old/include/engine.h jack1/include/engine.h
--- jack1.old/include/engine.h	2013-10-06 16:46:26.000000000 +0100
+++ jack1/include/engine.h	2013-10-06 17:44:19.756394834 +0100
@@ -172,6 +172,10 @@
     int audio_in_cnt;
     int midi_out_cnt;
     int midi_in_cnt;
+
+    void (* jackctl_port_registration_notify)(void * jackctl_context, jack_port_id_t port_id, int yn);
+    void (* jackctl_connection_notify)(void * jackctl_context, jack_port_id_t port1_id, jack_port_id_t port2_id, int connected);
+    void * jackctl_context;
 };
 
 /* public functions */
diff -U 3 -H -b -d -r -N -- jack1.old/include/list.h jack1/include/list.h
--- jack1.old/include/list.h	1970-01-01 01:00:00.000000000 +0100
+++ jack1/include/list.h	2013-10-06 17:44:19.758394809 +0100
@@ -0,0 +1,874 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*****************************************************************************
+ *
+ *   Linux kernel header adapted for user-mode
+ *   The 2.6.17-rt1 version was used.
+ *
+ *   Original copyright holders of this code are unknown, they were not
+ *   mentioned in the original file.
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *****************************************************************************/
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#if !defined(offsetof)
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define prefetch(x) (x = x)
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+  struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+  struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+  list->next = list;
+  list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+            struct list_head *prev,
+            struct list_head *next)
+{
+  next->prev = new;
+  new->next = next;
+  new->prev = prev;
+  prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+  __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+  __list_add(new, head->prev, head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add_rcu(struct list_head * new,
+    struct list_head * prev, struct list_head * next)
+{
+  new->next = next;
+  new->prev = prev;
+//  smp_wmb();
+  next->prev = new;
+  prev->next = new;
+}
+
+/**
+ * list_add_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
+{
+  __list_add_rcu(new, head, head->next);
+}
+
+/**
+ * list_add_tail_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_tail_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_tail_rcu(struct list_head *new,
+          struct list_head *head)
+{
+  __list_add_rcu(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+  next->prev = prev;
+  prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+  __list_del(entry->prev, entry->next);
+  entry->next = LIST_POISON1;
+  entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_rcu - deletes entry from list without re-initialization
+ * @entry: the element to delete from the list.
+ *
+ * Note: list_empty on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_del_rcu()
+ * or list_add_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ *
+ * Note that the caller is not permitted to immediately free
+ * the newly deleted entry.  Instead, either synchronize_rcu()
+ * or call_rcu() must be used to defer freeing until an RCU
+ * grace period has elapsed.
+ */
+static inline void list_del_rcu(struct list_head *entry)
+{
+  __list_del(entry->prev, entry->next);
+  entry->prev = LIST_POISON2;
+}
+
+/*
+ * list_replace_rcu - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * The old entry will be replaced with the new entry atomically.
+ */
+static inline void list_replace_rcu(struct list_head *old,
+        struct list_head *new)
+{
+  new->next = old->next;
+  new->prev = old->prev;
+//  smp_wmb();
+  new->next->prev = new;
+  new->prev->next = new;
+  old->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+  __list_del(entry->prev, entry->next);
+  INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+          struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+  return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+  struct list_head *next = head->next;
+  return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+         struct list_head *head)
+{
+  struct list_head *first = list->next;
+  struct list_head *last = list->prev;
+  struct list_head *at = head->next;
+
+  first->prev = head;
+  head->next = first;
+
+  last->next = at;
+  at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+  if (!list_empty(list))
+    __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+            struct list_head *head)
+{
+  if (!list_empty(list)) {
+    __list_splice(list, head);
+    INIT_LIST_HEAD(list);
+  }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:  the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+  container_of(ptr, type, member)
+
+/**
+ * list_for_each  - iterate over a list
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+  for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+          pos = pos->next)
+
+/**
+ * __list_for_each  - iterate over a list
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+  for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+  for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+          pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @n:    another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+  for (pos = (head)->next, n = pos->next; pos != (head); \
+    pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry  - iterate over list of given type
+ * @pos:  the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)        \
+  for (pos = list_entry((head)->next, typeof(*pos), member);  \
+       prefetch(pos->member.next), &pos->member != (head);  \
+       pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:  the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)      \
+  for (pos = list_entry((head)->prev, typeof(*pos), member);  \
+       prefetch(pos->member.prev), &pos->member != (head);  \
+       pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ *      list_for_each_entry_continue
+ * @pos:  the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+  ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ *      continuing after existing point
+ * @pos:  the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member)     \
+  for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
+       prefetch(pos->member.next), &pos->member != (head);  \
+       pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type
+ *      continuing from existing point
+ * @pos:  the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_from(pos, head, member)       \
+  for (; prefetch(pos->member.next), &pos->member != (head);  \
+       pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:  the type * to use as a loop counter.
+ * @n:    another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)      \
+  for (pos = list_entry((head)->next, typeof(*pos), member),  \
+    n = list_entry(pos->member.next, typeof(*pos), member); \
+       &pos->member != (head);          \
+       pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue -  iterate over list of given type
+ *      continuing after existing point safe against removal of list entry
+ * @pos:  the type * to use as a loop counter.
+ * @n:    another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member)     \
+  for (pos = list_entry(pos->member.next, typeof(*pos), member),    \
+    n = list_entry(pos->member.next, typeof(*pos), member);   \
+       &pos->member != (head);            \
+       pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list of given type
+ *      from existing point safe against removal of list entry
+ * @pos:  the type * to use as a loop counter.
+ * @n:    another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member)       \
+  for (n = list_entry(pos->member.next, typeof(*pos), member);    \
+       &pos->member != (head);            \
+       pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
+ *              removal of list entry
+ * @pos:  the type * to use as a loop counter.
+ * @n:    another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)    \
+  for (pos = list_entry((head)->prev, typeof(*pos), member),  \
+    n = list_entry(pos->member.prev, typeof(*pos), member); \
+       &pos->member != (head);          \
+       pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/**
+ * list_for_each_rcu  - iterate over an rcu-protected list
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_rcu(pos, head) \
+  for (pos = (head)->next; \
+    prefetch(rcu_dereference(pos)->next), pos != (head); \
+          pos = pos->next)
+
+#define __list_for_each_rcu(pos, head) \
+  for (pos = (head)->next; \
+    rcu_dereference(pos) != (head); \
+          pos = pos->next)
+
+/**
+ * list_for_each_safe_rcu - iterate over an rcu-protected list safe
+ *          against removal of list entry
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @n:    another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_safe_rcu(pos, n, head) \
+  for (pos = (head)->next; \
+    n = rcu_dereference(pos)->next, pos != (head); \
+    pos = n)
+
+/**
+ * list_for_each_entry_rcu  - iterate over rcu list of given type
+ * @pos:  the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_entry_rcu(pos, head, member) \
+  for (pos = list_entry((head)->next, typeof(*pos), member); \
+    prefetch(rcu_dereference(pos)->member.next), \
+      &pos->member != (head); \
+    pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/**
+ * list_for_each_continue_rcu - iterate over an rcu-protected list
+ *      continuing after existing point.
+ * @pos:  the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_continue_rcu(pos, head) \
+  for ((pos) = (pos)->next; \
+    prefetch(rcu_dereference((pos))->next), (pos) != (head); \
+          (pos) = (pos)->next)
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+  struct hlist_node *first;
+};
+
+struct hlist_node {
+  struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+  h->next = NULL;
+  h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+  return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+  return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+  struct hlist_node *next = n->next;
+  struct hlist_node **pprev = n->pprev;
+  *pprev = next;
+  if (next)
+    next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+  __hlist_del(n);
+  n->next = LIST_POISON1;
+  n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_rcu - deletes entry from hash list without re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry().
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+  __hlist_del(n);
+  n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+  if (!hlist_unhashed(n)) {
+    __hlist_del(n);
+    INIT_HLIST_NODE(n);
+  }
+}
+
+/*
+ * hlist_replace_rcu - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * The old entry will be replaced with the new entry atomically.
+ */
+static inline void hlist_replace_rcu(struct hlist_node *old,
+          struct hlist_node *new)
+{
+  struct hlist_node *next = old->next;
+
+  new->next = next;
+  new->pprev = old->pprev;
+//  smp_wmb();
+  if (next)
+    new->next->pprev = &new->next;
+  *new->pprev = new;
+  old->pprev = LIST_POISON2;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+  struct hlist_node *first = h->first;
+  n->next = first;
+  if (first)
+    first->pprev = &n->next;
+  h->first = n;
+  n->pprev = &h->first;
+}
+
+
+/**
+ * hlist_add_head_rcu - adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.  Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_add_head_rcu(struct hlist_node *n,
+          struct hlist_head *h)
+{
+  struct hlist_node *first = h->first;
+  n->next = first;
+  n->pprev = &h->first;
+//  smp_wmb();
+  if (first)
+    first->pprev = &n->next;
+  h->first = n;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+          struct hlist_node *next)
+{
+  n->pprev = next->pprev;
+  n->next = next;
+  next->pprev = &n->next;
+  *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+          struct hlist_node *next)
+{
+  next->next = n->next;
+  n->next = next;
+  next->pprev = &n->next;
+
+  if(next->next)
+    next->next->pprev  = &next->next;
+}
+
+/**
+ * hlist_add_before_rcu - adds the specified element to the specified hlist
+ * before the specified node while permitting racing traversals.
+ * @n: the new element to add to the hash list.
+ * @next: the existing element to add the new element before.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.
+ */
+static inline void hlist_add_before_rcu(struct hlist_node *n,
+          struct hlist_node *next)
+{
+  n->pprev = next->pprev;
+  n->next = next;
+//  smp_wmb();
+  next->pprev = &n->next;
+  *(n->pprev) = n;
+}
+
+/**
+ * hlist_add_after_rcu - adds the specified element to the specified hlist
+ * after the specified node while permitting racing traversals.
+ * @prev: the existing element to add the new element after.
+ * @n: the new element to add to the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.
+ */
+static inline void hlist_add_after_rcu(struct hlist_node *prev,
+               struct hlist_node *n)
+{
+  n->next = prev->next;
+  n->pprev = &prev->next;
+//  smp_wmb();
+  prev->next = n;
+  if (n->next)
+    n->next->pprev = &n->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+  for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+       pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+  for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+       pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos:  the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)      \
+  for (pos = (head)->first;          \
+       pos && ({ prefetch(pos->next); 1;}) &&      \
+    ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+       pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos:  the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)     \
+  for (pos = (pos)->next;            \
+       pos && ({ prefetch(pos->next); 1;}) &&      \
+    ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+       pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos:  the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)       \
+  for (; pos && ({ prefetch(pos->next); 1;}) &&      \
+    ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+       pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos:  the &struct hlist_node to use as a loop counter.
+ * @n:    another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member)      \
+  for (pos = (head)->first;          \
+       pos && ({ n = pos->next; 1; }) &&         \
+    ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+       pos = n)
+
+/**
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos:  the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_head_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu(tpos, pos, head, member)    \
+  for (pos = (head)->first;          \
+       rcu_dereference(pos) && ({ prefetch(pos->next); 1;}) &&   \
+    ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+       pos = pos->next)
+
+#endif
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/Makefile.am jack1/jackd/Makefile.am
--- jack1.old/jackd/Makefile.am	2013-10-06 16:46:26.000000000 +0100
+++ jack1/jackd/Makefile.am	2013-10-06 17:44:19.761394771 +0100
@@ -1,4 +1,5 @@
 MAINTAINERCLEANFILES = Makefile.in jackd.1 jack_md5.h 
+MOSTLYCLEANFILES =
 
 if USE_CAPABILITIES
 CAP_PROGS = jackstart
@@ -21,10 +22,17 @@
 
 bin_PROGRAMS = jackd $(CAP_PROGS)
 
-AM_CFLAGS = $(JACK_CFLAGS) -DJACK_LOCATION=\"$(bindir)\"
+if HAVE_DBUS
+bin_PROGRAMS += jackdbus
+endif
 
-jackd_SOURCES = jackd.c
-jackd_LDADD = libjackserver.la $(CAP_LIBS) @OS_LDFLAGS@
+AM_CFLAGS = $(JACK_CFLAGS) -DJACK_LOCATION=\"$(bindir)\" $(DBUS_CFLAGS) $(LIBXML2_CFLAGS)
+
+COMMON_SOURCES = engine.c clientengine.c transengine.c
+COMMON_LIBS = libjackserver.la $(CAP_LIBS) @OS_LDFLAGS@
+
+jackd_SOURCES = jackd.c $(COMMON_SOURCES)
+jackd_LDADD = $(COMMON_LIBS)
 
 noinst_HEADERS = jack_md5.h md5.h md5_loc.h \
 		 clientengine.h transengine.h
@@ -42,7 +50,7 @@
 
 lib_LTLIBRARIES	= libjackserver.la
 
-libjackserver_la_CFLAGS = $(AM_CFLAGS)
+libjackserver_la_CFLAGS = $(AM_CFLAGS) -DLIBJACKSERVER
 
 libjackserver_la_SOURCES = engine.c clientengine.c transengine.c controlapi.c \
 	../libjack/systemtest.c ../libjack/sanitycheck.c \
@@ -60,6 +68,43 @@
 man_MANS = jackd.1 jackstart.1
 EXTRA_DIST = $(man_MANS)
 
+if HAVE_DBUS
+noinst_HEADERS += jackdbus.h jackctl.h jackcontroller.h jackcontroller_xml.h jackcontroller_internal.h
+jackdbus_SOURCES = jackdbus.c jackctl.c $(COMMON_SOURCES) jackcontroller.c
+jackdbus_SOURCES += jackcontroller_iface_introspectable.c
+jackdbus_SOURCES += jackcontroller_iface_control.c
+jackdbus_SOURCES += jackcontroller_iface_configure.c
+jackdbus_SOURCES += jackcontroller_iface_patchbay.c
+jackdbus_SOURCES += jackcontroller_iface_transport.c
+jackdbus_LDADD = $(COMMON_LIBS) $(DBUS_LIBS)
+
+if SETTINGS_PERSISTENCE_USE_LIBXML2
+jackdbus_SOURCES += jackcontroller_xml_libxml.c jackcontroller_xml.c
+jackdbus_LDADD += $(LIBXML2_LIBS)
+endif
+
+if SETTINGS_PERSISTENCE_USE_EXPAT
+jackdbus_SOURCES += jackcontroller_xml_expat.c jackcontroller_xml.c jackcontroller_xml_write_raw.c
+jackdbus_LDADD += -lexpat
+endif
+
+if SETTINGS_PERSISTENCE_DISABLED
+jackdbus_SOURCES += jackcontroller_xml_nop.c
+endif
+
+# Dbus service file
+servicedir = $(DBUS_SERVICES_DIR)
+service_in_files = org.jackaudio.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+# Rule to make the service file with bindir expanded
+$(service_DATA): $(service_in_files) Makefile
+	@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
+
+EXTRA_DIST += $(service_in_files)
+MOSTLYCLEANFILES += $(service_DATA)
+endif
+
 dist-hook:
 	rm -f $(distdir)/jack_md5.h
 distclean-local:
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/engine.c jack1/jackd/engine.c
--- jack1.old/jackd/engine.c	2013-10-06 16:46:26.000000000 +0100
+++ jack1/jackd/engine.c	2013-10-06 17:44:19.764394734 +0100
@@ -91,10 +91,10 @@
 						    const char *name);
 static int  jack_rechain_graph (jack_engine_t *engine);
 static void jack_clear_fifos (jack_engine_t *engine);
-static int  jack_port_do_connect (jack_engine_t *engine,
+int  jack_port_do_connect (jack_engine_t *engine,
 				  const char *source_port,
 				  const char *destination_port);
-static int  jack_port_do_disconnect (jack_engine_t *engine,
+int  jack_port_do_disconnect (jack_engine_t *engine,
 				     const char *source_port,
 				     const char *destination_port);
 static int  jack_port_do_disconnect_all (jack_engine_t *engine,
@@ -1812,6 +1812,10 @@
 	engine->midi_out_cnt = 0;
 	engine->midi_in_cnt = 0;
 
+	engine->jackctl_port_registration_notify = NULL;
+	engine->jackctl_connection_notify = NULL;
+	engine->jackctl_context = NULL;
+
 	jack_engine_reset_rolling_usecs (engine);
 	engine->max_usecs = 0.0f;
 
@@ -2904,6 +2908,11 @@
 			jack_deliver_event (engine, client, &event);
 		} 
 	}
+
+	if (engine->jackctl_connection_notify != NULL)
+	{
+		engine->jackctl_connection_notify(engine->jackctl_context, a, b, connected);
+	}
 }
 
 int
@@ -3774,7 +3783,7 @@
 	jack_info("engine.c: <-- dump ends -->");
 }
 
-static int 
+int 
 jack_port_do_connect (jack_engine_t *engine,
 		       const char *source_port,
 		       const char *destination_port)
@@ -4104,7 +4113,7 @@
 	return 0;
 }
 
-static int 
+int 
 jack_port_do_disconnect (jack_engine_t *engine,
 			 const char *source_port,
 			 const char *destination_port)
@@ -4640,6 +4649,11 @@
 			}
 		}
 	}
+
+	if (engine->jackctl_port_registration_notify != NULL)
+	{
+		engine->jackctl_port_registration_notify(engine->jackctl_context, port_id, yn);
+	}
 }
 
 void
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller.c jack1/jackd/jackcontroller.c
--- jack1.old/jackd/jackcontroller.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller.c	2013-10-06 17:44:27.115302835 +0100
@@ -0,0 +1,267 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008,2010 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <string.h>
+#include <dbus/dbus.h>
+
+#include <include/internal.h>
+
+#include "jackcontroller.h"
+#include "jackcontroller_internal.h"
+#include "jackcontroller_xml.h"
+
+struct jack_dbus_interface_descriptor * g_jackcontroller_interfaces[] =
+{
+	&g_jack_controller_iface_introspectable,
+	&g_jack_controller_iface_control,
+	&g_jack_controller_iface_configure,
+	&g_jack_controller_iface_patchbay,
+	&g_jack_controller_iface_transport,
+	NULL
+};
+
+jackctl_driver
+jack_controller_find_driver(
+	jackctl_server server,
+	const char * driver_name)
+{
+	const JSList * node_ptr;
+
+	node_ptr = jackctl_server_get_drivers_list(server);
+
+	while (node_ptr)
+	{
+		if (strcmp(jackctl_driver_get_name((jackctl_driver)node_ptr->data), driver_name) == 0)
+		{
+			return (jackctl_driver)node_ptr->data;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+	}
+
+	return NULL;
+}
+
+jackctl_parameter
+jack_controller_find_parameter(
+	const JSList * parameters_list,
+	const char * parameter_name)
+{
+	while (parameters_list)
+	{
+		if (strcmp(jackctl_parameter_get_name((jackctl_parameter)parameters_list->data), parameter_name) == 0)
+		{
+			return (jackctl_parameter)parameters_list->data;
+		}
+
+		parameters_list = jack_slist_next(parameters_list);
+	}
+
+	return NULL;
+}
+
+bool
+jack_controller_select_driver(
+	struct jack_controller * controller_ptr,
+	const char * driver_name)
+{
+	jackctl_driver driver;
+
+	driver = jack_controller_find_driver(controller_ptr->server, driver_name);
+	if (driver == NULL)
+	{
+		return false;
+	}
+
+	jack_info("driver \"%s\" selected", driver_name);
+
+	controller_ptr->driver = driver;
+	controller_ptr->driver_set = true;
+
+	return true;
+}
+
+bool
+jack_controller_start_server(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr)
+{
+	jack_info("Starting jack server...");
+
+	if (controller_ptr->driver == NULL)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Select driver first!");
+		return FALSE;
+	}
+
+	if (!jackctl_server_start(
+		    controller_ptr->server,
+		    controller_ptr->driver,
+		    controller_ptr,
+		    jack_controller_patchbay_client_appeared_callback,
+		    jack_controller_patchbay_client_disappeared_callback,
+		    jack_controller_patchbay_port_appeared_callback,
+		    jack_controller_patchbay_port_disappeared_callback,
+		    jack_controller_patchbay_ports_connected_callback,
+		    jack_controller_patchbay_ports_disconnected_callback))
+	{
+		return FALSE;
+	}
+
+	controller_ptr->started = true;
+
+	return TRUE;
+}
+
+bool
+jack_controller_stop_server(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr)
+{
+	jack_info("Stopping jack server...");
+
+	if (!jackctl_server_stop(controller_ptr->server))
+	{
+		return FALSE;
+	}
+
+	controller_ptr->started = false;
+
+	return TRUE;
+}
+
+void *
+jack_controller_create(
+        DBusConnection *connection)
+{
+	struct jack_controller *controller_ptr;
+	const JSList * node_ptr;
+	const char ** driver_name_target;
+	JSList * drivers;
+	DBusObjectPathVTable vtable =
+	{
+		jack_dbus_message_handler_unregister,
+		jack_dbus_message_handler,
+		NULL
+	};
+
+	controller_ptr = malloc(sizeof(struct jack_controller));
+	if (!controller_ptr)
+	{
+		jack_error("Ran out of memory trying to allocate struct jack_controller");
+		goto fail;
+	}
+
+	if (!jack_controller_patchbay_init(controller_ptr))
+	{
+		jack_error("Failed to initialize patchbay district");
+		goto fail_free;
+	}
+
+	controller_ptr->server = jackctl_server_create(NULL);
+	if (controller_ptr->server == NULL)
+	{
+		jack_error("Failed to create server object");
+		goto fail_uninit_patchbay;
+	}
+
+	controller_ptr->started = false;
+	controller_ptr->driver = NULL;
+	controller_ptr->driver_set = true;
+
+	drivers = (JSList *)jackctl_server_get_drivers_list(controller_ptr->server);
+	controller_ptr->drivers_count = jack_slist_length(drivers);
+	controller_ptr->driver_names = malloc(controller_ptr->drivers_count * sizeof(const char *));
+	if (controller_ptr->driver_names == NULL)
+	{
+		jack_error("Ran out of memory trying to allocate driver names array");
+		goto fail_destroy_server;
+	}
+
+	driver_name_target = controller_ptr->driver_names;
+	node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
+	while (node_ptr != NULL)
+	{
+		*driver_name_target = jackctl_driver_get_name((jackctl_driver)node_ptr->data);
+
+		/* select default driver */
+		if (controller_ptr->driver == NULL && strcmp(*driver_name_target, JACK_DEFAULT_DRIVER) == 0)
+		{
+			controller_ptr->driver = (jackctl_driver_t *)node_ptr->data;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+		driver_name_target++;
+	}
+
+	controller_ptr->dbus_descriptor.context = controller_ptr;
+	controller_ptr->dbus_descriptor.interfaces = g_jackcontroller_interfaces;
+
+	if (!dbus_connection_register_object_path(
+		    connection,
+		    JACK_CONTROLLER_OBJECT_PATH,
+		    &vtable,
+		    &controller_ptr->dbus_descriptor))
+	{
+		jack_error("Ran out of memory trying to register D-Bus object path");
+		goto fail_free_driver_names_array;
+	}
+
+	jack_controller_settings_load(controller_ptr);
+
+	return controller_ptr;
+
+fail_free_driver_names_array:
+	free(controller_ptr->driver_names);
+
+fail_destroy_server:
+	jackctl_server_destroy(controller_ptr->server);
+
+fail_uninit_patchbay:
+	jack_controller_patchbay_uninit(controller_ptr);
+
+fail_free:
+	free(controller_ptr);
+
+fail:
+	return NULL;
+}
+
+#define controller_ptr ((struct jack_controller *)context)
+
+void
+jack_controller_destroy(
+        void * context)
+{
+	if (controller_ptr->started)
+	{
+		jack_controller_stop_server(controller_ptr, NULL);
+	}
+
+	free(controller_ptr->driver_names);
+
+	jackctl_server_destroy(controller_ptr->server);
+
+	jack_controller_patchbay_uninit(controller_ptr);
+
+	free(controller_ptr);
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller.h jack1/jackd/jackcontroller.h
--- jack1.old/jackd/jackcontroller.h	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller.h	2013-10-06 17:44:19.766394709 +0100
@@ -0,0 +1,31 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef JACKCONTROLLER_H__2CC80B1E_8D5D_45E3_A9D8_9086DDF68BB5__INCLUDED
+#define JACKCONTROLLER_H__2CC80B1E_8D5D_45E3_A9D8_9086DDF68BB5__INCLUDED
+
+void *
+jack_controller_create(
+        DBusConnection *connection);
+
+void
+jack_controller_destroy(
+        void *controller_ptr);
+
+#endif /* #ifndef JACKCONTROLLER_H__2CC80B1E_8D5D_45E3_A9D8_9086DDF68BB5__INCLUDED */
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_iface_configure.c jack1/jackd/jackcontroller_iface_configure.c
--- jack1.old/jackd/jackcontroller_iface_configure.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_iface_configure.c	2013-10-06 17:44:27.116302822 +0100
@@ -0,0 +1,2258 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <dbus/dbus.h>
+
+#include <include/internal.h>
+
+#include "jackdbus.h"
+#include "jackcontroller_internal.h"
+#include "jackcontroller_xml.h"
+
+#define PTNODE_ENGINE    "engine"
+#define PTNODE_DRIVER    "driver"
+#define PTNODE_DRIVERS   "drivers"
+#define PTNODE_INTERNALS "internals"
+
+#define ENGINE_DRIVER_PARAMETER_NAME         "driver"
+#define ENGINE_DRIVER_PARAMETER_TYPE         JackParamString
+#define ENGINE_DRIVER_PARAMETER_SHORT_DESCR  "Driver to use"
+#define ENGINE_DRIVER_PARAMETER_LONG_DESCR   ""
+
+struct parameter_info
+{
+    unsigned char type;
+    const char * name;
+    const char * short_decr;
+    const char * long_descr;
+};
+
+unsigned char jack_controller_dbus_types[JACK_PARAM_MAX] =
+{
+	[JackParamInt] = DBUS_TYPE_INT32,
+	[JackParamUInt] = DBUS_TYPE_UINT32,
+	[JackParamChar] = DBUS_TYPE_BYTE,
+	[JackParamString] = DBUS_TYPE_STRING,
+	[JackParamBool] = DBUS_TYPE_BOOLEAN,
+};
+
+const char * jack_controller_dbus_type_signatures[JACK_PARAM_MAX] =
+{
+	[JackParamInt] = DBUS_TYPE_INT32_AS_STRING,
+	[JackParamUInt] = DBUS_TYPE_UINT32_AS_STRING,
+	[JackParamChar] = DBUS_TYPE_BYTE_AS_STRING,
+	[JackParamString] = DBUS_TYPE_STRING_AS_STRING,
+	[JackParamBool] = DBUS_TYPE_BOOLEAN_AS_STRING,
+};
+
+#define PARAM_TYPE_JACK_TO_DBUS(_) jack_controller_dbus_types[_]
+#define PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(_) jack_controller_dbus_type_signatures[_]
+
+static
+bool
+jack_controller_jack_to_dbus_variant(
+	jackctl_param_type_t type,
+	const union jackctl_parameter_value * value_ptr,
+	message_arg_t  * dbusv_ptr)
+{
+	switch (type)
+	{
+	case JackParamInt:
+		dbusv_ptr->int32 = (dbus_int32_t)value_ptr->i;
+		return true;
+	case JackParamUInt:
+		dbusv_ptr->uint32 = (dbus_uint32_t)value_ptr->ui;
+		return true;
+	case JackParamChar:
+		dbusv_ptr->byte = value_ptr->c;
+		return true;
+	case JackParamString:
+		dbusv_ptr->string = value_ptr->str;
+		return true;
+	case JackParamBool:
+		dbusv_ptr->boolean = (dbus_bool_t)value_ptr->b;
+		return true;
+	}
+
+	jack_error("Unknown JACK parameter type %i", (int)type);
+	assert(0);
+	return false;
+}
+
+static
+bool
+jack_controller_dbus_to_jack_variant(
+	int type,
+	const message_arg_t * dbusv_ptr,
+	union jackctl_parameter_value * value_ptr)
+{
+	size_t len;
+
+	switch (type)
+	{
+	case DBUS_TYPE_INT32:
+		value_ptr->i = dbusv_ptr->int32;
+		return true;
+	case DBUS_TYPE_UINT32:
+		value_ptr->ui = dbusv_ptr->uint32;
+		return true;
+	case DBUS_TYPE_BYTE:
+		value_ptr->c = dbusv_ptr->byte;
+		return true;
+	case DBUS_TYPE_STRING:
+		len = strlen(dbusv_ptr->string);
+		if (len > JACK_PARAM_STRING_MAX)
+		{
+			jack_error("Parameter string value is too long (%u)", (unsigned int)len);
+			return false;
+		}
+		memcpy(value_ptr->str, dbusv_ptr->string, len + 1);
+
+		return true;
+	case DBUS_TYPE_BOOLEAN:
+		value_ptr->b = dbusv_ptr->boolean;
+		return true;
+	}
+
+	jack_error("Unknown D-Bus parameter type %i", (int)type);
+	return false;
+}
+
+/*
+ * Construct a return message for a Get[Driver|Engine]ParameterValue method call.
+ *
+ * The operation can only fail due to lack of memory, in which case
+ * there's no sense in trying to construct an error return. Instead,
+ * call->reply will be set to NULL and handled in send_method_return().
+ */
+static void
+jack_dbus_construct_method_return_parameter(
+	struct jack_dbus_method_call * call,
+	dbus_bool_t is_set,
+	int type,
+	const char * signature,
+	message_arg_t default_value,
+	message_arg_t value)
+{
+	DBusMessageIter iter;
+
+	/* Create a new method return message. */
+	call->reply = dbus_message_new_method_return (call->message);
+	if (!call->reply)
+	{
+		goto fail;
+	}
+
+	dbus_message_iter_init_append (call->reply, &iter);
+
+	/* Append the is_set argument. */
+	if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, (const void *) &is_set))
+	{
+		goto fail_unref;
+	}
+
+	/* Append the 'default' and 'value' arguments. */
+	if (!jack_dbus_message_append_variant(&iter, type, signature, &default_value))
+	{
+		goto fail_unref;
+	}
+	if (!jack_dbus_message_append_variant(&iter, type, signature, &value))
+	{
+		goto fail_unref;
+	}
+
+	return;
+
+fail_unref:
+	dbus_message_unref (call->reply);
+	call->reply = NULL;
+
+fail:
+	jack_error ("Ran out of memory trying to construct method return");
+}
+
+static
+bool
+jack_controller_dbus_get_parameter_address_ex(
+    struct jack_dbus_method_call * call,
+    DBusMessageIter * iter_ptr,
+    const char ** address_array)
+{
+    const char * signature;
+    DBusMessageIter array_iter;
+    int type;
+    int index;
+
+    if (!dbus_message_iter_init(call->message, iter_ptr))
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Invalid arguments to method '%s'. No input arguments found.",
+            call->method_name);
+        return false;
+    }
+
+    signature = dbus_message_iter_get_signature(iter_ptr);
+    if (signature == NULL)
+    {
+        jack_error("dbus_message_iter_get_signature() failed");
+        return false;
+    }
+
+    if (strcmp(signature, "as") != 0)
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Invalid arguments to method '%s'. Input arguments signature '%s', must begin with 'as'.",
+            call->method_name,
+            signature);
+        return false;
+    }
+
+    dbus_message_iter_recurse(iter_ptr, &array_iter);
+
+    index = 0;
+    while ((type = dbus_message_iter_get_arg_type(&array_iter)) != DBUS_TYPE_INVALID)
+    {
+        if (index == 3)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_INVALID_ARGS,
+                "Invalid arguments to method '%s'. Parameter address array must contain not more than three elements.",
+                call->method_name);
+            return false;
+        }
+
+        ;
+        if (type != DBUS_TYPE_STRING)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_FATAL,
+                "Internal error when parsing parameter address of method '%s'. Address array element type '%c' is not string type.",
+                call->method_name,
+                type);
+            return false;
+        }
+
+        dbus_message_iter_get_basic(&array_iter, address_array + index);
+        //jack_info("address component: '%s'", address_array[index]);
+
+        dbus_message_iter_next(&array_iter);
+        index++;
+    }
+
+    while (index < 3)
+    {
+        address_array[index] = NULL;
+        index++;
+    }
+
+    return true;
+}
+
+static
+bool
+jack_controller_dbus_get_parameter_address(
+    struct jack_dbus_method_call * call,
+    const char ** address_array)
+{
+    DBusMessageIter iter;
+    bool ret;
+
+    ret = jack_controller_dbus_get_parameter_address_ex(call, &iter, address_array);
+    if (ret && dbus_message_iter_has_next(&iter))
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Invalid arguments to method '%s'. Input arguments signature must be 'as'.",
+            call->method_name);
+        return false;
+    }
+
+    return ret;
+}
+
+#define controller_ptr ((struct jack_controller *)call->context)
+
+static
+bool
+jack_controller_fill_parameter_names(
+    struct jack_dbus_method_call * call,
+    DBusMessageIter * iter_ptr,
+    const char * special_first,
+    const JSList * parameters_list)
+{
+    DBusMessageIter array_iter;
+    const char * param_name;
+
+    if (!dbus_message_iter_open_container(iter_ptr, DBUS_TYPE_ARRAY, "s", &array_iter))
+    {
+        return false;
+    }
+
+    if (special_first != NULL)
+    {
+        if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &special_first))
+        {
+            dbus_message_iter_close_container(iter_ptr, &array_iter);
+            return false;
+        }
+    }
+
+    /* Append parameter descriptions to the array. */
+    while (parameters_list != NULL)
+    {
+        param_name = jackctl_parameter_get_name(parameters_list->data);
+        if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &param_name))
+        {
+            dbus_message_iter_close_container(iter_ptr, &array_iter);
+            return false;
+        }
+
+        parameters_list = jack_slist_next(parameters_list);
+    }
+
+    return dbus_message_iter_close_container(iter_ptr, &array_iter);
+}
+
+static
+void
+jack_controller_dbus_read_container(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    dbus_bool_t leaf;
+    DBusMessageIter iter;
+    DBusMessageIter array_iter;
+    const char * child_name;
+    unsigned int index;
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+
+    //jack_info("jack_controller_dbus_read_container() called");
+
+    if (!jack_controller_dbus_get_parameter_address(call, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    /* Create a new method return message. */
+    call->reply = dbus_message_new_method_return(call->message);
+    if (!call->reply)
+    {
+        goto oom;
+    }
+
+    dbus_message_iter_init_append(call->reply, &iter);
+
+    if (address[0] == NULL)     /* root node */
+    {
+        //jack_info("reading root container");
+
+        leaf = false;
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &leaf))
+        {
+            goto oom_unref;
+        }
+
+        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &array_iter))
+        {
+            goto oom_unref;
+        }
+
+        child_name = PTNODE_ENGINE;
+        if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &child_name))
+        {
+            goto oom_close_unref;
+        }
+
+        child_name = PTNODE_DRIVER;
+        if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &child_name))
+        {
+            goto oom_close_unref;
+        }
+
+        child_name = PTNODE_DRIVERS;
+        if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &child_name))
+        {
+            goto oom_close_unref;
+        }
+
+        child_name = PTNODE_INTERNALS;
+        if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &child_name))
+        {
+            goto oom_close_unref;
+        }
+
+        dbus_message_iter_close_container(&iter, &array_iter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        //jack_info("reading engine params container");
+
+        leaf = true;
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &leaf))
+        {
+            goto oom_unref;
+        }
+
+        if (!jack_controller_fill_parameter_names(
+                call,
+                &iter,
+                ENGINE_DRIVER_PARAMETER_NAME,
+                jackctl_server_get_parameters(controller_ptr->server)))
+        {
+            goto oom_unref;
+        }
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        //jack_info("reading current driver params container");
+
+        leaf = true;
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &leaf))
+        {
+            goto oom_unref;
+        }
+
+        if (!jack_controller_fill_parameter_names(
+                call,
+                &iter,
+                NULL,
+                jackctl_driver_get_parameters(controller_ptr->driver)))
+        {
+            goto oom_unref;
+        }
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        leaf = address[1] != NULL;
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &leaf))
+        {
+            goto oom_unref;
+        }
+
+        if (!leaf)              /* available drivers requested */
+        {
+            //jack_info("reading drivers container");
+
+            if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &array_iter))
+            {
+                goto oom_unref;
+            }
+
+            for (index = 0; index < controller_ptr->drivers_count; index++)
+            {
+                if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, controller_ptr->driver_names + index))
+                {
+                    goto oom_close_unref;
+                }
+            }
+
+            dbus_message_iter_close_container(&iter, &array_iter);
+        }
+        else                    /* specified driver parameters requested */
+        {
+            //jack_info("reading driver '%s' params container", address[1]);
+
+            driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+            if (driver == NULL)
+            {
+                jack_dbus_error(
+                    call,
+                    JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                    "Unknown driver '%s'",
+                    address[1]);
+                return;
+            }
+
+            if (!jack_controller_fill_parameter_names(
+                    call,
+                    &iter,
+                    NULL,
+                    jackctl_driver_get_parameters(driver)))
+            {
+                goto oom_unref;
+            }
+        }
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+        leaf = address[1] != NULL;
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &leaf))
+        {
+            goto oom_unref;
+        }
+
+        if (!leaf)              /* available internals requested */
+        {
+            //jack_info("reading internals container");
+
+            if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &array_iter))
+            {
+                goto oom_unref;
+            }
+
+#if 0
+            for (index = 0; index < controller_ptr->internals_count; index++)
+            {
+                if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, controller_ptr->internal_names + index))
+                {
+                    goto oom_close_unref;
+                }
+            }
+#endif
+
+            dbus_message_iter_close_container(&iter, &array_iter);
+        }
+        else                    /* specified driver parameters requested */
+        {
+            //jack_info("reading internal '%s' params container", address[1]);
+
+#if 0
+            internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+            if (internal == NULL)
+            {
+#endif
+                jack_dbus_error(
+                    call,
+                    JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                    "Unknown internal '%s'",
+                    address[1]);
+                return;
+#if 0
+            }
+
+            if (!jack_controller_fill_parameter_names(
+                    call,
+                    &iter,
+                    NULL,
+                    jackctl_internal_get_parameters(internal)))
+            {
+                goto oom_unref;
+            }
+#endif
+        }
+
+        return;
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+
+    return;
+
+oom_close_unref:
+    dbus_message_iter_close_container(&iter, &array_iter);
+
+oom_unref:
+    dbus_message_unref(call->reply);
+    call->reply = NULL;
+
+oom:
+    jack_error ("Ran out of memory trying to construct method return");
+}
+
+static
+void
+jack_controller_get_parameters_info(
+    struct jack_dbus_method_call * call,
+    struct parameter_info * special_parameter_info_ptr,
+    const JSList * parameters_list)
+{
+    DBusMessageIter iter, array_iter, struct_iter;
+    unsigned char type;
+    const char *str;
+
+    call->reply = dbus_message_new_method_return (call->message);
+    if (!call->reply)
+    {
+        goto fail;
+    }
+
+    dbus_message_iter_init_append (call->reply, &iter);
+
+    /* Open the array. */
+    if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ysss)", &array_iter))
+    {
+        goto fail_unref;
+    }
+
+    if (special_parameter_info_ptr != NULL)
+    {
+        /* Open the struct. */
+        if (!dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        /* Append parameter type. */
+        type = PARAM_TYPE_JACK_TO_DBUS(special_parameter_info_ptr->type);
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BYTE, &type))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Append parameter name. */
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &special_parameter_info_ptr->name))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Append parameter short description. */
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &special_parameter_info_ptr->short_decr))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Append parameter long description. */
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &special_parameter_info_ptr->long_descr))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Close the struct. */
+        if (!dbus_message_iter_close_container (&array_iter, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+    }
+
+    /* Append parameter descriptions to the array. */
+    while (parameters_list != NULL)
+    {
+        /* Open the struct. */
+        if (!dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        /* Append parameter type. */
+        type = PARAM_TYPE_JACK_TO_DBUS(jackctl_parameter_get_type(parameters_list->data));
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BYTE, &type))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Append parameter name. */
+        str = jackctl_parameter_get_name(parameters_list->data);
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &str))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Append parameter short description. */
+        str = jackctl_parameter_get_short_description(parameters_list->data);
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &str))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Append parameter long description. */
+        str = jackctl_parameter_get_long_description(parameters_list->data);
+        if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &str))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Close the struct. */
+        if (!dbus_message_iter_close_container (&array_iter, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        parameters_list = jack_slist_next(parameters_list);
+    }
+
+    /* Close the array. */
+    if (!dbus_message_iter_close_container (&iter, &array_iter))
+    {
+        goto fail_unref;
+    }
+
+    return;
+
+fail_close2_unref:
+    dbus_message_iter_close_container (&iter, &struct_iter);
+
+fail_close_unref:
+    dbus_message_iter_close_container (&iter, &array_iter);
+
+fail_unref:
+    dbus_message_unref (call->reply);
+    call->reply = NULL;
+
+fail:
+    jack_error ("Ran out of memory trying to construct method return");
+}
+
+static
+void
+jack_controller_dbus_get_parameters_info(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+    struct parameter_info driver_parameter_info;
+
+    //jack_info("jack_controller_dbus_get_parameters_info() called");
+
+    if (!jack_controller_dbus_get_parameter_address(call, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    if (address[0] != NULL &&
+        address[1] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        driver_parameter_info.type = ENGINE_DRIVER_PARAMETER_TYPE;
+        driver_parameter_info.name = ENGINE_DRIVER_PARAMETER_NAME;
+        driver_parameter_info.short_decr = ENGINE_DRIVER_PARAMETER_SHORT_DESCR;
+        driver_parameter_info.long_descr = ENGINE_DRIVER_PARAMETER_LONG_DESCR;
+
+        jack_controller_get_parameters_info(
+            call,
+            &driver_parameter_info,
+            jackctl_server_get_parameters(controller_ptr->server));
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        jack_controller_get_parameters_info(
+            call,
+            NULL,
+            jackctl_driver_get_parameters(controller_ptr->driver));
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+        if (driver == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown driver '%s'",
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameters_info(
+            call,
+            NULL,
+            jackctl_driver_get_parameters(driver));
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+#if 0
+        internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+        if (internal == NULL)
+        {
+#endif
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown internal '%s'",
+                address[1]);
+            return;
+#if 0
+        }
+
+        jack_controller_get_parameters_info(
+            call,
+            NULL,
+            jackctl_internal_get_parameters(internal));
+
+        return;
+#endif
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+}
+
+static
+void
+jack_controller_get_parameter_info_ex(
+    struct jack_dbus_method_call * call,
+    struct parameter_info * info_ptr)
+{
+    DBusMessageIter iter, struct_iter;
+    unsigned char type;
+
+    call->reply = dbus_message_new_method_return(call->message);
+    if (!call->reply)
+    {
+        goto fail;
+    }
+
+    dbus_message_iter_init_append(call->reply, &iter);
+
+    /* Open the struct. */
+    if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+    {
+        goto fail_unref;
+    }
+
+    /* Append parameter type. */
+    type = PARAM_TYPE_JACK_TO_DBUS(info_ptr->type);
+    if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BYTE, &type))
+    {
+        goto fail_close_unref;
+    }
+
+    /* Append parameter name. */
+    if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->name))
+    {
+        goto fail_close_unref;
+    }
+
+    /* Append parameter short description. */
+    if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->short_decr))
+    {
+        goto fail_close_unref;
+    }
+
+    /* Append parameter long description. */
+    if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->long_descr))
+    {
+        goto fail_close_unref;
+    }
+
+    /* Close the struct. */
+    if (!dbus_message_iter_close_container(&iter, &struct_iter))
+    {
+        goto fail_unref;
+    }
+
+    return;
+
+fail_close_unref:
+    dbus_message_iter_close_container(&iter, &struct_iter);
+
+fail_unref:
+    dbus_message_unref(call->reply);
+    call->reply = NULL;
+
+fail:
+    jack_error("Ran out of memory trying to construct method return");
+}
+
+static
+void
+jack_controller_get_parameter_info(
+    struct jack_dbus_method_call * call,
+    jackctl_parameter_t * parameter)
+{
+    struct parameter_info info;
+
+    info.type = jackctl_parameter_get_type(parameter);
+    info.name = jackctl_parameter_get_name(parameter);
+    info.short_decr = jackctl_parameter_get_short_description(parameter);
+    info.long_descr = jackctl_parameter_get_long_description(parameter);
+
+    jack_controller_get_parameter_info_ex(call, &info);
+}
+
+static
+void
+jack_controller_dbus_get_parameter_info(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+    jackctl_parameter_t * parameter;
+    struct parameter_info driver_parameter_info;
+
+    //jack_info("jack_controller_dbus_get_parameter_info() called");
+
+    if (!jack_controller_dbus_get_parameter_address(call, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        if (strcmp(address[1], ENGINE_DRIVER_PARAMETER_NAME) == 0)
+        {
+            driver_parameter_info.type = ENGINE_DRIVER_PARAMETER_TYPE;
+            driver_parameter_info.name = ENGINE_DRIVER_PARAMETER_NAME;
+            driver_parameter_info.short_decr = ENGINE_DRIVER_PARAMETER_SHORT_DESCR;
+            driver_parameter_info.long_descr = ENGINE_DRIVER_PARAMETER_LONG_DESCR;
+
+            jack_controller_get_parameter_info_ex(call, &driver_parameter_info);
+
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown engine parameter '%s'",
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_info(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(controller_ptr->driver), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[1],
+                jackctl_driver_get_name(controller_ptr->driver));
+            return;
+        }
+
+        jack_controller_get_parameter_info(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+        if (driver == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown driver '%s'",
+                address[1]);
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_info(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+#if 0
+        internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+        if (internal == NULL)
+        {
+#endif
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown internal '%s'",
+                address[1]);
+            return;
+#if 0
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for internal '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_info(call, parameter);
+
+        return;
+#endif
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+}
+
+static
+void
+jack_controller_get_parameter_constraint(
+    struct jack_dbus_method_call * call,
+    jackctl_parameter_t * parameter)
+{
+    uint32_t index;
+    uint32_t count;
+	union jackctl_parameter_value min;
+	union jackctl_parameter_value max;
+    union jackctl_parameter_value jackctl_value;
+    DBusMessageIter iter, array_iter, struct_iter;
+    const char * descr;
+    jackctl_param_type_t type;
+    message_arg_t value;
+    bool is_range;
+
+    type = jackctl_parameter_get_type(parameter);
+
+    call->reply = dbus_message_new_method_return(call->message);
+    if (!call->reply)
+    {
+        goto fail;
+    }
+
+    dbus_message_iter_init_append(call->reply, &iter);
+
+    is_range = jackctl_parameter_has_range_constraint(parameter);
+    value.boolean = is_range;
+    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value))
+    {
+        goto fail_unref;
+    }
+
+    value.boolean = jackctl_parameter_constraint_is_strict(parameter);
+    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value))
+    {
+        goto fail_unref;
+    }
+
+    value.boolean = jackctl_parameter_constraint_is_fake_value(parameter);
+    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value))
+    {
+        goto fail_unref;
+    }
+
+    /* Open the array. */
+    if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(vs)", &array_iter))
+    {
+        goto fail_unref;
+    }
+
+    if (is_range)
+    {
+        jackctl_parameter_get_range_constraint(parameter, &min, &max);
+
+        /* Open the struct. */
+        if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        jack_controller_jack_to_dbus_variant(type, &min, &value);
+
+        if (!jack_dbus_message_append_variant(&struct_iter, PARAM_TYPE_JACK_TO_DBUS(type), PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(type), &value))
+        {
+            goto fail_close2_unref;
+        }
+
+        descr = "min";
+
+        if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &descr))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Close the struct. */
+        if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        /* Open the struct. */
+        if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        jack_controller_jack_to_dbus_variant(type, &max, &value);
+ 
+        if (!jack_dbus_message_append_variant(&struct_iter, PARAM_TYPE_JACK_TO_DBUS(type), PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(type), &value))
+        {
+            goto fail_close2_unref;
+        }
+
+        descr = "max";
+
+        if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &descr))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Close the struct. */
+        if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+    }
+    else
+    {
+        count = jackctl_parameter_get_enum_constraints_count(parameter);
+
+        /* Append enum values to the array. */
+        for (index = 0 ; index < count ; index++)
+        {
+            jackctl_value = jackctl_parameter_get_enum_constraint_value(parameter, index);
+            descr = jackctl_parameter_get_enum_constraint_description(parameter, index);
+
+            jack_controller_jack_to_dbus_variant(type, &jackctl_value, &value);
+
+            /* Open the struct. */
+            if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+            {
+                goto fail_close_unref;
+            }
+
+            if (!jack_dbus_message_append_variant(&struct_iter, PARAM_TYPE_JACK_TO_DBUS(type), PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(type), &value))
+            {
+                goto fail_close2_unref;
+            }
+
+            if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &descr))
+            {
+                goto fail_close2_unref;
+            }
+
+            /* Close the struct. */
+            if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
+            {
+                goto fail_close_unref;
+            }
+        }
+    }
+
+    /* Close the array. */
+    if (!dbus_message_iter_close_container(&iter, &array_iter))
+    {
+        goto fail_unref;
+    }
+
+    return;
+
+fail_close2_unref:
+    dbus_message_iter_close_container(&array_iter, &struct_iter);
+
+fail_close_unref:
+    dbus_message_iter_close_container(&iter, &array_iter);
+
+fail_unref:
+    dbus_message_unref(call->reply);
+    call->reply = NULL;
+
+fail:
+    jack_error ("Ran out of memory trying to construct method return");
+}
+
+static
+void
+jack_controller_get_parameter_constraint_engine_driver(
+    struct jack_dbus_method_call * call)
+{
+    unsigned int index;
+    DBusMessageIter iter, array_iter, struct_iter;
+    jackctl_param_type_t type;
+    dbus_bool_t bval;
+    message_arg_t value;
+
+    type = ENGINE_DRIVER_PARAMETER_TYPE;
+
+    call->reply = dbus_message_new_method_return(call->message);
+    if (!call->reply)
+    {
+        goto fail;
+    }
+
+    dbus_message_iter_init_append(call->reply, &iter);
+
+    /* is_range */
+    bval = false;
+    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &bval))
+    {
+        goto fail_unref;
+    }
+
+    /* is_strict */
+    bval = true;
+    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &bval))
+    {
+        goto fail_unref;
+    }
+
+    /* is_fake_value */
+    bval = true;
+    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &bval))
+    {
+        goto fail_unref;
+    }
+
+    /* Open the array. */
+    if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(vs)", &array_iter))
+    {
+        goto fail_unref;
+    }
+
+    /* Append enum values to the array. */
+    for (index = 0 ; index < controller_ptr->drivers_count ; index++)
+    {
+        /* Open the struct. */
+        if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+
+        value.string = controller_ptr->driver_names[index];
+        if (!jack_dbus_message_append_variant(
+                &struct_iter,
+                PARAM_TYPE_JACK_TO_DBUS(type),
+                PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(type),
+                &value))
+        {
+            goto fail_close2_unref;
+        }
+
+        if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &value))
+        {
+            goto fail_close2_unref;
+        }
+
+        /* Close the struct. */
+        if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
+        {
+            goto fail_close_unref;
+        }
+    }
+
+    /* Close the array. */
+    if (!dbus_message_iter_close_container(&iter, &array_iter))
+    {
+        goto fail_unref;
+    }
+
+    return;
+
+fail_close2_unref:
+    dbus_message_iter_close_container(&array_iter, &struct_iter);
+
+fail_close_unref:
+    dbus_message_iter_close_container(&iter, &array_iter);
+
+fail_unref:
+    dbus_message_unref(call->reply);
+    call->reply = NULL;
+
+fail:
+    jack_error ("Ran out of memory trying to construct method return");
+}
+
+static
+void
+jack_controller_dbus_get_parameter_constraint(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+    jackctl_parameter_t * parameter;
+
+    //jack_info("jack_controller_dbus_get_parameter_constraint() called");
+
+    if (!jack_controller_dbus_get_parameter_address(call, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        if (strcmp(address[1], ENGINE_DRIVER_PARAMETER_NAME) == 0)
+        {
+            jack_controller_get_parameter_constraint_engine_driver(call);
+
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown engine parameter '%s'",
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_constraint(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(controller_ptr->driver), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[1],
+                jackctl_driver_get_name(controller_ptr->driver));
+            return;
+        }
+
+        jack_controller_get_parameter_constraint(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+        if (driver == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown driver '%s'",
+                address[1]);
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_constraint(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+#if 0
+        internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+        if (internal == NULL)
+        {
+#endif
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown internal '%s'",
+                address[1]);
+            return;
+#if 0
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for internal '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_constraint(call, parameter);
+
+        return;
+#endif
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+}
+
+static
+void
+jack_controller_get_parameter_value(
+    struct jack_dbus_method_call * call,
+    jackctl_parameter_t * parameter)
+{
+    int type;
+    union jackctl_parameter_value jackctl_value;
+    union jackctl_parameter_value jackctl_default_value;
+    message_arg_t value;
+    message_arg_t default_value;
+
+    type = jackctl_parameter_get_type(parameter);
+    jackctl_default_value = jackctl_parameter_get_default_value(parameter);
+    jackctl_value = jackctl_parameter_get_value(parameter);
+
+    jack_controller_jack_to_dbus_variant(type, &jackctl_value, &value);
+    jack_controller_jack_to_dbus_variant(type, &jackctl_default_value, &default_value);
+
+    /* Construct the reply. */
+    jack_dbus_construct_method_return_parameter(
+        call,
+        (dbus_bool_t)(jackctl_parameter_is_set(parameter) ? TRUE : FALSE),
+        PARAM_TYPE_JACK_TO_DBUS(type),
+        PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(type),
+        default_value,
+        value);
+}
+
+static
+void
+jack_controller_get_parameter_value_engine_driver(
+    struct jack_dbus_method_call * call)
+{
+    message_arg_t value;
+    message_arg_t default_value;
+
+    default_value.string = JACK_DEFAULT_DRIVER;
+    value.string = jackctl_driver_get_name(controller_ptr->driver);
+
+    /* Construct the reply. */
+    jack_dbus_construct_method_return_parameter(
+        call,
+        controller_ptr->driver_set,
+        DBUS_TYPE_STRING,
+        DBUS_TYPE_STRING_AS_STRING,
+        default_value,
+        value);
+}
+
+static void
+jack_controller_dbus_get_parameter_value(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+    jackctl_parameter_t * parameter;
+
+    //jack_info("jack_controller_dbus_get_parameter_value() called");
+
+    if (!jack_controller_dbus_get_parameter_address(call, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        if (strcmp(address[1], ENGINE_DRIVER_PARAMETER_NAME) == 0)
+        {
+            jack_controller_get_parameter_value_engine_driver(call);
+
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown engine parameter '%s'",
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_value(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(controller_ptr->driver), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[1],
+                jackctl_driver_get_name(controller_ptr->driver));
+            return;
+        }
+
+        jack_controller_get_parameter_value(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+        if (driver == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown driver '%s'",
+                address[1]);
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_value(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+#if 0
+        internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+        if (internal == NULL)
+        {
+#endif
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown internal '%s'",
+                address[1]);
+            return;
+#if 0
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for internal '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_get_parameter_value(call, parameter);
+
+        return;
+#endif
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+}
+
+static
+void
+jack_controller_set_parameter_value(
+    struct jack_dbus_method_call * call,
+    jackctl_parameter_t * parameter,
+    message_arg_t * arg_ptr,
+    int arg_type)
+{
+    jackctl_param_type_t type;
+    union jackctl_parameter_value value;
+
+    type = jackctl_parameter_get_type(parameter);
+
+    if (PARAM_TYPE_JACK_TO_DBUS(type) != arg_type)
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Parameter value type mismatch: was expecting '%c', got '%c'",
+            (char)PARAM_TYPE_JACK_TO_DBUS(type),
+            (char)arg_type);
+        return;
+    }
+
+    if (!jack_controller_dbus_to_jack_variant(
+            arg_type,
+            arg_ptr,
+            &value))
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Cannot convert parameter value");
+        return;
+    }
+
+    jackctl_parameter_set_value(parameter, &value);
+
+    jack_controller_settings_save_auto(controller_ptr);
+
+    jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_set_parameter_value_engine_driver(
+    struct jack_dbus_method_call * call,
+    message_arg_t * arg_ptr,
+    int arg_type)
+{
+    union jackctl_parameter_value value;
+
+    if (arg_type != DBUS_TYPE_STRING)
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Engine parameter value type mismatch: was expecting '%c', got '%c'",
+            (char)DBUS_TYPE_STRING,
+            (char)arg_type);
+        return;
+    }
+
+    if (!jack_controller_dbus_to_jack_variant(
+            arg_type,
+            arg_ptr,
+            &value))
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Cannot convert engine parameter value");
+        return;
+    }
+
+    if (!jack_controller_select_driver(controller_ptr, value.str))
+    {
+        /* Couldn't find driver with the specified name. */
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_UNKNOWN_DRIVER,
+            "Unknown driver '%s'",
+            value.str);
+        return;
+    }
+
+    jack_controller_settings_save_auto(controller_ptr);
+
+    jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_set_parameter_value(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    DBusMessageIter iter;
+    DBusMessageIter variant_iter;
+    message_arg_t arg;
+    int arg_type;
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+    jackctl_parameter_t * parameter;
+
+    //jack_info("jack_controller_dbus_set_parameter_value() called");
+
+    if (!jack_controller_dbus_get_parameter_address_ex(call, &iter, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    dbus_message_iter_next(&iter);
+
+    if (dbus_message_iter_has_next(&iter))
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Invalid arguments to method '%s'. Too many arguments.",
+            call->method_name);
+        return;
+    }
+
+    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+    {
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_INVALID_ARGS,
+            "Invalid arguments to method '%s'. Value to set must be variant.",
+            call->method_name);
+        return;
+    }
+
+    dbus_message_iter_recurse (&iter, &variant_iter);
+    dbus_message_iter_get_basic(&variant_iter, &arg);
+    arg_type = dbus_message_iter_get_arg_type(&variant_iter);
+
+    //jack_info("argument of type '%c'", arg_type);
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        if (strcmp(address[1], ENGINE_DRIVER_PARAMETER_NAME) == 0)
+        {
+            jack_controller_set_parameter_value_engine_driver(call, &arg, arg_type);
+
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown engine parameter '%s'",
+                address[1]);
+            return;
+        }
+
+        jack_controller_set_parameter_value(call, parameter, &arg, arg_type);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(controller_ptr->driver), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[1],
+                jackctl_driver_get_name(controller_ptr->driver));
+            return;
+        }
+
+        jack_controller_set_parameter_value(call, parameter, &arg, arg_type);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+        if (driver == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown driver '%s'",
+                address[1]);
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_set_parameter_value(call, parameter, &arg, arg_type);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+#if 0
+        internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+        if (internal == NULL)
+        {
+#endif
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown internal '%s'",
+                address[1]);
+            return;
+#if 0
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for internal '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_set_parameter_value(call, parameter, &arg, arg_type);
+        return;
+#endif
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+}
+
+static
+void
+jack_controller_reset_parameter_value(
+    struct jack_dbus_method_call * call,
+    jackctl_parameter_t * parameter)
+{
+    jackctl_parameter_reset(parameter);
+
+    jack_controller_settings_save_auto(controller_ptr);
+
+    jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_reset_parameter_value_engine_driver(
+    struct jack_dbus_method_call * call)
+{
+    if (!jack_controller_select_driver(controller_ptr, JACK_DEFAULT_DRIVER))
+    {
+        /* Couldn't find driver with the specified name. */
+        jack_dbus_error(
+            call,
+            JACK_DBUS_ERROR_UNKNOWN_DRIVER,
+            "Default driver '%s' is unknown",
+	    JACK_DEFAULT_DRIVER);
+        return;
+    }
+
+    controller_ptr->driver_set = false;
+
+    jack_controller_settings_save_auto(controller_ptr);
+
+    jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_reset_parameter_value(
+    struct jack_dbus_method_call * call)
+{
+    const char * address[3];
+    //jackctl_internal_t * internal;
+    jackctl_driver_t * driver;
+    jackctl_parameter_t * parameter;
+
+    //jack_info("jack_controller_dbus_reset_parameter_value() called");
+
+    if (!jack_controller_dbus_get_parameter_address(call, address))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_controller_dbus_get_parameter_address() has
+         * constructed an error for us. */
+        return;
+    }
+
+    //jack_info("address is '%s':'%s':'%s'", address[0], address[1], address[2]);
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_ENGINE) == 0) /* engine parameters requested */
+    {
+        if (strcmp(address[1], ENGINE_DRIVER_PARAMETER_NAME) == 0)
+        {
+            jack_controller_reset_parameter_value_engine_driver(call);
+
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown engine parameter '%s'",
+                address[1]);
+            return;
+        }
+
+        jack_controller_reset_parameter_value(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] == NULL &&
+        strcmp(address[0], PTNODE_DRIVER) == 0) /* current driver parameters requested */
+    {
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(controller_ptr->driver), address[1]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[1],
+                jackctl_driver_get_name(controller_ptr->driver));
+            return;
+        }
+
+        jack_controller_reset_parameter_value(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_DRIVERS) == 0)
+    {
+        driver = jack_controller_find_driver(controller_ptr->server, address[1]);
+        if (driver == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown driver '%s'",
+                address[1]);
+            return;
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for driver '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_reset_parameter_value(call, parameter);
+
+        return;
+    }
+
+    if (address[0] != NULL &&
+        address[1] != NULL &&
+        address[2] != NULL &&
+        strcmp(address[0], PTNODE_INTERNALS) == 0)
+    {
+#if 0
+        internal = jack_controller_find_internal(controller_ptr->server, address[1]);
+        if (internal == NULL)
+        {
+#endif
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_INTERNAL,
+                "Unknown internal '%s'",
+                address[1]);
+            return;
+#if 0
+        }
+
+        parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), address[2]);
+        if (parameter == NULL)
+        {
+            jack_dbus_error(
+                call,
+                JACK_DBUS_ERROR_UNKNOWN_PARAMETER,
+                "Unknown parameter '%s' for internal '%s'",
+                address[2],
+                address[1]);
+            return;
+        }
+
+        jack_controller_reset_parameter_value(call, parameter);
+
+        return;
+#endif
+    }
+
+    jack_dbus_error(
+        call,
+        JACK_DBUS_ERROR_INVALID_ARGS,
+        "Invalid container address '%s':'%s':'%s' supplied to method '%s'.",
+        address[0],
+        address[1],
+        address[2],
+        call->method_name);
+}
+
+#undef controller_ptr
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(ReadContainer, "Get names of child parameters or containers")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parent", "as", "Address of parent container")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("leaf", "b", "Whether children are parameters (true) or containers (false)")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("children", "as", "Array of child names")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(GetParametersInfo, "Retrieve info about parameters")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parent", "as", "Address of parameters parent")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("parameter_info_array", "a(ysss)", "Array of parameter info structs. Each info struct contains: type char, name, short and long description")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(GetParameterInfo, "Retrieve info about parameter")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parameter", "as", "Address of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("parameter_info", "(ysss)", "Parameter info struct that contains: type char, name, short and long description")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(GetParameterConstraint, "Get constraint of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parameter", "as", "Address of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("is_range", "b", "Whether constrinat is a range. If so, values parameter will contain two values, min and max")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("is_strict", "b", "Whether enum constraint is strict. I.e. value not listed in values array will not work")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("is_fake_value", "b", "Whether enum values are fake. I.e. have no user meaningful meaning")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("values", "a(vs)", "Values. If there is no constraint, this array will be empty. For range constraint there will be two values, min and max. For enum constraint there will be 2 or more values.")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(GetParameterValue, "Get value of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parameter", "as", "Address of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("is_set", "b", "Whether parameter is set or its default value is used")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("default", "v", "Default value of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_OUT("value", "v", "Actual value of parameter")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(SetParameterValue, "Set value of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parameter", "as", "Address of parameter")
+    JACK_DBUS_METHOD_ARGUMENT_IN("value", "v", "New value for parameter")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(ResetParameterValue, "Reset parameter to default value")
+    JACK_DBUS_METHOD_ARGUMENT_IN("parameter", "as", "Address of parameter")
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHODS_BEGIN
+    JACK_DBUS_METHOD_DESCRIBE(ReadContainer, jack_controller_dbus_read_container)
+    JACK_DBUS_METHOD_DESCRIBE(GetParametersInfo, jack_controller_dbus_get_parameters_info)
+    JACK_DBUS_METHOD_DESCRIBE(GetParameterInfo, jack_controller_dbus_get_parameter_info)
+    JACK_DBUS_METHOD_DESCRIBE(GetParameterConstraint, jack_controller_dbus_get_parameter_constraint)
+    JACK_DBUS_METHOD_DESCRIBE(GetParameterValue, jack_controller_dbus_get_parameter_value)
+    JACK_DBUS_METHOD_DESCRIBE(SetParameterValue, jack_controller_dbus_set_parameter_value)
+    JACK_DBUS_METHOD_DESCRIBE(ResetParameterValue, jack_controller_dbus_reset_parameter_value)
+JACK_DBUS_METHODS_END
+
+/*
+ * Parameter addresses:
+ *
+ * "engine"
+ * "engine", "driver"
+ * "engine", "realtime"
+ * "engine", ...more engine parameters
+ *
+ * "driver", "device"
+ * "driver", ...more driver parameters
+ *
+ * "drivers", "alsa", "device"
+ * "drivers", "alsa", ...more alsa driver parameters
+ *
+ * "drivers", ...more drivers
+ *
+ * "internals", "netmanager", "multicast_ip"
+ * "internals", "netmanager", ...more netmanager parameters
+ *
+ * "internals", ...more internals
+ *
+ */
+
+JACK_DBUS_IFACE_BEGIN(g_jack_controller_iface_configure, "org.jackaudio.Configure")
+    JACK_DBUS_IFACE_EXPOSE_METHODS
+JACK_DBUS_IFACE_END
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_iface_control.c jack1/jackd/jackcontroller_iface_control.c
--- jack1.old/jackd/jackcontroller_iface_control.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_iface_control.c	2013-10-06 17:44:27.117302810 +0100
@@ -0,0 +1,283 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008,2010 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dbus/dbus.h>
+
+#include <include/internal.h>
+
+#include "jackdbus.h"
+#include "jackcontroller_internal.h"
+
+#define JACK_DBUS_IFACE_NAME "org.jackaudio.JackControl"
+
+#define controller_ptr ((struct jack_controller *)call->context)
+
+/*
+ * Check if the supplied method name exists in org.jackaudio.JackControl,
+ * if it does execute it and return true. Otherwise return false.
+ */
+static
+bool
+jack_control_run_method(
+	struct jack_dbus_method_call * call,
+	const struct jack_dbus_interface_method_descriptor * methods)
+{
+	int type;
+	message_arg_t arg;
+
+	/* use empty reply if not overriden in the code that follows */
+	type = DBUS_TYPE_INVALID;
+
+	if (strcmp (call->method_name, "Exit") == 0)
+	{
+                g_exit_command = TRUE;
+	}
+	else if (strcmp (call->method_name, "IsStarted") == 0)
+	{
+		type = DBUS_TYPE_BOOLEAN;
+		arg.boolean = (dbus_bool_t) (controller_ptr->started ? TRUE : FALSE);
+	}
+	else if (strcmp (call->method_name, "StartServer") == 0)
+	{
+		if (controller_ptr->started)
+		{
+			jack_info("Already started.");
+		}
+		else
+		{
+			if (!jack_controller_start_server(controller_ptr, call))
+			{
+				jack_error ("Failed to start server");
+			}
+			else
+			{
+				jack_dbus_send_signal(
+					JACK_CONTROLLER_OBJECT_PATH,
+					JACK_DBUS_IFACE_NAME,
+					"ServerStarted",
+					DBUS_TYPE_INVALID);
+			}
+		}
+	}
+	else if (strcmp (call->method_name, "StopServer") == 0)
+	{
+		if (!controller_ptr->started)
+		{
+			jack_info("Already stopped.");
+		}
+		else
+		{
+			if (!jack_controller_stop_server(controller_ptr, call))
+			{
+				jack_error ("Failed to stop server");
+			}
+			else
+			{
+				jack_dbus_send_signal(
+					JACK_CONTROLLER_OBJECT_PATH,
+					JACK_DBUS_IFACE_NAME,
+					"ServerStopped",
+					DBUS_TYPE_INVALID);
+			}
+		}
+	}
+	else if (strcmp (call->method_name, "GetLoad") == 0)
+	{
+		if (!controller_ptr->started)
+		{
+			goto not_started;
+		}
+
+		type = DBUS_TYPE_DOUBLE;
+		arg.doubl = jackctl_server_get_load(controller_ptr->server);
+	}
+	else if (strcmp (call->method_name, "GetXruns") == 0)
+	{
+		type = DBUS_TYPE_UINT32;
+		arg.uint32 = (uint32_t)jackctl_server_get_xruns(controller_ptr->server);
+	}
+	else if (strcmp (call->method_name, "GetSampleRate") == 0)
+	{
+		if (!controller_ptr->started)
+		{
+			goto not_started;
+		}
+
+		type = DBUS_TYPE_UINT32;
+		arg.uint32 = (uint32_t)jackctl_server_get_sample_rate(controller_ptr->server);
+	}
+	else if (strcmp (call->method_name, "GetLatency") == 0)
+	{
+		if (!controller_ptr->started)
+		{
+			goto not_started;
+		}
+
+		type = DBUS_TYPE_DOUBLE;
+		arg.doubl = jackctl_server_get_latency(controller_ptr->server);
+	}
+	else if (strcmp (call->method_name, "GetBufferSize") == 0)
+	{
+		if (!controller_ptr->started)
+		{
+			goto not_started;
+		}
+
+		type = DBUS_TYPE_UINT32;
+		arg.uint32 = jackctl_server_get_buffer_size(controller_ptr->server);
+	}
+	else if (strcmp (call->method_name, "SetBufferSize") == 0)
+	{
+		dbus_uint32_t buffer_size;
+
+		if (!controller_ptr->started)
+		{
+			goto not_started;
+		}
+
+		if (!jack_dbus_get_method_args(call, DBUS_TYPE_UINT32, &buffer_size, DBUS_TYPE_INVALID))
+		{
+			/* jack_dbus_get_method_args() has set reply for us */
+			goto exit;
+		}
+
+		if (!jackctl_server_set_buffer_size(controller_ptr->server, buffer_size))
+		{
+			jack_dbus_error(
+				call,
+				JACK_DBUS_ERROR_GENERIC,
+				"jackctl_server_set_buffer_size() failed.");
+
+			goto exit;
+		}
+	}
+	else if (strcmp (call->method_name, "IsRealtime") == 0)
+	{
+		type = DBUS_TYPE_BOOLEAN;
+		arg.boolean = (dbus_bool_t) (jackctl_server_is_realtime(controller_ptr->server) ? TRUE : FALSE);
+	}
+	else if (strcmp (call->method_name, "ResetXruns") == 0)
+	{
+		jackctl_server_reset_xruns(controller_ptr->server);
+	}
+	else
+	{
+		return false;
+	}
+
+	jack_dbus_construct_method_return_single(call, type, arg);
+
+	return true;
+
+not_started:
+	jack_dbus_error (call, JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
+	                 "Can't execute this method with stopped JACK server");
+
+exit:
+	return true;
+}
+
+#undef controller_ptr
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(IsStarted)
+	JACK_DBUS_METHOD_ARGUMENT("started", "b", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(StartServer)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(StopServer)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetLoad)
+	JACK_DBUS_METHOD_ARGUMENT("load", "d", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetXruns)
+	JACK_DBUS_METHOD_ARGUMENT("xruns_count", "u", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetSampleRate)
+	JACK_DBUS_METHOD_ARGUMENT("sample_rate", "u", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetLatency)
+	JACK_DBUS_METHOD_ARGUMENT("latency_ms", "d", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetBufferSize)
+	JACK_DBUS_METHOD_ARGUMENT("buffer_size_frames", "u", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(SetBufferSize)
+	JACK_DBUS_METHOD_ARGUMENT("buffer_size_frames", "u", false)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(IsRealtime)
+	JACK_DBUS_METHOD_ARGUMENT("realtime", "b", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ResetXruns)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+static
+const struct jack_dbus_interface_method_descriptor g_jack_controller_control_iface_methods[] =
+{
+	JACK_DBUS_METHOD_DESCRIBE(IsStarted, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(StartServer, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(StopServer, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(GetLoad, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(GetXruns, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(GetSampleRate, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(GetLatency, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(GetBufferSize, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(SetBufferSize, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(IsRealtime, NULL)
+	JACK_DBUS_METHOD_DESCRIBE(ResetXruns, NULL)
+	JACK_DBUS_METHOD_DESCRIBE_END
+};
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ServerStarted)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ServerStopped)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+static
+const struct jack_dbus_interface_signal_descriptor g_jack_controller_control_iface_signals[] =
+{
+	JACK_DBUS_SIGNAL_DESCRIBE(ServerStarted)
+	JACK_DBUS_SIGNAL_DESCRIBE(ServerStopped)
+	JACK_DBUS_SIGNAL_DESCRIBE_END
+};
+
+struct jack_dbus_interface_descriptor g_jack_controller_iface_control =
+{
+	.name = JACK_DBUS_IFACE_NAME,
+	.handler = jack_control_run_method,
+	.methods = g_jack_controller_control_iface_methods,
+	.signals = g_jack_controller_control_iface_signals
+};
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_iface_introspectable.c jack1/jackd/jackcontroller_iface_introspectable.c
--- jack1.old/jackd/jackcontroller_iface_introspectable.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_iface_introspectable.c	2013-10-06 17:44:19.772394634 +0100
@@ -0,0 +1,159 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007-2008 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dbus/dbus.h>
+
+#include "jackdbus.h"
+
+static char g_xml_data[102400];
+
+static
+void
+jack_controller_dbus_introspect(
+	struct jack_dbus_method_call * call)
+{
+	jack_dbus_construct_method_return_single(
+		call,
+		DBUS_TYPE_STRING,
+		(message_arg_t)(const char *)g_xml_data);
+}
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(Introspect)
+	JACK_DBUS_METHOD_ARGUMENT("xml_data", "s", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+static
+const struct jack_dbus_interface_method_descriptor g_jack_controller_introspectable_iface_methods[] =
+{
+	JACK_DBUS_METHOD_DESCRIBE(Introspect, jack_controller_dbus_introspect)
+	JACK_DBUS_METHOD_DESCRIBE_END
+};
+
+JACK_DBUS_IFACE_DESCRIBE(
+	g_jack_controller_iface_introspectable,
+	"org.freedesktop.DBus.Introspectable",
+	g_jack_controller_introspectable_iface_methods,
+	NULL);
+
+static char * g_buffer_ptr;
+
+static
+void
+write_line_format(const char * format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	g_buffer_ptr += vsprintf(g_buffer_ptr, format, ap);
+	va_end(ap);
+}
+
+static
+void
+write_line(const char * line)
+{
+	write_line_format("%s\n", line);
+}
+
+void jack_controller_introspect_init() __attribute__((constructor));
+
+void
+jack_controller_introspect_init()
+{
+	struct jack_dbus_interface_descriptor ** interface_ptr_ptr;
+	const struct jack_dbus_interface_method_descriptor * method_ptr;
+	const struct jack_dbus_interface_method_argument_descriptor * method_argument_ptr;
+	const struct jack_dbus_interface_signal_descriptor * signal_ptr;
+	const struct jack_dbus_interface_signal_argument_descriptor * signal_argument_ptr;
+
+	g_buffer_ptr = g_xml_data;
+
+	write_line("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"");
+	write_line("\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">");
+
+	write_line("<node name=\"" JACK_CONTROLLER_OBJECT_PATH "\">");
+
+	interface_ptr_ptr = g_jackcontroller_interfaces;
+
+	while (*interface_ptr_ptr != NULL)
+	{
+		write_line_format("  <interface name=\"%s\">\n", (*interface_ptr_ptr)->name);
+
+		if ((*interface_ptr_ptr)->methods != NULL)
+		{
+			method_ptr = (*interface_ptr_ptr)->methods;
+			while (method_ptr->name != NULL)
+			{
+				write_line_format("    <method name=\"%s\">\n", method_ptr->name);
+
+				method_argument_ptr = method_ptr->arguments;
+
+				while (method_argument_ptr->name != NULL)
+				{
+					write_line_format(
+						"      <arg name=\"%s\" type=\"%s\" direction=\"%s\" />\n",
+						method_argument_ptr->name,
+						method_argument_ptr->type,
+						method_argument_ptr->direction_out ? "out" : "in");
+					method_argument_ptr++;
+				}
+
+				write_line("    </method>");
+				method_ptr++;
+			}
+		}
+
+		if ((*interface_ptr_ptr)->signals != NULL)
+		{
+			signal_ptr = (*interface_ptr_ptr)->signals;
+			while (signal_ptr->name != NULL)
+			{
+				write_line_format("    <signal name=\"%s\">\n", signal_ptr->name);
+
+				signal_argument_ptr = signal_ptr->arguments;
+
+				while (signal_argument_ptr->name != NULL)
+				{
+					write_line_format(
+						"      <arg name=\"%s\" type=\"%s\" />\n",
+						signal_argument_ptr->name,
+						signal_argument_ptr->type);
+					signal_argument_ptr++;
+				}
+
+				write_line("    </signal>");
+				signal_ptr++;
+			}
+		}
+
+		write_line("  </interface>");
+		interface_ptr_ptr++;
+	}
+
+	write_line("</node>");
+
+	*g_buffer_ptr = 0;
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_iface_patchbay.c jack1/jackd/jackcontroller_iface_patchbay.c
--- jack1.old/jackd/jackcontroller_iface_patchbay.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_iface_patchbay.c	2013-10-06 17:44:27.118302797 +0100
@@ -0,0 +1,1364 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2008,2010 Nedko Arnaudov
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dbus/dbus.h>
+
+#include <include/internal.h>
+
+#include "jackdbus.h"
+#include "jackcontroller_internal.h"
+#include "../include/list.h"
+
+#define JACK_DBUS_IFACE_NAME "org.jackaudio.JackPatchbay"
+
+struct jack_graph
+{
+	uint64_t version;
+	struct list_head clients;
+	struct list_head ports;
+	struct list_head connections;
+};
+
+struct jack_graph_client
+{
+	uint64_t id;
+	char * name;
+	int pid;
+	struct list_head siblings;
+	struct list_head ports;
+};
+
+struct jack_graph_port
+{
+	uint64_t id;
+	char * name;
+	uint32_t flags;
+	uint32_t type;
+	struct list_head siblings_graph;
+	struct list_head siblings_client;
+	struct jack_graph_client * client;
+};
+
+struct jack_graph_connection
+{
+	uint64_t id;
+	struct jack_graph_port * port1;
+	struct jack_graph_port * port2;
+	struct list_head siblings;
+};
+
+struct jack_controller_patchbay
+{
+	pthread_mutex_t lock;
+	struct jack_graph graph;
+};
+
+bool
+jack_controller_patchbay_init(
+	struct jack_controller * controller_ptr)
+{
+	struct jack_controller_patchbay * patchbay_ptr;
+
+	//jack_info("jack_controller_patchbay_init() called");
+
+	patchbay_ptr = malloc(sizeof(struct jack_controller_patchbay));
+	if (patchbay_ptr == NULL)
+	{
+		jack_error("Memory allocation of jack_controller_patchbay structure failed.");
+		return false;
+	}
+
+	pthread_mutex_init(&patchbay_ptr->lock, NULL);
+	INIT_LIST_HEAD(&patchbay_ptr->graph.clients);
+	INIT_LIST_HEAD(&patchbay_ptr->graph.ports);
+	INIT_LIST_HEAD(&patchbay_ptr->graph.connections);
+	patchbay_ptr->graph.version = 1;
+
+	controller_ptr->patchbay_context = patchbay_ptr;
+
+	return true;
+}
+
+void
+jack_controller_patchbay_send_signal_graph_changed(
+	dbus_uint64_t new_graph_version)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"GraphChanged",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_INVALID);
+}
+
+void
+jack_controller_patchbay_send_signal_client_appeared(
+	dbus_uint64_t new_graph_version,
+	dbus_uint64_t client_id,
+	const char * client_name)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"ClientAppeared",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_UINT64,
+		&client_id,
+		DBUS_TYPE_STRING,
+		&client_name,
+		DBUS_TYPE_INVALID);
+}
+
+void
+jack_controller_patchbay_send_signal_client_disappeared(
+	dbus_uint64_t new_graph_version,
+	dbus_uint64_t client_id,
+	const char * client_name)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"ClientDisappeared",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_UINT64,
+		&client_id,
+		DBUS_TYPE_STRING,
+		&client_name,
+		DBUS_TYPE_INVALID);
+}
+
+void
+jack_controller_patchbay_send_signal_port_appeared(
+	dbus_uint64_t new_graph_version,
+	dbus_uint64_t client_id,
+	const char * client_name,
+	dbus_uint64_t port_id,
+	const char * port_name,
+	dbus_uint32_t port_flags,
+	dbus_uint32_t port_type)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"PortAppeared",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_UINT64,
+		&client_id,
+		DBUS_TYPE_STRING,
+		&client_name,
+		DBUS_TYPE_UINT64,
+		&port_id,
+		DBUS_TYPE_STRING,
+		&port_name,
+		DBUS_TYPE_UINT32,
+		&port_flags,
+		DBUS_TYPE_UINT32,
+		&port_type,
+		DBUS_TYPE_INVALID);
+}
+
+void
+jack_controller_patchbay_send_signal_port_disappeared(
+	dbus_uint64_t new_graph_version,
+	dbus_uint64_t client_id,
+	const char * client_name,
+	dbus_uint64_t port_id,
+	const char * port_name)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"PortDisappeared",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_UINT64,
+		&client_id,
+		DBUS_TYPE_STRING,
+		&client_name,
+		DBUS_TYPE_UINT64,
+		&port_id,
+		DBUS_TYPE_STRING,
+		&port_name,
+		DBUS_TYPE_INVALID);
+}
+
+void
+jack_controller_patchbay_send_signal_ports_connected(
+	dbus_uint64_t new_graph_version,
+	dbus_uint64_t client1_id,
+	const char * client1_name,
+	dbus_uint64_t port1_id,
+	const char * port1_name,
+	dbus_uint64_t client2_id,
+	const char * client2_name,
+	dbus_uint64_t port2_id,
+	const char * port2_name,
+	dbus_uint64_t connection_id)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"PortsConnected",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_UINT64,
+		&client1_id,
+		DBUS_TYPE_STRING,
+		&client1_name,
+		DBUS_TYPE_UINT64,
+		&port1_id,
+		DBUS_TYPE_STRING,
+		&port1_name,
+		DBUS_TYPE_UINT64,
+		&client2_id,
+		DBUS_TYPE_STRING,
+		&client2_name,
+		DBUS_TYPE_UINT64,
+		&port2_id,
+		DBUS_TYPE_STRING,
+		&port2_name,
+		DBUS_TYPE_UINT64,
+		&connection_id,
+		DBUS_TYPE_INVALID);
+}
+
+void
+jack_controller_patchbay_send_signal_ports_disconnected(
+	dbus_uint64_t new_graph_version,
+	dbus_uint64_t client1_id,
+	const char * client1_name,
+	dbus_uint64_t port1_id,
+	const char * port1_name,
+	dbus_uint64_t client2_id,
+	const char * client2_name,
+	dbus_uint64_t port2_id,
+	const char * port2_name,
+	dbus_uint64_t connection_id)
+{
+
+	jack_dbus_send_signal(
+		JACK_CONTROLLER_OBJECT_PATH,
+		JACK_DBUS_IFACE_NAME,
+		"PortsDisconnected",
+		DBUS_TYPE_UINT64,
+		&new_graph_version,
+		DBUS_TYPE_UINT64,
+		&client1_id,
+		DBUS_TYPE_STRING,
+		&client1_name,
+		DBUS_TYPE_UINT64,
+		&port1_id,
+		DBUS_TYPE_STRING,
+		&port1_name,
+		DBUS_TYPE_UINT64,
+		&client2_id,
+		DBUS_TYPE_STRING,
+		&client2_name,
+		DBUS_TYPE_UINT64,
+		&port2_id,
+		DBUS_TYPE_STRING,
+		&port2_name,
+		DBUS_TYPE_UINT64,
+		&connection_id,
+		DBUS_TYPE_INVALID);
+}
+
+static
+struct jack_graph_client *
+jack_controller_patchbay_find_client_by_id(
+    struct jack_controller_patchbay *patchbay_ptr,
+    uint64_t id)
+{
+    struct list_head *node_ptr;
+    struct jack_graph_client *client_ptr;
+
+    list_for_each(node_ptr, &patchbay_ptr->graph.clients)
+    {
+        client_ptr = list_entry(node_ptr, struct jack_graph_client, siblings);
+        if (client_ptr->id == id)
+        {
+            return client_ptr;
+        }
+    }
+
+    return NULL;
+}
+
+#define patchbay_ptr ((struct jack_controller_patchbay *)((struct jack_controller *)server_context)->patchbay_context)
+
+void *
+jack_controller_patchbay_client_appeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	const char * client_name)
+{
+	struct jack_graph_client * client_ptr;
+
+/* 	jack_info("new client: '%s' (%" PRIu64 ")", client_name, client_id); */
+
+	client_ptr = malloc(sizeof(struct jack_graph_client));
+	if (client_ptr == NULL)
+	{
+		jack_error("Memory allocation of jack_graph_client structure failed.");
+		goto fail;
+	}
+
+	client_ptr->name = strdup(client_name);
+	if (client_ptr->name == NULL)
+	{
+		jack_error("strdup() call for client name '%s' failed.", client_name);
+		goto fail_free_client;
+	}
+
+	client_ptr->id = client_id;
+	INIT_LIST_HEAD(&client_ptr->ports);
+
+	client_ptr->pid = jackctl_get_client_pid(((struct jack_controller *)server_context)->server, client_ptr->name);
+	jack_info("New client '%s' with PID %d", client_ptr->name, client_ptr->pid);
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+	list_add_tail(&client_ptr->siblings, &patchbay_ptr->graph.clients);
+	patchbay_ptr->graph.version++;
+	jack_controller_patchbay_send_signal_client_appeared(patchbay_ptr->graph.version, client_id, client_name);
+	jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	return client_ptr;
+
+fail_free_client:
+	free(client_ptr);
+
+fail:
+	return NULL;
+}
+
+#define client_ptr ((struct jack_graph_client *)client_context)
+
+void
+jack_controller_patchbay_client_disappeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context)
+{
+/* 	jack_info("client %" PRIu64 " gone", client_id); */
+
+	if (client_ptr == NULL)
+	{
+		jack_error("Ignoring disappear of client that failed to appear.");
+		return;
+	}
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+	list_del(&client_ptr->siblings);
+	patchbay_ptr->graph.version++;
+	jack_controller_patchbay_send_signal_client_disappeared(patchbay_ptr->graph.version, client_id, client_ptr->name);
+	jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	free(client_ptr->name);
+	free(client_ptr);
+}
+
+void *
+jack_controller_patchbay_port_appeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context,
+	uint64_t port_id,
+	const char * port_name,
+	uint32_t port_flags,
+	uint32_t port_type)
+{
+	struct jack_graph_port * port_ptr;
+
+/* 	jack_info( */
+/* 		"new port: '%s' (%" PRIu64 "), flags 0x%" PRIX32 ", type %" PRIu32 ", of client %" PRIu64, */
+/* 		port_name, */
+/* 		port_id, */
+/* 		port_flags, */
+/* 		port_type, */
+/* 		client_id); */
+
+	port_ptr = malloc(sizeof(struct jack_graph_port));
+	if (port_ptr == NULL)
+	{
+		jack_error("Memory allocation of jack_graph_port structure failed.");
+		goto fail;
+	}
+
+	port_ptr->name = strdup(port_name);
+	if (port_ptr->name == NULL)
+	{
+		jack_error("strdup() call for port name '%s' failed.", port_name);
+		goto fail_free_client;
+	}
+
+	port_ptr->id = port_id;
+	port_ptr->flags = port_flags;
+	port_ptr->type = port_type;
+	port_ptr->client = client_ptr;
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+	list_add_tail(&port_ptr->siblings_client, &client_ptr->ports);
+	list_add_tail(&port_ptr->siblings_graph, &patchbay_ptr->graph.ports);
+	patchbay_ptr->graph.version++;
+	jack_controller_patchbay_send_signal_port_appeared(
+		patchbay_ptr->graph.version,
+		client_id,
+		client_ptr->name,
+		port_id,
+		port_name,
+		port_flags,
+		port_type);
+	jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	return port_ptr;
+
+fail_free_client:
+	free(port_ptr);
+
+fail:
+	return NULL;
+}
+
+#define port_ptr ((struct jack_graph_port *)port_context)
+
+void
+jack_controller_patchbay_port_disappeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context,
+	uint64_t port_id,
+	void * port_context)
+{
+/* 	jack_info("port %" PRIu64 " of client %" PRIu64 " gone", port_id, client_id); */
+
+	if (port_ptr == NULL)
+	{
+		jack_error("Ignoring disappear of port that failed to appear.");
+		return;
+	}
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+	list_del(&port_ptr->siblings_client);
+	list_del(&port_ptr->siblings_graph);
+	patchbay_ptr->graph.version++;
+	jack_controller_patchbay_send_signal_port_disappeared(patchbay_ptr->graph.version, client_id, client_ptr->name, port_id, port_ptr->name);
+	jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	free(port_ptr->name);
+	free(port_ptr);
+}
+
+#undef port_ptr
+#undef client_ptr
+
+#define port1_ptr ((struct jack_graph_port *)port1_context)
+#define port2_ptr ((struct jack_graph_port *)port2_context)
+
+void *
+jack_controller_patchbay_ports_connected_callback(
+	void * server_context,
+	uint64_t client1_id,
+	void * client1_context,
+	uint64_t port1_id,
+	void * port1_context,
+	uint64_t client2_id,
+	void * client2_context,
+	uint64_t port2_id,
+	void * port2_context,
+	uint64_t connection_id)
+{
+	struct jack_graph_connection * connection_ptr;
+
+/* 	jack_info( */
+/* 		"connected: '%s' (%" PRIu64 "), of client %" PRIu64 " and '%s' (%" PRIu64 "), of client %" PRIu64, */
+/* 		port1_ptr->name, */
+/* 		port1_id, */
+/* 		client1_id, */
+/* 		port2_ptr->name, */
+/* 		port2_id, */
+/* 		client2_id); */
+
+	connection_ptr = malloc(sizeof(struct jack_graph_connection));
+	if (connection_ptr == NULL)
+	{
+		jack_error("Memory allocation of jack_graph_connection structure failed.");
+		return NULL;
+	}
+
+	connection_ptr->id = connection_id;
+	connection_ptr->port1 = port1_ptr;
+	connection_ptr->port2 = port2_ptr;
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+	list_add_tail(&connection_ptr->siblings, &patchbay_ptr->graph.connections);
+	patchbay_ptr->graph.version++;
+	jack_controller_patchbay_send_signal_ports_connected(
+		patchbay_ptr->graph.version,
+		client1_id,
+		port1_ptr->client->name,
+		port1_id,
+		port1_ptr->name,
+		client2_id,
+		port2_ptr->client->name,
+		port2_id,
+		port2_ptr->name,
+		connection_id);
+	jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	return connection_ptr;
+}
+
+#define connection_ptr ((struct jack_graph_connection *)connection_context)
+
+void
+jack_controller_patchbay_ports_disconnected_callback(
+	void * server_context,
+	uint64_t client1_id,
+	void * client1_context,
+	uint64_t port1_id,
+	void * port1_context,
+	uint64_t client2_id,
+	void * client2_context,
+	uint64_t port2_id,
+	void * port2_context,
+	uint64_t connection_id,
+	void * connection_context)
+{
+/* 	jack_info( */
+/* 		"disconnected: '%s' (%" PRIu64 "), of client %" PRIu64 " and '%s' (%" PRIu64 "), of client %" PRIu64, */
+/* 		port1_ptr->name, */
+/* 		port1_id, */
+/* 		client1_id, */
+/* 		port2_ptr->name, */
+/* 		port2_id, */
+/* 		client2_id); */
+
+	if (connection_ptr == NULL)
+	{
+		jack_error("Ignoring removal of connection that failed to appear.");
+		return;
+	}
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+	list_del(&connection_ptr->siblings);
+	patchbay_ptr->graph.version++;
+	jack_controller_patchbay_send_signal_ports_disconnected(
+		patchbay_ptr->graph.version,
+		client1_id,
+		port1_ptr->client->name,
+		port1_id,
+		port1_ptr->name,
+		client2_id,
+		port2_ptr->client->name,
+		port2_id,
+		port2_ptr->name,
+		connection_id);
+	jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	free(connection_ptr);
+}
+
+#undef connection_ptr
+#undef port1_ptr
+#undef port2_ptr
+#undef patchbay_ptr
+
+#define controller_ptr ((struct jack_controller *)call->context)
+#define patchbay_ptr ((struct jack_controller_patchbay *)controller_ptr->patchbay_context)
+
+static
+void
+jack_controller_dbus_get_all_ports(
+	struct jack_dbus_method_call * call)
+{
+	struct list_head * client_node_ptr;
+	struct list_head * port_node_ptr;
+	struct jack_graph_client * client_ptr;
+	struct jack_graph_port * port_ptr;
+	DBusMessageIter iter, sub_iter;
+	char fullname[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+	char *fullname_var = fullname;
+
+	call->reply = dbus_message_new_method_return (call->message);
+	if (!call->reply)
+	{
+		goto fail;
+	}
+
+	dbus_message_iter_init_append (call->reply, &iter);
+
+	if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
+	{
+		goto fail_unref;
+	}
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+
+	list_for_each(client_node_ptr, &patchbay_ptr->graph.clients)
+	{
+		client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings);
+
+		list_for_each(port_node_ptr, &client_ptr->ports)
+		{
+			port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client);
+
+			jack_info("%s:%s", client_ptr->name, port_ptr->name);
+			sprintf(fullname, "%s:%s", client_ptr->name, port_ptr->name);
+			if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, &fullname_var))
+			{
+				pthread_mutex_unlock(&patchbay_ptr->lock);
+				dbus_message_iter_close_container (&iter, &sub_iter);
+				goto fail_unref;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	if (!dbus_message_iter_close_container (&iter, &sub_iter))
+	{
+		goto fail_unref;
+	}
+
+	return;
+
+fail_unref:
+	dbus_message_unref (call->reply);
+	call->reply = NULL;
+
+fail:
+	jack_error ("Ran out of memory trying to construct method return");
+}
+
+static
+void
+jack_controller_dbus_get_graph(
+	struct jack_dbus_method_call * call)
+{
+	struct list_head * client_node_ptr;
+	struct list_head * port_node_ptr;
+	struct list_head * connection_node_ptr;
+	struct jack_graph_client * client_ptr;
+	struct jack_graph_port * port_ptr;
+	struct jack_graph_connection * connection_ptr;
+	DBusMessageIter iter;
+	DBusMessageIter clients_array_iter;
+	DBusMessageIter client_struct_iter;
+	DBusMessageIter ports_array_iter;
+	DBusMessageIter port_struct_iter;
+	dbus_uint64_t version;
+	DBusMessageIter connections_array_iter;
+	DBusMessageIter connection_struct_iter;
+
+	if (!jack_dbus_get_method_args(call, DBUS_TYPE_UINT64, &version, DBUS_TYPE_INVALID))
+	{
+		/* The method call had invalid arguments meaning that
+		 * jack_dbus_get_method_args() has constructed an error for us.
+		 */
+		goto exit;
+	}
+
+	//jack_info("Getting graph, know version is %" PRIu32, version);
+
+	call->reply = dbus_message_new_method_return(call->message);
+	if (!call->reply)
+	{
+		jack_error("Ran out of memory trying to construct method return");
+		goto exit;
+	}
+
+	dbus_message_iter_init_append (call->reply, &iter);
+
+	pthread_mutex_lock(&patchbay_ptr->lock);
+
+	if (version > patchbay_ptr->graph.version)
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_INVALID_ARGS,
+			"known graph version %" PRIu64 " is newer than actual version %" PRIu64,
+			version,
+			patchbay_ptr->graph.version);
+		pthread_mutex_unlock(&patchbay_ptr->lock);
+		goto exit;
+	}
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &patchbay_ptr->graph.version))
+	{
+		goto nomem_unlock;
+	}
+
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
+	{
+		goto nomem_unlock;
+	}
+
+	if (version < patchbay_ptr->graph.version)
+	{
+		list_for_each(client_node_ptr, &patchbay_ptr->graph.clients)
+		{
+			client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings);
+
+			if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
+			{
+				goto nomem_close_clients_array;
+			}
+
+			if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
+			{
+				goto nomem_close_client_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name))
+			{
+				goto nomem_close_client_struct;
+			}
+
+			if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
+			{
+				goto nomem_close_client_struct;
+			}
+
+			list_for_each(port_node_ptr, &client_ptr->ports)
+			{
+				port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client);
+
+				if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
+				{
+					goto nomem_close_ports_array;
+				}
+
+				if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
+				{
+					goto nomem_close_port_struct;
+				}
+
+				if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
+				{
+					goto nomem_close_port_struct;
+				}
+
+				if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
+				{
+					goto nomem_close_port_struct;
+				}
+
+				if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
+				{
+					goto nomem_close_port_struct;
+				}
+
+				if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
+				{
+					goto nomem_close_ports_array;
+				}
+			}
+
+			if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
+			{
+				goto nomem_close_client_struct;
+			}
+
+			if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
+			{
+				goto nomem_close_clients_array;
+			}
+		}
+	}
+
+	if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
+	{
+		goto nomem_unlock;
+	}
+
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
+	{
+		goto nomem_unlock;
+	}
+
+	if (version < patchbay_ptr->graph.version)
+	{
+		list_for_each(connection_node_ptr, &patchbay_ptr->graph.connections)
+		{
+			connection_ptr = list_entry(connection_node_ptr, struct jack_graph_connection, siblings);
+
+			if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
+			{
+				goto nomem_close_connections_array;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1->client->id))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1->client->name))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1->id))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1->name))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2->client->id))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2->client->name))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2->id))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2->name))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
+			{
+				goto nomem_close_connection_struct;
+			}
+
+			if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
+			{
+				goto nomem_close_connections_array;
+			}
+		}
+	}
+
+	if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
+	{
+		goto nomem_unlock;
+	}
+
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+	return;
+
+nomem_close_connection_struct:
+	dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
+
+nomem_close_connections_array:
+	dbus_message_iter_close_container(&iter, &connections_array_iter);
+	goto nomem_unlock;
+
+nomem_close_port_struct:
+	dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
+
+nomem_close_ports_array:
+	dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
+
+nomem_close_client_struct:
+	dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
+
+nomem_close_clients_array:
+	dbus_message_iter_close_container(&iter, &clients_array_iter);
+
+nomem_unlock:
+	pthread_mutex_unlock(&patchbay_ptr->lock);
+
+//nomem:
+	dbus_message_unref(call->reply);
+	call->reply = NULL;
+	jack_error("Ran out of memory trying to construct method return");
+
+exit:
+	return;
+}
+
+static
+void
+jack_controller_dbus_connect_ports_by_name(
+	struct jack_dbus_method_call * call)
+{
+	const char * client1_name;
+	const char * port1_name;
+	const char * client2_name;
+	const char * port2_name;
+
+/* 	jack_info("jack_controller_dbus_connect_ports_by_name() called."); */
+
+	if (!controller_ptr->started)
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
+			"Can't execute this method with stopped JACK server");
+		return;
+	}
+
+	if (!jack_dbus_get_method_args(
+		    call,
+		    DBUS_TYPE_STRING,
+		    &client1_name,
+		    DBUS_TYPE_STRING,
+		    &port1_name,
+		    DBUS_TYPE_STRING,
+		    &client2_name,
+		    DBUS_TYPE_STRING,
+		    &port2_name,
+		    DBUS_TYPE_INVALID))
+	{
+		/* The method call had invalid arguments meaning that
+		 * jack_dbus_get_method_args() has constructed an error for us.
+		 */
+		return;
+	}
+
+/* 	jack_info("connecting %s:%s and %s:%s", client1_name, port1_name, client2_name, port2_name); */
+
+	if (!jackctl_connect_ports_by_name(
+		    controller_ptr->server,
+		    client1_name,
+		    port1_name,
+		    client2_name,
+		    port2_name))
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_GENERIC,
+			"jackctl_connect_ports_by_name() failed.");
+		return;
+	}
+
+	jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_connect_ports_by_id(
+	struct jack_dbus_method_call * call)
+{
+	dbus_uint64_t port1;
+	dbus_uint64_t port2;
+
+	jack_info("jack_controller_dbus_connect_ports_by_id() called.");
+
+	if (!controller_ptr->started)
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
+			"Can't execute this method with stopped JACK server");
+		return;
+	}
+
+	if (!jack_dbus_get_method_args(
+		    call,
+		    DBUS_TYPE_UINT64,
+		    &port1,
+		    DBUS_TYPE_UINT64,
+		    &port2,
+		    DBUS_TYPE_INVALID))
+	{
+		/* The method call had invalid arguments meaning that
+		 * jack_dbus_get_method_args() has constructed an error for us.
+		 */
+		return;
+	}
+
+	if (!jackctl_connect_ports_by_id(
+		    controller_ptr->server,
+		    port1,
+		    port2))
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_GENERIC,
+			"jackctl_connect_ports_by_id() failed.");
+		return;
+	}
+
+	jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_disconnect_ports_by_name(
+	struct jack_dbus_method_call * call)
+{
+	const char * client1_name;
+	const char * port1_name;
+	const char * client2_name;
+	const char * port2_name;
+
+/* 	jack_info("jack_controller_dbus_disconnect_ports_by_name() called."); */
+
+	if (!controller_ptr->started)
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
+			"Can't execute this method with stopped JACK server");
+		return;
+	}
+
+	if (!jack_dbus_get_method_args(
+		    call,
+		    DBUS_TYPE_STRING,
+		    &client1_name,
+		    DBUS_TYPE_STRING,
+		    &port1_name,
+		    DBUS_TYPE_STRING,
+		    &client2_name,
+		    DBUS_TYPE_STRING,
+		    &port2_name,
+		    DBUS_TYPE_INVALID))
+	{
+		/* The method call had invalid arguments meaning that
+		 * jack_dbus_get_method_args() has constructed an error for us.
+		 */
+		return;
+	}
+
+/* 	jack_info("disconnecting %s:%s and %s:%s", client1_name, port1_name, client2_name, port2_name); */
+
+	if (!jackctl_disconnect_ports_by_name(
+		    controller_ptr->server,
+		    client1_name,
+		    port1_name,
+		    client2_name,
+		    port2_name))
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_GENERIC,
+			"jackctl_disconnect_ports_by_name() failed.");
+		return;
+	}
+
+	jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_disconnect_ports_by_id(
+	struct jack_dbus_method_call * call)
+{
+	dbus_uint64_t port1;
+	dbus_uint64_t port2;
+
+	jack_info("jack_controller_dbus_disconnect_ports_by_id() called.");
+
+	if (!controller_ptr->started)
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
+			"Can't execute this method with stopped JACK server");
+		return;
+	}
+
+	if (!jack_dbus_get_method_args(
+		    call,
+		    DBUS_TYPE_UINT64,
+		    &port1,
+		    DBUS_TYPE_UINT64,
+		    &port2,
+		    DBUS_TYPE_INVALID))
+	{
+		/* The method call had invalid arguments meaning that
+		 * jack_dbus_get_method_args() has constructed an error for us.
+		 */
+		return;
+	}
+
+	if (!jackctl_disconnect_ports_by_id(
+		    controller_ptr->server,
+		    port1,
+		    port2))
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_GENERIC,
+			"jackctl_disconnect_ports_by_id() failed.");
+		return;
+	}
+
+	jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_disconnect_ports_by_connection_id(
+	struct jack_dbus_method_call * call)
+{
+	dbus_uint64_t id;
+
+	jack_info("jack_controller_dbus_disconnect_ports_by_connection_id() called.");
+
+	if (!controller_ptr->started)
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
+			"Can't execute this method with stopped JACK server");
+		return;
+	}
+
+	if (!jack_dbus_get_method_args(
+		    call,
+		    DBUS_TYPE_UINT64,
+		    &id,
+		    DBUS_TYPE_INVALID))
+	{
+		/* The method call had invalid arguments meaning that
+		 * jack_dbus_get_method_args() has constructed an error for us.
+		 */
+		return;
+	}
+
+	if (!jackctl_disconnect_ports_by_connection_id(
+		    controller_ptr->server,
+		    id))
+	{
+		jack_dbus_error(
+			call,
+			JACK_DBUS_ERROR_GENERIC,
+			"jackctl_disconnect_ports_by_connection_id() failed.");
+		return;
+	}
+
+	jack_dbus_construct_method_return_empty(call);
+}
+
+static
+void
+jack_controller_dbus_get_client_pid(
+    struct jack_dbus_method_call * call)
+{
+    dbus_uint64_t client_id;
+    struct jack_graph_client *client_ptr;
+    message_arg_t arg;
+
+/*     jack_info("jack_controller_dbus_get_client_pid() called."); */
+
+    if (!jack_dbus_get_method_args(
+            call,
+            DBUS_TYPE_UINT64,
+            &client_id,
+            DBUS_TYPE_INVALID))
+    {
+        /* The method call had invalid arguments meaning that
+         * jack_dbus_get_method_args() has constructed an error for us.
+         */
+        return;
+    }
+
+    pthread_mutex_lock(&patchbay_ptr->lock);
+
+    client_ptr = jack_controller_patchbay_find_client_by_id(patchbay_ptr, client_id);
+    if (client_ptr == NULL)
+    {
+        jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find client %" PRIu64, client_id);
+        goto unlock;
+    }
+
+    arg.int64 = client_ptr->pid;
+
+    jack_dbus_construct_method_return_single(call, DBUS_TYPE_INT64, arg);
+
+unlock:
+    pthread_mutex_unlock(&patchbay_ptr->lock);
+}
+
+#undef controller_ptr
+
+void
+jack_controller_patchbay_uninit(
+	struct jack_controller * controller_ptr)
+{
+	//jack_info("jack_controller_patchbay_uninit() called");
+
+	pthread_mutex_destroy(&patchbay_ptr->lock);
+}
+
+#undef patchbay_ptr
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetAllPorts)
+	JACK_DBUS_METHOD_ARGUMENT("ports_list", "as", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetGraph)
+	JACK_DBUS_METHOD_ARGUMENT("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, true)
+	JACK_DBUS_METHOD_ARGUMENT("clients_and_ports", "a(tsa(tsuu))", true)
+	JACK_DBUS_METHOD_ARGUMENT("connections", "a(tstststst)", true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ConnectPortsByName)
+	JACK_DBUS_METHOD_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING, false)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ConnectPortsByID)
+	JACK_DBUS_METHOD_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING, false)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByName)
+	JACK_DBUS_METHOD_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING, false)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByID)
+	JACK_DBUS_METHOD_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING, false)
+	JACK_DBUS_METHOD_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING, false)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByConnectionID)
+	JACK_DBUS_METHOD_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING, false)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetClientPID)
+    JACK_DBUS_METHOD_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING, false)
+    JACK_DBUS_METHOD_ARGUMENT("process_id", DBUS_TYPE_INT64_AS_STRING, true)
+JACK_DBUS_METHOD_ARGUMENTS_END
+
+static
+const struct jack_dbus_interface_method_descriptor g_jack_controller_patchbay_iface_methods[] =
+{
+	JACK_DBUS_METHOD_DESCRIBE(GetAllPorts, jack_controller_dbus_get_all_ports)
+	JACK_DBUS_METHOD_DESCRIBE(GetGraph, jack_controller_dbus_get_graph)
+	JACK_DBUS_METHOD_DESCRIBE(ConnectPortsByName, jack_controller_dbus_connect_ports_by_name)
+	JACK_DBUS_METHOD_DESCRIBE(ConnectPortsByID, jack_controller_dbus_connect_ports_by_id)
+	JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByName, jack_controller_dbus_disconnect_ports_by_name)
+	JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByID, jack_controller_dbus_disconnect_ports_by_id)
+	JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByConnectionID, jack_controller_dbus_disconnect_ports_by_connection_id)
+	JACK_DBUS_METHOD_DESCRIBE(GetClientPID, jack_controller_dbus_get_client_pid)
+	JACK_DBUS_METHOD_DESCRIBE_END
+};
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(GraphChanged)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ClientAppeared)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ClientDisappeared)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortAppeared)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port_flags", DBUS_TYPE_UINT32_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port_type", DBUS_TYPE_UINT32_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortDisappeared)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port_name", DBUS_TYPE_STRING_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortsConnected)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client1_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client2_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortsDisconnected)
+	JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client1_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client2_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING)
+	JACK_DBUS_SIGNAL_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING)
+JACK_DBUS_SIGNAL_ARGUMENTS_END
+
+static
+const struct jack_dbus_interface_signal_descriptor g_jack_controller_patchbay_iface_signals[] =
+{
+	JACK_DBUS_SIGNAL_DESCRIBE(GraphChanged)
+	JACK_DBUS_SIGNAL_DESCRIBE(ClientAppeared)
+	JACK_DBUS_SIGNAL_DESCRIBE(ClientDisappeared)
+	JACK_DBUS_SIGNAL_DESCRIBE(PortAppeared)
+	JACK_DBUS_SIGNAL_DESCRIBE(PortDisappeared)
+	JACK_DBUS_SIGNAL_DESCRIBE(PortsConnected)
+	JACK_DBUS_SIGNAL_DESCRIBE(PortsDisconnected)
+	JACK_DBUS_SIGNAL_DESCRIBE_END
+};
+
+JACK_DBUS_IFACE_DESCRIBE(
+	g_jack_controller_iface_patchbay,
+	JACK_DBUS_IFACE_NAME,
+	g_jack_controller_patchbay_iface_methods,
+	g_jack_controller_patchbay_iface_signals);
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_iface_transport.c jack1/jackd/jackcontroller_iface_transport.c
--- jack1.old/jackd/jackcontroller_iface_transport.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_iface_transport.c	2013-10-06 17:44:19.775394596 +0100
@@ -0,0 +1,40 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2008 Nedko Arnaudov
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dbus/dbus.h>
+
+#include "jackdbus.h"
+
+static
+const struct jack_dbus_interface_method_descriptor g_jack_controller_transport_iface_methods[] =
+{
+	JACK_DBUS_METHOD_DESCRIBE_END
+};
+
+JACK_DBUS_IFACE_DESCRIBE(
+	g_jack_controller_iface_transport,
+	"org.jackaudio.JackTransport",
+	g_jack_controller_transport_iface_methods,
+	NULL);
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_internal.h jack1/jackd/jackcontroller_internal.h
--- jack1.old/jackd/jackcontroller_internal.h	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_internal.h	2013-10-06 17:44:19.776394584 +0100
@@ -0,0 +1,178 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef JACKCONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED
+#define JACKCONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED
+
+#include <stdbool.h>
+#include "jackctl.h"
+#include "jackdbus.h"
+
+struct jack_controller
+{
+	jackctl_server server;
+
+	void * patchbay_context;
+
+	bool started;
+
+	const char ** driver_names;
+	unsigned int drivers_count;
+
+	/* current driver, NULL if not driver is selected */
+	jackctl_driver driver;
+	bool driver_set;
+
+	struct jack_dbus_object_descriptor dbus_descriptor;
+};
+
+#define JACK_CONF_HEADER_TEXT						\
+	"JACK settings, as persisted by D-Bus object.\n"		\
+	"You probably don't want to edit this because\n"		\
+	"it will be overwritten next time jackdbus saves.\n"
+
+jackctl_driver
+jack_controller_find_driver(
+	jackctl_server server,
+	const char * driver_name);
+
+jackctl_parameter
+jack_controller_find_parameter(
+	const JSList * parameters_list,
+	const char * parameter_name);
+
+bool
+jack_controller_start_server(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr);
+
+bool
+jack_controller_stop_server(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr);
+
+bool
+jack_controller_select_driver(
+	struct jack_controller * controller_ptr,
+	const char * driver_name);
+
+void
+jack_controller_settings_set_driver_option(
+	jackctl_driver driver,
+	const char *option_name,
+	const char *option_value);
+
+void
+jack_controller_settings_set_engine_option(
+	struct jack_controller *controller_ptr,
+	const char *option_name,
+	const char *option_value);
+
+bool
+jack_controller_settings_save_engine_options(
+	void *context,
+	struct jack_controller *controller_ptr,
+	void *dbus_call_context_ptr);
+
+bool
+jack_controller_settings_write_option(
+	void *context,
+	const char *name,
+	const char *content,
+	void *dbus_call_context_ptr);
+
+bool
+jack_controller_settings_save_driver_options(
+	void *context,
+	jackctl_driver driver,
+	void *dbus_call_context_ptr);
+
+bool
+jack_controller_patchbay_init(
+	struct jack_controller * controller_ptr);
+
+void
+jack_controller_patchbay_uninit(
+	struct jack_controller * controller_ptr);
+
+void *
+jack_controller_patchbay_client_appeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	const char * client_name);
+
+void
+jack_controller_patchbay_client_disappeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context);
+
+void *
+jack_controller_patchbay_port_appeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context,
+	uint64_t port_id,
+	const char * port_name,
+	uint32_t port_flags,
+	uint32_t port_type);
+
+void
+jack_controller_patchbay_port_disappeared_callback(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context,
+	uint64_t port_id,
+	void * port_context);
+
+void *
+jack_controller_patchbay_ports_connected_callback(
+	void * server_context,
+	uint64_t client1_id,
+	void * client1_context,
+	uint64_t port1_id,
+	void * port1_context,
+	uint64_t client2_id,
+	void * client2_context,
+	uint64_t port2_id,
+	void * port2_context,
+	uint64_t connection_id);
+
+void
+jack_controller_patchbay_ports_disconnected_callback(
+	void * server_context,
+	uint64_t client1_id,
+	void * client1_context,
+	uint64_t port1_id,
+	void * port1_context,
+	uint64_t client2_id,
+	void * client2_context,
+	uint64_t port2_id,
+	void * port2_context,
+	uint64_t connection_id,
+	void * connection_context);
+
+extern struct jack_dbus_interface_descriptor g_jack_controller_iface_introspectable;
+extern struct jack_dbus_interface_descriptor g_jack_controller_iface_control;
+extern struct jack_dbus_interface_descriptor g_jack_controller_iface_configure;
+extern struct jack_dbus_interface_descriptor g_jack_controller_iface_patchbay;
+extern struct jack_dbus_interface_descriptor g_jack_controller_iface_transport;
+
+#endif /* #ifndef JACKCONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED */
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_xml.c jack1/jackd/jackcontroller_xml.c
--- jack1.old/jackd/jackcontroller_xml.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_xml.c	2013-10-06 17:44:27.119302785 +0100
@@ -0,0 +1,314 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <dbus/dbus.h>
+
+#include <include/driver.h>
+#include <include/engine.h>
+#include "jackcontroller_internal.h"
+
+void
+jack_controller_settings_set_bool_option(
+	const char *value_str,
+	int *value_ptr)
+{
+	if (strcmp(value_str, "true") == 0)
+	{
+		*value_ptr = true;
+	}
+	else if (strcmp(value_str, "false") == 0)
+	{
+		*value_ptr = false;
+	}
+	else
+	{
+		jack_error("ignoring unknown bool value \"%s\"", value_str);
+	}
+}
+
+void
+jack_controller_settings_set_sint_option(
+	const char *value_str,
+	int *value_ptr)
+{
+	*value_ptr = atoi(value_str);
+}
+
+void
+jack_controller_settings_set_uint_option(
+	const char *value_str,
+	unsigned int *value_ptr)
+{
+	*value_ptr = strtoul(value_str, NULL, 10);
+}
+
+void
+jack_controller_settings_set_char_option(
+	const char *value_str,
+	char *value_ptr)
+{
+	if (value_str[0] == 0 || value_str[1] != 0)
+	{
+		jack_error("invalid char option value \"%s\"", value_str);
+		return;
+	}
+
+	*value_ptr = *value_str;
+}
+
+void
+jack_controller_settings_set_string_option(
+	const char *value_str,
+	char *value_ptr,
+	size_t max_size)
+{
+	size_t size;
+
+	size = strlen(value_str);
+
+	if (size >= max_size)
+	{
+		jack_error("string option value \"%s\" is too long, max is %u chars (including terminating zero)", value_str, (unsigned int)max_size);
+		return;
+	}
+
+	strcpy(value_ptr, value_str);
+}
+
+void
+jack_controller_settings_set_driver_option(
+	jackctl_driver driver,
+	const char *option_name,
+	const char *option_value)
+{
+	jackctl_parameter parameter;
+	jackctl_param_type_t type;
+	int value_int;
+	unsigned int value_uint;
+	union jackctl_parameter_value value;
+
+	jack_info("setting driver option \"%s\" to value \"%s\"", option_name, option_value);
+
+	parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), option_name);
+	if (parameter == NULL)
+	{
+		jack_error(
+			"Unknown parameter \"%s\" of driver \"%s\"",
+			option_name,
+			jackctl_driver_get_name(driver));
+		return;
+	}
+
+	type = jackctl_parameter_get_type(parameter);
+
+	switch (type)
+	{
+	case JackParamInt:
+		jack_controller_settings_set_sint_option(option_value, &value_int);
+		value.i = value_int;
+		break;
+	case JackParamUInt:
+		jack_controller_settings_set_uint_option(option_value, &value_uint);
+		value.ui = value_uint;
+		break;
+	case JackParamChar:
+		jack_controller_settings_set_char_option(option_value, &value.c);
+		break;
+	case JackParamString:
+		jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str));
+		break;
+	case JackParamBool:
+		jack_controller_settings_set_bool_option(option_value, &value_int);
+		value.i = value_int;
+		break;
+	default:
+		jack_error("Parameter \"%s\" of driver \"%s\" is of unknown type %d",
+			   jackctl_parameter_get_name(parameter),
+			   jackctl_driver_get_name(driver),
+			   type);
+	}
+
+	jackctl_parameter_set_value(parameter, &value);
+}
+
+void
+jack_controller_settings_set_engine_option(
+	struct jack_controller *controller_ptr,
+	const char *option_name,
+	const char *option_value)
+{
+	jackctl_parameter parameter;
+	jackctl_param_type_t type;
+	int value_int;
+	unsigned int value_uint;
+	union jackctl_parameter_value value;
+
+	jack_info("setting engine option \"%s\" to value \"%s\"", option_name, option_value);
+
+	if (strcmp(option_name, "driver") == 0)
+	{
+		if (!jack_controller_select_driver(controller_ptr, option_value))
+		{
+			jack_error("unknown driver '%s'", option_value);
+		}
+
+		return;
+	}
+
+	parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), option_name);
+	if (parameter == NULL)
+	{
+		jack_error(
+			"Unknown engine parameter \"%s\"",
+			option_name);
+		return;
+	}
+
+	type = jackctl_parameter_get_type(parameter);
+
+	switch (type)
+	{
+	case JackParamInt:
+		jack_controller_settings_set_sint_option(option_value, &value_int);
+		value.i = value_int;
+		break;
+	case JackParamUInt:
+		jack_controller_settings_set_uint_option(option_value, &value_uint);
+		value.ui = value_uint;
+		break;
+	case JackParamChar:
+		jack_controller_settings_set_char_option(option_value, &value.c);
+		break;
+	case JackParamString:
+		jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str));
+		break;
+	case JackParamBool:
+		jack_controller_settings_set_bool_option(option_value, &value_int);
+		value.i = value_int;
+		break;
+	default:
+		jack_error("Engine parameter \"%s\" is of unknown type %d",
+			   jackctl_parameter_get_name(parameter),
+			   type);
+	}
+
+	jackctl_parameter_set_value(parameter, &value);
+}
+
+static
+bool
+jack_controller_settings_save_options(
+	void *context,
+	const JSList * parameters_list,
+	void *dbus_call_context_ptr)
+{
+	jackctl_parameter parameter;
+	jackctl_param_type_t type;
+	union jackctl_parameter_value value;
+	const char * name;
+	char value_str[50];
+
+	while (parameters_list != NULL)
+	{
+		parameter = (jackctl_parameter)parameters_list->data;
+
+		if (jackctl_parameter_is_set(parameter))
+		{
+			type = jackctl_parameter_get_type(parameter);
+			value = jackctl_parameter_get_value(parameter);
+			name = jackctl_parameter_get_name(parameter);
+		
+			switch (type)
+			{
+			case JackParamInt:
+				sprintf(value_str, "%d", (int)value.i);
+				if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr))
+				{
+					return false;
+				}
+				break;
+			case JackParamUInt:
+				sprintf(value_str, "%u", (unsigned int)value.ui);
+				if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr))
+				{
+					return false;
+				}
+				break;
+			case JackParamChar:
+				sprintf(value_str, "%c", (char)value.c);
+				if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr))
+				{
+					return false;
+				}
+				break;
+			case JackParamString:
+				if (!jack_controller_settings_write_option(context, name, value.str, dbus_call_context_ptr))
+				{
+					return false;
+				}
+				break;
+			case JackParamBool:
+				if (!jack_controller_settings_write_option(context, name, value.b ? "true" : "false", dbus_call_context_ptr))
+				{
+					return false;
+				}
+				break;
+			default:
+				jack_error("parameter of unknown type %d", type);
+			}
+		}
+
+		parameters_list = jack_slist_next(parameters_list);
+	}
+
+	return true;
+}
+
+bool
+jack_controller_settings_save_engine_options(
+	void *context,
+	struct jack_controller *controller_ptr,
+	void *dbus_call_context_ptr)
+{
+	if (controller_ptr->driver != NULL)
+	{
+		if (!jack_controller_settings_write_option(
+			    context,
+			    "driver",
+			    jackctl_driver_get_name(controller_ptr->driver),
+			    dbus_call_context_ptr))
+		{
+			return false;
+		}
+	}
+
+	return jack_controller_settings_save_options(context, jackctl_server_get_parameters(controller_ptr->server), dbus_call_context_ptr);
+}
+
+bool
+jack_controller_settings_save_driver_options(
+	void *context,
+	jackctl_driver driver,
+	void *dbus_call_context_ptr)
+{
+	return jack_controller_settings_save_options(context, jackctl_driver_get_parameters(driver), dbus_call_context_ptr);
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_xml.h jack1/jackd/jackcontroller_xml.h
--- jack1.old/jackd/jackcontroller_xml.h	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_xml.h	2013-10-06 17:44:19.778394559 +0100
@@ -0,0 +1,36 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef JACKCONTROLLER_XML_H__4F102BD2_3354_41C9_B842_DC00E1557A0F__INCLUDED
+#define JACKCONTROLLER_XML_H__4F102BD2_3354_41C9_B842_DC00E1557A0F__INCLUDED
+
+bool
+jack_controller_settings_save(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr);
+
+void
+jack_controller_settings_load(
+	struct jack_controller * controller_ptr);
+
+void
+jack_controller_settings_save_auto(
+	struct jack_controller * controller_ptr);
+
+#endif /* #ifndef JACKCONTROLLER_XML_H__4F102BD2_3354_41C9_B842_DC00E1557A0F__INCLUDED */
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_xml_expat.c jack1/jackd/jackcontroller_xml_expat.c
--- jack1.old/jackd/jackcontroller_xml_expat.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_xml_expat.c	2013-10-06 17:44:27.120302772 +0100
@@ -0,0 +1,318 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <expat.h>
+#include <dbus/dbus.h>
+
+#include <include/driver.h>
+#include <include/engine.h>
+#include "jackcontroller_internal.h"
+#include "jackdbus.h"
+
+bool
+jack_controller_settings_init()
+{
+	return true;
+}
+
+void
+jack_controller_settings_uninit()
+{
+}
+
+#define PARSE_CONTEXT_ROOT     0
+#define PARSE_CONTEXT_JACK     1
+#define PARSE_CONTEXT_ENGINE   1
+#define PARSE_CONTEXT_DRIVERS  2
+#define PARSE_CONTEXT_DRIVER   3
+#define PARSE_CONTEXT_OPTION   4
+
+#define MAX_STACK_DEPTH       10
+
+struct parse_context
+{
+	struct jack_controller *controller_ptr;
+	XML_Bool error;
+	unsigned int element[MAX_STACK_DEPTH];
+	signed int depth;
+	jackctl_driver driver;
+	char option[JACK_DRIVER_PARAM_STRING_MAX+1];
+	int option_used;
+	char *name;
+};
+
+#define context_ptr ((struct parse_context *)data)
+
+void
+jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len)
+{
+	if (context_ptr->error)
+	{
+		return;
+	}
+
+	if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
+	{
+		if (context_ptr->option_used + len >= JACK_DRIVER_PARAM_STRING_MAX)
+		{
+			jack_error("xml parse max char data length reached");
+			context_ptr->error = XML_TRUE;
+			return;
+		}
+
+		memcpy(context_ptr->option + context_ptr->option_used, s, len);
+		context_ptr->option_used += len;
+	}
+}
+
+void
+jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
+{
+	jackctl_driver driver;
+
+	if (context_ptr->error)
+	{
+		return;
+	}
+
+	if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
+	{
+		jack_error("xml parse max stack depth reached");
+		context_ptr->error = XML_TRUE;
+		return;
+	}
+
+	if (strcmp(el, "jack") == 0)
+	{
+		//jack_info("<jack>");
+		context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
+		return;
+	}
+
+	if (strcmp(el, "engine") == 0)
+	{
+		//jack_info("<engine>");
+		context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
+		return;
+	}
+
+	if (strcmp(el, "drivers") == 0)
+	{
+		//jack_info("<drivers>");
+		context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
+		return;
+	}
+
+	if (strcmp(el, "driver") == 0)
+	{
+		if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
+		{
+			jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
+			context_ptr->error = XML_TRUE;
+			return;
+		}
+
+		//jack_info("<driver>");
+		context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;
+
+		driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
+		if (driver == NULL)
+		{
+			jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
+		}
+		else
+		{
+			jack_info("setting for driver \"%s\" found", attr[1]);
+		}
+
+		context_ptr->driver = driver;
+
+		return;
+	}
+
+	if (strcmp(el, "option") == 0)
+	{
+		//jack_info("<option>");
+		if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
+		{
+			jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
+			context_ptr->error = XML_TRUE;
+			return;
+		}
+
+		context_ptr->name = strdup(attr[1]);
+		if (context_ptr->name == NULL)
+		{
+			jack_error("strdup() failed");
+			context_ptr->error = XML_TRUE;
+			return;
+		}
+
+		context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
+		context_ptr->option_used = 0;
+		return;
+	}
+
+	jack_error("unknown element \"%s\"", el);
+	context_ptr->error = XML_TRUE;
+}
+
+void
+jack_controller_settings_callback_elend(void *data, const char *el)
+{
+	if (context_ptr->error)
+	{
+		return;
+	}
+
+	//jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
+
+	if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
+	{
+		context_ptr->option[context_ptr->option_used] = 0;
+
+		if (context_ptr->depth == 2 &&
+		    context_ptr->element[0] == PARSE_CONTEXT_JACK &&
+		    context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
+		{
+			jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
+		}
+
+		if (context_ptr->depth == 3 &&
+		    context_ptr->element[0] == PARSE_CONTEXT_JACK &&
+		    context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
+		    context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
+		    context_ptr->driver != NULL)
+		{
+			jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
+		}
+	}
+
+	context_ptr->depth--;
+
+	if (context_ptr->name != NULL)
+	{
+		free(context_ptr->name);
+		context_ptr->name = NULL;
+	}
+}
+
+#undef context_ptr
+
+void
+jack_controller_settings_load(
+	struct jack_controller * controller_ptr)
+{
+	XML_Parser parser;
+	int bytes_read;
+	void *buffer;
+	char *filename;
+	size_t conf_len;
+	struct stat st;
+	int fd;
+	enum XML_Status xmls;
+	struct parse_context context;
+
+	conf_len = strlen(JACKDBUS_CONF);
+
+	filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
+	if (filename == NULL)
+	{
+		jack_error("Out of memory.");
+		goto exit;
+	}
+
+	memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
+	memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
+	filename[g_jackdbus_config_dir_len + conf_len] = 0;
+
+	jack_info("Loading settings from \"%s\" using %s ...", filename, XML_ExpatVersion());
+
+	if (stat(filename, &st) != 0)
+	{
+		jack_error("failed to stat \"%s\", error is %d (%s)", filename, errno, strerror(errno));
+	}
+
+	fd = open(filename, O_RDONLY);
+	if (fd == -1)
+	{
+		jack_error("open() failed to open conf filename.");
+		goto exit_free_filename;
+	}
+
+	parser = XML_ParserCreate(NULL);
+	if (parser == NULL)
+	{
+		jack_error("XML_ParserCreate() failed to create parser object.");
+		goto exit_close_file;
+	}
+
+	//jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
+
+	/* we are expecting that conf file has small enough size to fit in memory */
+
+	buffer = XML_GetBuffer(parser, st.st_size);
+	if (buffer == NULL)
+	{
+		jack_error("XML_GetBuffer() failed.");
+		goto exit_free_parser;
+	}
+
+	bytes_read = read(fd, buffer, st.st_size);
+	if (bytes_read != st.st_size)
+	{
+		jack_error("read() returned unexpected result.");
+		goto exit_free_parser;
+	}
+
+	context.controller_ptr = controller_ptr;
+	context.error = XML_FALSE;
+	context.depth = -1;
+	context.name = NULL;
+
+	XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
+	XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
+	XML_SetUserData(parser, &context);
+
+	xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
+	if (xmls == XML_STATUS_ERROR)
+	{
+		jack_error("XML_ParseBuffer() failed.");
+		goto exit_free_parser;
+	}
+
+exit_free_parser:
+	XML_ParserFree(parser);
+
+exit_close_file:
+	close(fd);
+
+exit_free_filename:
+	free(filename);
+
+exit:
+	return;
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_xml_libxml.c jack1/jackd/jackcontroller_xml_libxml.c
--- jack1.old/jackd/jackcontroller_xml_libxml.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_xml_libxml.c	2013-10-06 17:44:19.780394534 +0100
@@ -0,0 +1,572 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdbool.h>
+#include <string.h>
+#include <dbus/dbus.h>
+
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#include <jack/driver.h>
+#include <jack/engine.h>
+#include "jackcontroller_internal.h"
+#include "jackdbus.h"
+
+/* XPath expression used for engine options selection */
+#define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
+
+/* XPath expression used for drivers selection */
+#define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
+
+/* XPath expression used for driver options selection */
+#define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
+
+bool
+jack_controller_settings_init()
+{
+	/*
+	 * this initialize the library and check potential ABI mismatches
+	 * between the version it was compiled for and the actual shared
+	 * library used.
+	 */
+	LIBXML_TEST_VERSION;
+
+	return true;
+}
+
+void
+jack_controller_settings_uninit()
+{
+}
+
+#define writer ((xmlTextWriterPtr)context)
+
+bool
+jack_controller_settings_write_option(
+	void *context,
+	const char *name,
+	const char *content,
+	void *dbus_call_context_ptr)
+{
+	if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
+		return false;
+	}
+
+	if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
+		return false;
+	}
+
+	if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
+		return false;
+	}
+
+	if (xmlTextWriterEndElement(writer) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
+		return false;
+	}
+
+	return true;
+}
+
+#undef writer
+
+bool
+jack_controller_settings_write_engine(
+	struct jack_controller * controller_ptr,
+	xmlTextWriterPtr writer,
+	void *dbus_call_context_ptr)
+{
+/* 	jack_info("engine settings begin"); */
+
+/* 	if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
+/* 	{ */
+/* 		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
+/* 		return false; */
+/* 	} */
+
+	if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
+		return false;
+	}
+
+	if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (xmlTextWriterEndElement(writer) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
+		return false;
+	}
+
+/* 	jack_info("engine settings end"); */
+	return true;
+}
+
+bool
+jack_controller_settings_write_driver(
+	struct jack_controller * controller_ptr,
+	xmlTextWriterPtr writer,
+	jackctl_driver driver,
+	void *dbus_call_context_ptr)
+{
+/* 	if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
+/* 	{ */
+/* 		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
+/* 		return false; */
+/* 	} */
+
+	if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
+		return false;
+	}
+
+	if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
+		return false;
+	}
+
+	if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (xmlTextWriterEndElement(writer) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
+		return false;
+	}
+
+	return true;
+}
+
+bool
+jack_controller_settings_write_drivers(
+	struct jack_controller * controller_ptr,
+	xmlTextWriterPtr writer,
+	void *dbus_call_context_ptr)
+{
+	const JSList * node_ptr;
+	jackctl_driver driver;
+
+	if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
+		return false;
+	}
+
+	node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
+
+	while (node_ptr != NULL)
+	{
+		driver = (jackctl_driver)node_ptr->data;
+
+		if (!jack_controller_settings_write_driver(
+			    controller_ptr,
+			    writer,
+			    driver,
+			    dbus_call_context_ptr))
+		{
+			return false;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+	}
+
+	if (xmlTextWriterEndElement(writer) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
+		return false;
+	}
+
+	return true;
+}
+
+bool
+jack_controller_settings_save(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr)
+{
+	xmlTextWriterPtr writer;
+	char *filename;
+	size_t conf_len;
+	bool ret;
+	time_t timestamp;
+	char timestamp_str[28];
+
+	time(&timestamp);
+	timestamp_str[0] = ' ';
+	ctime_r(&timestamp, timestamp_str + 1);
+	timestamp_str[25] = ' ';
+
+	ret = false;
+
+	conf_len = strlen(JACKDBUS_CONF);
+
+	filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
+	if (filename == NULL)
+	{
+		jack_error("Out of memory.");
+		goto fail;
+	}
+
+	memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
+	memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
+	filename[g_jackdbus_config_dir_len + conf_len] = 0;
+
+	jack_info("saving settings to \"%s\"", filename);
+
+	writer = xmlNewTextWriterFilename(filename, 0);
+	if (writer == NULL)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
+		goto fail_free_filename;
+	}
+
+	if (xmlTextWriterSetIndent(writer, 1) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
+		goto fail_free_writter;
+	}
+
+	if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
+		goto fail_free_writter;
+	}
+
+	if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
+		goto fail_free_writter;
+	}
+
+	if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
+		goto fail_free_writter;
+	}
+
+	if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
+		goto fail_free_writter;
+	}
+
+	if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
+	{
+		goto fail_free_writter;
+	}
+
+	if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
+	{
+		goto fail_free_writter;
+	}
+
+	if (xmlTextWriterEndElement(writer) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
+		goto fail_free_writter;
+	}
+
+	if (xmlTextWriterEndDocument(writer) == -1)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
+		goto fail_free_writter;
+	}
+
+	ret = true;
+
+fail_free_writter:
+	xmlFreeTextWriter(writer);
+
+fail_free_filename:
+	free(filename);
+
+fail:
+	return ret;
+}
+
+void
+jack_controller_settings_read_engine(
+	struct jack_controller * controller_ptr,
+	xmlXPathContextPtr xpath_ctx_ptr)
+{
+	xmlXPathObjectPtr xpath_obj_ptr;
+	xmlBufferPtr content_buffer_ptr;
+	int i;
+	const char *option_name;
+	const char *option_value;
+
+	/* Evaluate xpath expression */
+	xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
+	if (xpath_obj_ptr == NULL)
+	{
+		jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
+		goto exit;
+	}
+
+	if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
+	{
+		jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
+		goto free_xpath_obj;
+	}
+
+	content_buffer_ptr = xmlBufferCreate();
+	if (content_buffer_ptr == NULL)
+	{
+		jack_error("xmlBufferCreate() failed.");
+		goto free_xpath_obj;
+	}
+
+	for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
+	{
+		//jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
+
+		if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
+		{
+			jack_error("xmlNodeBufGetContent() failed.");
+			goto next_option;
+		}
+
+		option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
+		option_value = (const char *)xmlBufferContent(content_buffer_ptr);
+
+		jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);
+
+	next_option:
+		xmlBufferEmpty(content_buffer_ptr);
+	}
+
+//free_buffer:
+	xmlBufferFree(content_buffer_ptr);
+
+free_xpath_obj:
+	xmlXPathFreeObject(xpath_obj_ptr);
+
+exit:
+	return;
+}
+
+void
+jack_controller_settings_read_driver(
+	struct jack_controller * controller_ptr,
+	xmlXPathContextPtr xpath_ctx_ptr,
+	jackctl_driver driver)
+{
+	char *xpath;
+	size_t xpath_len;
+	xmlXPathObjectPtr xpath_obj_ptr;
+	xmlBufferPtr content_buffer_ptr;
+	int i;
+	const char *option_name;
+	const char *option_value;
+	const char *driver_name;
+
+	driver_name = jackctl_driver_get_name(driver);
+
+	jack_info("reading options for driver \"%s\"", driver_name);
+
+	xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
+
+	xpath = malloc(xpath_len);
+	if (xpath == NULL)
+	{
+		jack_error("Out of memory.");
+		goto exit;
+	}
+
+	snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
+
+	//jack_info("xpath = \"%s\"", xpath);
+
+	/* Evaluate xpath expression */
+	xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
+	if (xpath_obj_ptr == NULL)
+	{
+		jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
+		goto free_xpath;
+	}
+
+	if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
+	{
+		//jack_info("XPath \"%s\" evaluation returned no data", xpath);
+		goto free_xpath_obj;
+	}
+
+	content_buffer_ptr = xmlBufferCreate();
+	if (content_buffer_ptr == NULL)
+	{
+		jack_error("xmlBufferCreate() failed.");
+		goto free_xpath_obj;
+	}
+
+	for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
+	{
+		//jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
+
+		if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
+		{
+			jack_error("xmlNodeBufGetContent() failed.");
+			goto next_option;
+		}
+
+		option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
+		option_value = (const char *)xmlBufferContent(content_buffer_ptr);
+
+		jack_controller_settings_set_driver_option(driver, option_name, option_value);
+
+	next_option:
+		xmlBufferEmpty(content_buffer_ptr);
+	}
+
+//free_buffer:
+	xmlBufferFree(content_buffer_ptr);
+
+free_xpath_obj:
+	xmlXPathFreeObject(xpath_obj_ptr);
+
+free_xpath:
+	free(xpath);
+
+exit:
+	return;
+}
+
+void
+jack_controller_settings_read_drivers(
+	struct jack_controller * controller_ptr,
+	xmlXPathContextPtr xpath_ctx_ptr)
+{
+	xmlXPathObjectPtr xpath_obj_ptr;
+	int i;
+	const char *driver_name;
+	jackctl_driver driver;
+
+	/* Evaluate xpath expression */
+	xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
+	if (xpath_obj_ptr == NULL)
+	{
+		jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
+		goto exit;
+	}
+
+	if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
+	{
+		jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
+		goto free_xpath_obj;
+	}
+
+	for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
+	{
+		driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
+
+		driver = jack_controller_find_driver(controller_ptr->server, driver_name);
+		if (driver == NULL)
+		{
+			jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
+		}
+		else
+		{
+			jack_info("setting for driver \"%s\" found", driver_name);
+
+			jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
+		}
+	}
+
+free_xpath_obj:
+	xmlXPathFreeObject(xpath_obj_ptr);
+
+exit:
+	return;
+}
+
+void
+jack_controller_settings_load(
+	struct jack_controller * controller_ptr)
+{
+	char *filename;
+	size_t conf_len;
+	xmlDocPtr doc_ptr;
+	xmlXPathContextPtr xpath_ctx_ptr;
+
+	conf_len = strlen(JACKDBUS_CONF);
+
+	filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
+	if (filename == NULL)
+	{
+		jack_error("Out of memory.");
+		goto exit;
+	}
+
+	memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
+	memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
+	filename[g_jackdbus_config_dir_len + conf_len] = 0;
+
+	jack_info("loading settings from \"%s\"", filename);
+
+	doc_ptr = xmlParseFile(filename);
+	if (doc_ptr == NULL)
+	{
+		jack_error("Failed to parse \"%s\"", filename);
+		goto free_filename;
+	}
+
+	/* Create xpath evaluation context */
+	xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
+	if (xpath_ctx_ptr == NULL)
+	{
+		jack_error("Unable to create new XPath context");
+		goto free_doc;
+	}
+
+	jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
+	jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
+
+	xmlXPathFreeContext(xpath_ctx_ptr);
+
+free_doc:
+	xmlFreeDoc(doc_ptr);
+
+free_filename:
+	free(filename);
+
+exit:
+	return;
+}
+
+void
+jack_controller_settings_save_auto(
+	struct jack_controller * controller_ptr)
+{
+	jack_controller_settings_save(controller_ptr, NULL);
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_xml_nop.c jack1/jackd/jackcontroller_xml_nop.c
--- jack1.old/jackd/jackcontroller_xml_nop.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_xml_nop.c	2013-10-06 17:44:19.780394534 +0100
@@ -0,0 +1,58 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdbool.h>
+#include <dbus/dbus.h>
+
+#include <jack/driver.h>
+#include <jack/engine.h>
+#include "jackdbus.h"
+#include "jackcontroller_internal.h"
+
+bool
+jack_controller_settings_init()
+{
+	return true;
+}
+
+void
+jack_controller_settings_uninit()
+{
+}
+
+bool
+jack_controller_settings_save(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr)
+{
+	jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "jackdbus compiled without settings persistence");
+	return true;
+}
+
+void
+jack_controller_settings_load(
+	struct jack_controller * controller_ptr)
+{
+}
+
+void
+jack_controller_settings_save_auto(
+	struct jack_controller * controller_ptr)
+{
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackcontroller_xml_write_raw.c jack1/jackd/jackcontroller_xml_write_raw.c
--- jack1.old/jackd/jackcontroller_xml_write_raw.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackcontroller_xml_write_raw.c	2013-10-06 17:44:27.121302760 +0100
@@ -0,0 +1,270 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <dbus/dbus.h>
+
+#include <include/driver.h>
+#include <include/engine.h>
+#include "jackcontroller_internal.h"
+#include "jackdbus.h"
+
+bool
+jack_controller_settings_write_string(int fd, const char * string, void *dbus_call_context_ptr)
+{
+	size_t len;
+
+	len = strlen(string);
+
+	if (write(fd, string, len) != len)
+	{
+		jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "write() failed to write config file.");
+		return false;
+	}
+
+	return true;
+}
+
+struct save_context
+{
+	int fd;
+	const char *indent;
+};
+
+#define save_context_ptr ((struct save_context *)context)
+#define fd (save_context_ptr->fd)
+
+bool
+jack_controller_settings_write_option(
+	void *context,
+	const char *name,
+	const char *content,
+	void *dbus_call_context_ptr)
+{
+	if (!jack_controller_settings_write_string(fd, save_context_ptr->indent, dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "<option name=\"", dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (!jack_controller_settings_write_string(fd, name, dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "\">", dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (!jack_controller_settings_write_string(fd, content, dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "</option>\n", dbus_call_context_ptr))
+	{
+		return false;
+	}
+
+	return true;
+}
+
+#undef fd
+
+bool
+jack_controller_settings_save(
+	struct jack_controller * controller_ptr,
+	void *dbus_call_context_ptr)
+{
+	char *filename;
+	size_t conf_len;
+	int fd;
+	bool ret;
+	time_t timestamp;
+	char timestamp_str[26];
+	struct save_context context;
+	const JSList * node_ptr;
+	jackctl_driver driver;
+
+	time(&timestamp);
+	ctime_r(&timestamp, timestamp_str);
+	timestamp_str[24] = 0;
+
+	ret = false;
+
+	conf_len = strlen(JACKDBUS_CONF);
+
+	filename = malloc(g_jackdbus_config_dir_len + conf_len + 1);
+	if (filename == NULL)
+	{
+		jack_error("Out of memory.");
+		goto exit;
+	}
+
+	memcpy(filename, g_jackdbus_config_dir, g_jackdbus_config_dir_len);
+	memcpy(filename + g_jackdbus_config_dir_len, JACKDBUS_CONF, conf_len);
+	filename[g_jackdbus_config_dir_len + conf_len] = 0;
+
+	jack_info("Saving settings to \"%s\" ...", filename);
+
+	fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if (fd == -1)
+	{
+		jack_error("open() failed to open conf filename.");
+		goto exit_free_filename;
+	}
+
+	context.fd = fd;
+
+	if (!jack_controller_settings_write_string(fd, "<?xml version=\"1.0\"?>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "<!--\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, JACK_CONF_HEADER_TEXT, dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "-->\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "<!-- ", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, timestamp_str, dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, " -->\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "<jack>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, " <engine>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	context.indent = "  ";
+	if (!jack_controller_settings_save_engine_options(&context, controller_ptr, dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, " </engine>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, " <drivers>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
+
+	while (node_ptr != NULL)
+	{
+		driver = (jackctl_driver)node_ptr->data;
+
+		if (!jack_controller_settings_write_string(fd, "  <driver name=\"", dbus_call_context_ptr))
+		{
+			goto exit_close;
+		}
+
+		if (!jack_controller_settings_write_string(fd, jackctl_driver_get_name(driver), dbus_call_context_ptr))
+		{
+			goto exit_close;
+		}
+
+		if (!jack_controller_settings_write_string(fd, "\">\n", dbus_call_context_ptr))
+		{
+			goto exit_close;
+		}
+
+		context.indent = "   ";
+
+		if (!jack_controller_settings_save_driver_options(&context, driver, dbus_call_context_ptr))
+		{
+			goto exit_close;
+		}
+
+		if (!jack_controller_settings_write_string(fd, "  </driver>\n", dbus_call_context_ptr))
+		{
+			goto exit_close;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+	}
+
+	if (!jack_controller_settings_write_string(fd, " </drivers>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	if (!jack_controller_settings_write_string(fd, "</jack>\n", dbus_call_context_ptr))
+	{
+		goto exit_close;
+	}
+
+	ret = true;
+
+exit_close:
+	close(fd);
+
+exit_free_filename:
+	free(filename);
+
+exit:
+	return ret;
+}
+
+void
+jack_controller_settings_save_auto(
+	struct jack_controller * controller_ptr)
+{
+	jack_controller_settings_save(controller_ptr, NULL);
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackctl.c jack1/jackd/jackctl.c
--- jack1.old/jackd/jackctl.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackctl.c	2013-10-06 17:44:27.122302747 +0100
@@ -0,0 +1,2069 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    JACK control API implementation
+
+    Copyright (C) 2008,2010 Nedko Arnaudov
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <config.h>
+#include <include/internal.h>
+#include <include/engine.h>
+#include <include/driver.h>
+
+#include "../libjack/local.h"
+
+#include "jackctl.h"
+
+struct jackctl_server
+{
+	char * name;
+	JSList * drivers;
+	JSList * parameters;
+
+	jack_engine_t * engine;
+
+	unsigned int xruns;
+
+	/* bool, whether to be "realtime" */
+	union jackctl_parameter_value realtime;
+	union jackctl_parameter_value default_realtime;
+
+	/* int32_t */
+	union jackctl_parameter_value realtime_priority;
+	union jackctl_parameter_value default_realtime_priority;
+
+	/* bool, if true - do not attempt to lock memory, even in realtime mode. */
+	union jackctl_parameter_value no_mem_lock;
+	union jackctl_parameter_value default_no_mem_lock;
+
+	/* bool, whether to exit once all clients have closed their connections */
+	union jackctl_parameter_value temporary;
+	union jackctl_parameter_value default_temporary;
+
+	/* bool, whether to be verbose */
+	union jackctl_parameter_value verbose;
+	union jackctl_parameter_value default_verbose;
+
+	/* int32_t, msecs; if zero, use period size. */
+	union jackctl_parameter_value client_timeout;
+	union jackctl_parameter_value default_client_timeout;
+
+	/* uint32_t, maximum number of ports the JACK server can manage */
+	union jackctl_parameter_value port_max;
+	union jackctl_parameter_value default_port_max;
+
+	/* bool, whether to unlock libraries GTK+, QT, FLTK, Wine */
+	union jackctl_parameter_value do_unlock;
+	union jackctl_parameter_value default_do_unlock;
+
+	/* int32_t */
+	union jackctl_parameter_value frame_time_offset;
+	union jackctl_parameter_value default_frame_time_offset;
+
+	/* bool, whether to prevent from ever kicking out clients because they were too slow */
+	union jackctl_parameter_value nozombies;
+	union jackctl_parameter_value default_nozombies;
+
+	/* char, clock source */
+	union jackctl_parameter_value clock_source;
+	union jackctl_parameter_value default_clock_source;
+
+	/* bool, whether to remove the shared memory registry used by all JACK server instances before startup */
+	union jackctl_parameter_value replace_registry;
+	union jackctl_parameter_value default_replace_registry;
+
+	/* int32_t */
+	union jackctl_parameter_value midi_buffer_size;
+	union jackctl_parameter_value default_midi_buffer_size;
+
+	/* uint32_t */
+	union jackctl_parameter_value timothres;
+	union jackctl_parameter_value default_timothres;
+
+	uint64_t next_client_id;
+	uint64_t next_port_id;
+	uint64_t next_connection_id;
+	void * patchbay_context;
+	jackctl_client_appeared_callback client_appeared_callback;
+	jackctl_client_disappeared_callback client_disappeared_callback;
+	jackctl_port_appeared_callback port_appeared_callback;
+	jackctl_port_disappeared_callback port_disappeared_callback;
+	jackctl_ports_connected_callback ports_connected_callback;
+	jackctl_ports_disconnected_callback ports_disconnected_callback;
+
+	JSList * clients;
+	JSList * connections;
+};
+
+struct jackctl_driver
+{
+	char * filename;
+	jack_driver_desc_t * desc_ptr;
+	JSList * parameters;
+	JSList * set_parameters;
+};
+
+struct jackctl_parameter
+{
+	const char * name;
+	const char * short_description;
+	const char * long_description;
+	jackctl_param_type_t type;
+	bool is_set;
+	union jackctl_parameter_value * value_ptr;
+	union jackctl_parameter_value * default_value_ptr;
+
+	union jackctl_parameter_value value;
+	union jackctl_parameter_value default_value;
+	struct jackctl_driver * driver_ptr;
+	char id;
+	jack_driver_param_t * driver_parameter_ptr;
+};
+
+struct jackctl_client
+{
+	uint64_t id;
+	char * name;
+	pid_t pid;
+	JSList * ports;
+	void * patchbay_context;
+};
+
+struct jackctl_port
+{
+	uint64_t id;
+	char * name;
+	uint32_t flags;
+	uint32_t type;
+	struct jackctl_client * client_ptr;
+	void * patchbay_context;
+};
+
+struct jackctl_connection
+{
+	uint64_t id;
+	struct jackctl_port * port1_ptr;
+	struct jackctl_port * port2_ptr;
+	void * patchbay_context;
+};
+
+static
+struct jackctl_parameter *
+jackctl_add_parameter(
+	JSList ** parameters_list_ptr_ptr,
+	const char * name,
+	const char * short_description,
+	const char * long_description,
+	jackctl_param_type_t type,
+	union jackctl_parameter_value * value_ptr,
+	union jackctl_parameter_value * default_value_ptr,
+	union jackctl_parameter_value value)
+{
+	struct jackctl_parameter * parameter_ptr;
+
+	parameter_ptr = malloc(sizeof(struct jackctl_parameter));
+	if (parameter_ptr == NULL)
+	{
+		jack_error("Cannot allocate memory for jackctl_parameter structure.");
+		goto fail;
+	}
+
+	parameter_ptr->name = name;
+	parameter_ptr->short_description = short_description;
+	parameter_ptr->long_description = long_description;
+	parameter_ptr->type = type;
+	parameter_ptr->is_set = false;
+
+	if (value_ptr == NULL)
+	{
+		value_ptr = &parameter_ptr->value;
+	}
+
+	if (default_value_ptr == NULL)
+	{
+		default_value_ptr = &parameter_ptr->default_value;
+	}
+
+	parameter_ptr->value_ptr = value_ptr;
+	parameter_ptr->default_value_ptr = default_value_ptr;
+
+	*value_ptr = *default_value_ptr = value;
+
+	parameter_ptr->driver_ptr = NULL;
+	parameter_ptr->driver_parameter_ptr = NULL;
+	parameter_ptr->id = 0;
+
+	*parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
+
+	return parameter_ptr;
+
+fail:
+	return NULL;
+}
+
+static
+void
+jackctl_free_driver_parameters(
+	struct jackctl_driver * driver_ptr)
+{
+	JSList * next_node_ptr;
+
+	while (driver_ptr->parameters)
+	{
+		next_node_ptr = driver_ptr->parameters->next;
+		free(driver_ptr->parameters->data);
+		free(driver_ptr->parameters);
+		driver_ptr->parameters = next_node_ptr;
+	}
+
+	while (driver_ptr->set_parameters)
+	{
+		next_node_ptr = driver_ptr->set_parameters->next;
+		free(driver_ptr->set_parameters->data);
+		free(driver_ptr->set_parameters);
+		driver_ptr->set_parameters = next_node_ptr;
+	}
+}
+
+static
+bool
+jackctl_add_driver_parameters(
+	struct jackctl_driver * driver_ptr)
+{
+	uint32_t i;
+	union jackctl_parameter_value jackctl_value;
+	jackctl_param_type_t jackctl_type;
+	struct jackctl_parameter * parameter_ptr;
+	jack_driver_param_desc_t * descriptor_ptr;
+
+	for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
+	{
+		descriptor_ptr = driver_ptr->desc_ptr->params + i;
+
+		switch (descriptor_ptr->type)
+		{
+		case JackDriverParamInt:
+			jackctl_type = JackParamInt;
+			jackctl_value.i = descriptor_ptr->value.i;
+			break;
+		case JackDriverParamUInt:
+			jackctl_type = JackParamUInt;
+			jackctl_value.ui = descriptor_ptr->value.ui;
+			break;
+		case JackDriverParamChar:
+			jackctl_type = JackParamChar;
+			jackctl_value.c = descriptor_ptr->value.c;
+			break;
+		case JackDriverParamString:
+			jackctl_type = JackParamString;
+			strcpy(jackctl_value.str, descriptor_ptr->value.str);
+			break;
+		case JackDriverParamBool:
+			jackctl_type = JackParamBool;
+			jackctl_value.b = descriptor_ptr->value.i;
+			break;
+		default:
+			jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type);
+			assert(0);
+			goto fail;
+		}
+
+		parameter_ptr = jackctl_add_parameter(
+			&driver_ptr->parameters,
+			descriptor_ptr->name,
+			descriptor_ptr->short_desc,
+			descriptor_ptr->long_desc,
+			jackctl_type,
+			NULL,
+			NULL,
+			jackctl_value);
+
+		if (parameter_ptr == NULL)
+		{
+			goto fail;
+		}
+
+		parameter_ptr->driver_ptr = driver_ptr;
+		parameter_ptr->id = descriptor_ptr->character;
+	}
+
+	return true;
+
+fail:
+	jackctl_free_driver_parameters(driver_ptr);
+
+	return false;
+}
+
+static
+bool
+jackctl_load_driver_descriptor(
+	struct jackctl_server * server_ptr,
+	struct jackctl_driver * driver_ptr)
+{
+	jack_driver_desc_t * descriptor;
+	JackDriverDescFunction so_get_descriptor;
+	void * dlhandle;
+	const char * dlerr;
+	int err;
+
+	if (server_ptr->verbose.b) {
+		jack_info ("getting driver descriptor from %s", driver_ptr->filename);
+	}
+
+	dlhandle = dlopen(driver_ptr->filename, RTLD_NOW|RTLD_GLOBAL);
+	if (dlhandle == NULL) {
+		jack_error("could not open driver .so '%s': %s", driver_ptr->filename, dlerror());
+		return false;
+	}
+
+	so_get_descriptor = (JackDriverDescFunction)
+		dlsym(dlhandle, "driver_get_descriptor");
+
+	dlerr = dlerror();
+	if (dlerr != NULL) {
+		jack_error("cannot find driver_get_descriptor symbol: %s", dlerr);
+		dlclose(dlhandle);
+		return false;
+	}
+
+	descriptor = so_get_descriptor();
+	if (descriptor == NULL) {
+		jack_error("driver from '%s' returned NULL descriptor", driver_ptr->filename);
+		dlclose(dlhandle);
+		return false;
+	}
+
+	err = dlclose(dlhandle);
+	if (err != 0) {
+		jack_error("error closing driver .so '%s': %s", driver_ptr->filename, dlerror());
+		free(descriptor->params);
+		free(descriptor);
+		return false;
+	}
+
+	/* for some mad reason we are storing filename in descriptor allocated by driver
+	   instead of reusing dlhandle when another dlsym() call is needed */
+	snprintf (descriptor->file, sizeof(descriptor->file), "%s", driver_ptr->filename);
+
+	driver_ptr->desc_ptr = descriptor;
+
+	return true;
+}
+
+static int
+jack_drivers_load(
+	struct jackctl_server * server_ptr)
+{
+	struct dirent * dir_entry;
+	DIR * dir_stream;
+	const char * ptr;
+	int err;
+	char* driver_dir;
+	struct jackctl_driver * driver_ptr;
+	struct jackctl_driver * other_driver_ptr;
+	JSList * node_ptr;
+	unsigned int drivers_count;
+
+	if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
+		driver_dir = ADDON_DIR;
+	}
+
+	if (server_ptr->verbose.b) {
+		jack_info ("searching for drivers in %s", driver_dir);
+	}
+
+	/* search through the driver_dir and add get descriptors
+	   from the .so files in it */
+	dir_stream = opendir (driver_dir);
+	if (!dir_stream) {
+		jack_error ("could not open driver directory %s: %s",
+			    driver_dir, strerror (errno));
+		return false;
+	}
+
+	drivers_count = 0;
+
+	while ( (dir_entry = readdir (dir_stream)) ) {
+		/* check the filename is of the right format */
+		if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
+			continue;
+		}
+
+#if SETTINGS_PERSISTENCE_USE_LIBXML2
+		/* disable ffado driver.
+		   it is incompatible with using libxml2 by other module,
+		   be it jackdbus or some other driver.
+		   libxml2 has global hooks used by libxml++, used by libffado */
+		if (strcmp ("jack_firewire.so", dir_entry->d_name) == 0) {
+			continue;
+		}
+#endif
+
+		ptr = strrchr (dir_entry->d_name, '.');
+		if (!ptr) {
+			continue;
+		}
+		ptr++;
+		if (strncmp ("so", ptr, 2) != 0) {
+			continue;
+		}
+
+		driver_ptr = malloc(sizeof(struct jackctl_driver));
+		if (driver_ptr == NULL)
+		{
+			jack_error("memory allocation of jackctl_driver structure failed.");
+			continue;
+		}
+
+		driver_ptr->filename = malloc(strlen(driver_dir) + 1 + strlen(dir_entry->d_name) + 1);
+
+		sprintf(driver_ptr->filename, "%s/%s", driver_dir, dir_entry->d_name);
+
+		if (!jackctl_load_driver_descriptor(server_ptr, driver_ptr))
+		{
+			goto dealloc_driver;
+		}
+
+		/* check it doesn't exist already */
+		for (node_ptr = server_ptr->drivers; node_ptr != NULL; node_ptr = jack_slist_next(node_ptr))
+		{
+			other_driver_ptr = (struct jackctl_driver *)node_ptr->data;
+
+			if (strcmp(driver_ptr->desc_ptr->name, other_driver_ptr->desc_ptr->name) == 0)
+			{
+				jack_error(
+					"the drivers in '%s' and '%s' both have the name '%s'; using the first",
+					other_driver_ptr->filename,
+					driver_ptr->filename,
+					driver_ptr->desc_ptr->name);
+				goto dealloc_descriptor;
+			}
+		}
+
+		driver_ptr->parameters = NULL;
+		driver_ptr->set_parameters = NULL;
+
+		if (!jackctl_add_driver_parameters(driver_ptr))
+		{
+			assert(driver_ptr->parameters == NULL);
+			goto dealloc_descriptor;
+		}
+
+		server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
+		drivers_count++;
+
+		continue;
+
+	dealloc_descriptor:
+		free(driver_ptr->desc_ptr->params);
+		free(driver_ptr->desc_ptr);
+
+	dealloc_driver:
+		free(driver_ptr->filename);
+		free(driver_ptr);
+	}
+
+	err = closedir (dir_stream);
+	if (err) {
+		jack_error ("error closing driver directory %s: %s",
+			    driver_dir, strerror (errno));
+	}
+
+	if (drivers_count == 0)
+	{
+		jack_error ("could not find any drivers in %s!", driver_dir);
+		return false;
+	}
+
+	return true;
+}
+
+static
+void
+jackctl_server_free_drivers(
+	struct jackctl_server * server_ptr)
+{
+	JSList * next_node_ptr;
+	struct jackctl_driver * driver_ptr;
+
+	while (server_ptr->drivers)
+	{
+		next_node_ptr = server_ptr->drivers->next;
+		driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
+
+		jackctl_free_driver_parameters(driver_ptr);
+		free(driver_ptr->desc_ptr->params);
+		free(driver_ptr->desc_ptr);
+		free(driver_ptr->filename);
+		free(driver_ptr);
+
+		free(server_ptr->drivers);
+		server_ptr->drivers = next_node_ptr;
+	}
+}
+
+static
+void
+jackctl_server_free_parameters(
+	struct jackctl_server * server_ptr)
+{
+	JSList * next_node_ptr;
+
+	while (server_ptr->parameters)
+	{
+		next_node_ptr = server_ptr->parameters->next;
+		free(server_ptr->parameters->data);
+		free(server_ptr->parameters);
+		server_ptr->parameters = next_node_ptr;
+	}
+}
+
+static void
+jack_cleanup_files (const char *server_name)
+{
+	DIR *dir;
+	struct dirent *dirent;
+	char dir_name[PATH_MAX+1] = "";
+        jack_server_dir (server_name, dir_name);
+
+	/* On termination, we remove all files that jackd creates so
+	 * subsequent attempts to start jackd will not believe that an
+	 * instance is already running.  If the server crashes or is
+	 * terminated with SIGKILL, this is not possible.  So, cleanup
+	 * is also attempted when jackd starts.
+	 *
+	 * There are several tricky issues.  First, the previous JACK
+	 * server may have run for a different user ID, so its files
+	 * may be inaccessible.  This is handled by using a separate
+	 * JACK_TMP_DIR subdirectory for each user.  Second, there may
+	 * be other servers running with different names.  Each gets
+	 * its own subdirectory within the per-user directory.  The
+	 * current process has already registered as `server_name', so
+	 * we know there is no other server actively using that name.
+	 */
+
+	/* nothing to do if the server directory does not exist */
+	if ((dir = opendir (dir_name)) == NULL) {
+		return;
+	}
+
+	/* unlink all the files in this directory, they are mine */
+	while ((dirent = readdir (dir)) != NULL) {
+
+		char fullpath[PATH_MAX+1];
+
+		if ((strcmp (dirent->d_name, ".") == 0)
+		    || (strcmp (dirent->d_name, "..") == 0)) {
+			continue;
+		}
+
+		snprintf (fullpath, sizeof (fullpath), "%s/%s",
+			  dir_name, dirent->d_name);
+
+		if (unlink (fullpath)) {
+			jack_error ("cannot unlink `%s' (%s)", fullpath,
+				    strerror (errno));
+		}
+	} 
+
+	closedir (dir);
+
+	/* now, delete the per-server subdirectory, itself */
+	if (rmdir (dir_name)) {
+ 		jack_error ("cannot remove `%s' (%s)", dir_name,
+			    strerror (errno));
+	}
+
+	/* finally, delete the per-user subdirectory, if empty */
+	if (rmdir (jack_user_dir ())) {
+		if (errno != ENOTEMPTY) {
+			jack_error ("cannot remove `%s' (%s)",
+				    jack_user_dir (), strerror (errno));
+		}
+	}
+}
+
+static
+int
+jackctl_xrun(void *arg)
+{
+	((struct jackctl_server *)arg)->xruns++;
+
+	return 0;
+}
+
+jackctl_server jackctl_server_create(const char * name)
+{
+	struct jackctl_server * server_ptr;
+	union jackctl_parameter_value value;
+
+	server_ptr = malloc(sizeof(struct jackctl_server));
+	if (server_ptr == NULL)
+	{
+		jack_error("Cannot allocate memory for jackctl_server structure.");
+		goto fail;
+	}
+
+	if (name != NULL)
+	{
+		server_ptr->name = strdup(name);
+	}
+	else
+	{
+		server_ptr->name = strdup(jack_default_server_name());
+	}
+
+	if (server_ptr->name == NULL)
+	{
+		goto fail_free_server;
+	}
+
+	server_ptr->drivers = NULL;
+	server_ptr->parameters = NULL;
+
+	server_ptr->engine = NULL;
+	server_ptr->xruns = 0;
+	server_ptr->next_client_id = 1;
+	server_ptr->next_port_id = 1;
+	server_ptr->next_connection_id = 1;
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "realtime",
+		    "Whether to use realtime mode",
+		    "Use realtime scheduling. This is needed for reliable low-latency performance. On most systems, it requires JACK to run with special scheduler and memory allocation privileges, which may be obtained in several ways. On Linux you should use PAM.",
+		    JackParamBool,
+		    &server_ptr->realtime,
+		    &server_ptr->default_realtime,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.i = 10;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "realtime-priority",
+		    "Scheduler priority when running in realtime mode.",
+		    "",
+		    JackParamInt,
+		    &server_ptr->realtime_priority,
+		    &server_ptr->default_realtime_priority,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "no-mem-lock",
+		    "Do not attempt to lock memory, even in realtime mode.",
+		    "",
+		    JackParamBool,
+		    &server_ptr->no_mem_lock,
+		    &server_ptr->default_no_mem_lock,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "temporary",
+		    "Exit once all clients have closed their connections.",
+		    "",
+		    JackParamBool,
+		    &server_ptr->temporary,
+		    &server_ptr->default_temporary,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "verbose",
+		    "Verbose mode.",
+		    "",
+		    JackParamBool,
+		    &server_ptr->verbose,
+		    &server_ptr->default_verbose,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.i = 500;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "client-timeout",
+		    "Client timeout limit in milliseconds",
+		    "Client timeout limit in milliseconds. In realtime mode the client timeout must be smaller than the watchdog timeout (5000 msec).",
+		    JackParamInt,
+		    &server_ptr->client_timeout,
+		    &server_ptr->default_client_timeout,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "no-zombies",
+		    "Prevent JACK from ever kicking out clients because they were too slow.",
+		    "Prevent JACK from ever kicking out clients because they were too slow. JACK and its clients are still subject to the supervision of the watchdog thread or its equivalent.",
+		    JackParamBool,
+		    &server_ptr->nozombies,
+		    &server_ptr->default_nozombies,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.ui = 256;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "port-max",
+		    "Maximum number of ports the JACK server can manage",
+		    "",
+		    JackParamUInt,
+		    &server_ptr->port_max,
+		    &server_ptr->default_port_max,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "libs-unlock",
+		    "Unlock libraries GTK+, QT, FLTK, Wine.",
+		    "",
+		    JackParamBool,
+		    &server_ptr->do_unlock,
+		    &server_ptr->default_do_unlock,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.c = 's';
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "clock-source",
+		    "Clock source",
+		    "Select a specific wall clock.\n"
+		    "  'c' - Cycle Counter\n"
+		    "  'h' - HPET timer\n"
+		    "  's' - System timer\n",
+		    JackParamChar,
+		    &server_ptr->clock_source,
+		    &server_ptr->default_clock_source,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.i = 0;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "debug-timer",
+		    "Debug timer",
+		    "",
+		    JackParamInt,
+		    &server_ptr->frame_time_offset,
+		    &server_ptr->default_frame_time_offset,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.b = false;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "replace-registry",
+		    "Replace registry.",
+		    "Remove the shared memory registry used by all JACK server instances before startup. This should rarely be used, and is intended only for occasions when the structure of this registry changes in ways that are incompatible across JACK versions (which is rare).",
+		    JackParamBool,
+		    &server_ptr->replace_registry,
+		    &server_ptr->default_replace_registry,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.ui = 0;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "midi-bufsize",
+		    "Override MIDI buffer size",
+		    "User-specified MIDI buffer sizing. The units are \"MIDI events per process() cycle\", where an event occupies up to 4 bytes (as most common MIDI events do). The default buffer size is same as the one used for audio data, which will store about 2 MIDI events per sample. Typical values for event-count will range from 10 to about 500. Be aware that using very high values along with a large number of ports may cause JACK to fail to start because of the amount of memory that would be required.",
+		    JackParamUInt,
+		    &server_ptr->midi_buffer_size,
+		    &server_ptr->default_midi_buffer_size,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	value.ui = 0;
+	if (jackctl_add_parameter(
+		    &server_ptr->parameters,
+		    "timeout-threshold",
+		    "threshold for suspending processing",
+		    "If not zero, stop processing clients if JACK cannot complete the process cycle in time (typically caused by CPU overloading or misbehaved clients). The value specifies the number of miliseconds, during which consectutive process cycles must fail before JACK gives up. If you want to enable this behavour but are not sure about what value to set, use 250. Processing will resume on the next change to the port graph (i.e. a port is added, removed, connected or disconnected)",
+		    JackParamUInt,
+		    &server_ptr->timothres,
+		    &server_ptr->default_timothres,
+		    value) == NULL)
+	{
+		goto fail_free_name;
+	}
+
+	if (!jack_drivers_load(server_ptr))
+	{
+		goto fail_free_parameters;
+	}
+
+	return (jackctl_server)server_ptr;
+
+fail_free_parameters:
+	jackctl_server_free_parameters(server_ptr);
+
+fail_free_name:
+	free(server_ptr->name);
+
+fail_free_server:
+	free(server_ptr);
+
+fail:
+	return NULL;
+}
+
+static
+struct jackctl_client *
+jackctl_find_client(
+	struct jackctl_server * server_ptr,
+	const char * client_name, /* not '\0' terminated */
+	size_t client_name_len)	/* without terminating '\0' */
+{
+	JSList * node_ptr;
+	struct jackctl_client * client_ptr;
+
+	node_ptr = server_ptr->clients;
+
+	while (node_ptr != NULL)
+	{
+		client_ptr = node_ptr->data;
+		if (strlen(client_ptr->name) == client_name_len && strncmp(client_ptr->name, client_name, client_name_len) == 0)
+		{
+			return client_ptr;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+	}
+
+	return NULL;
+}
+
+static
+struct jackctl_client *
+jackctl_find_or_create_client(
+	struct jackctl_server * server_ptr,
+	const char * client_name, /* not '\0' terminated */
+	size_t client_name_len,	/* without terminating '\0' */
+	pid_t pid)
+{
+	struct jackctl_client * client_ptr;
+
+	/* First, try to find existing client */
+	client_ptr = jackctl_find_client(server_ptr, client_name, client_name_len);
+	if (client_ptr != NULL)
+	{
+		return client_ptr;
+	}
+
+	/* Such client does not exist, create new one */
+
+	client_ptr = malloc(sizeof(struct jackctl_client));
+	if (client_ptr == NULL)
+	{
+		jack_error("Allocation of jackctl_client structure failed.");
+		goto fail;
+	}
+
+	client_ptr->name = malloc((client_name_len + 1) * sizeof(char));
+	if (client_ptr->name == NULL)
+	{
+		jack_error("Allocation of client name string of %u chars failed.", (unsigned int)client_name_len);
+		goto fail_free_client;
+	}
+
+	memcpy(client_ptr->name, client_name, client_name_len * sizeof(char));
+	client_ptr->name[client_name_len] = '\0';
+
+	client_ptr->ports = NULL;
+
+	client_ptr->id = server_ptr->next_client_id++;
+
+	client_ptr->pid = pid;
+
+	server_ptr->clients = jack_slist_append(server_ptr->clients, client_ptr);
+
+	if (server_ptr->client_appeared_callback != NULL)
+	{
+		client_ptr->patchbay_context = server_ptr->client_appeared_callback(
+			server_ptr->patchbay_context,
+			client_ptr->id,
+			client_ptr->name);
+
+	}
+
+
+	return client_ptr;
+
+fail_free_client:
+	free(client_ptr);
+
+fail:
+	return NULL;
+}
+
+static
+struct jackctl_port *
+jackctl_find_client_port_by_name(
+	struct jackctl_client * client_ptr,
+	const char * port_name)	/* '\0' terminated */
+{
+	JSList * node_ptr;
+	struct jackctl_port * port_ptr;
+
+	node_ptr = client_ptr->ports;
+
+	while (node_ptr != NULL)
+	{
+		port_ptr = node_ptr->data;
+		if (strcmp(port_ptr->name, port_name) == 0)
+		{
+			return port_ptr;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+	}
+
+	return NULL;
+}
+
+static
+bool
+jackctl_compose_port_fullname(
+	struct jackctl_client * client_ptr,
+	struct jackctl_port * port_ptr,
+	char * port_fullname_buffer)
+{
+	if (strlen(client_ptr->name) + strlen(port_ptr->name) + 2 > JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE)
+	{
+		jack_error("client name + port name too long");
+		return false;
+	}
+
+	sprintf(port_fullname_buffer, "%s:%s", client_ptr->name, port_ptr->name);
+	return true;
+}
+
+static
+bool
+jackctl_find_client_ports_by_id(
+	struct jackctl_server * server_ptr,
+	uint64_t port1_id,
+	uint64_t port2_id,
+	char * port1_fullname_buffer,
+	char * port2_fullname_buffer)
+{
+	int found;
+	JSList * client_node_ptr;
+	JSList * port_node_ptr;
+	struct jackctl_client * client_ptr;
+	struct jackctl_port * port_ptr;
+
+	found = 0;
+
+	for (client_node_ptr = server_ptr->clients; client_node_ptr != NULL; client_node_ptr = jack_slist_next(client_node_ptr))
+	{
+		client_ptr = client_node_ptr->data;
+
+		for (port_node_ptr = client_ptr->ports; port_node_ptr != NULL; port_node_ptr = jack_slist_next(port_node_ptr))
+		{
+			port_ptr = port_node_ptr->data;
+
+			if (port_ptr->id == port1_id)
+			{
+				if (!jackctl_compose_port_fullname(client_ptr, port_ptr, port1_fullname_buffer))
+				{
+					return false;
+				}
+
+				found++;
+			}
+
+			if (port_ptr->id == port2_id)
+			{
+				if (!jackctl_compose_port_fullname(client_ptr, port_ptr, port2_fullname_buffer))
+				{
+					return false;
+				}
+
+				found++;
+			}
+
+			if (found == 2)
+			{
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+static
+bool
+jackctl_remove_port(
+	struct jackctl_server * server_ptr,
+	struct jackctl_client * client_ptr,
+	const char * port_name)
+{
+	JSList * node_ptr;
+	struct jackctl_port * port_ptr;
+
+	node_ptr = client_ptr->ports;
+
+	while (node_ptr != NULL)
+	{
+		port_ptr = node_ptr->data;
+		if (strcmp(port_ptr->name, port_name) == 0)
+		{
+			goto found;
+		}
+
+		node_ptr = jack_slist_next(node_ptr);
+	}
+
+	jack_error("Unknown port '%s' of client '%s'", port_name, client_ptr->name);
+
+	return false;
+
+found:
+	client_ptr->ports = jack_slist_remove(client_ptr->ports, port_ptr);
+
+	if (server_ptr->port_disappeared_callback != NULL)
+	{
+		server_ptr->port_disappeared_callback(
+			server_ptr->patchbay_context,
+			client_ptr->id,
+			client_ptr->patchbay_context,
+			port_ptr->id,
+			port_ptr->patchbay_context);
+
+	}
+
+	free(port_ptr->name);
+	free(port_ptr);
+
+	if (client_ptr->ports == NULL)
+	{
+		/* the last port of the client, remove the client */
+
+		server_ptr->clients = jack_slist_remove(server_ptr->clients, client_ptr);
+
+		if (server_ptr->client_disappeared_callback != NULL)
+		{
+			server_ptr->client_disappeared_callback(
+				server_ptr->patchbay_context,
+				client_ptr->id,
+				client_ptr->patchbay_context);
+
+		}
+
+		free(client_ptr->name);
+		free(client_ptr);
+	}
+
+	return true;
+}
+
+#define server_ptr ((struct jackctl_server *)server)
+
+int
+jack_port_do_connect(
+	jack_engine_t *engine,
+	const char *source_port,
+	const char *destination_port);
+
+int
+jack_port_do_disconnect(
+	jack_engine_t *engine,
+	const char *source_port,
+	const char *destination_port);
+
+bool
+jackctl_connect_ports_by_name(
+	jackctl_server server,
+	const char * client1_name,
+	const char * port1_name,
+	const char * client2_name,
+	const char * port2_name)
+{
+	int ret;
+	char port1_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+	char port2_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+
+	if (strlen(client1_name) + strlen(port1_name) + 2 > JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE ||
+	    strlen(client2_name) + strlen(port2_name) + 2 > JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE)
+	{
+		jack_error("client name + port name too long");
+		return false;
+	}
+
+	sprintf(port1_full_name, "%s:%s", client1_name, port1_name);
+	sprintf(port2_full_name, "%s:%s", client2_name, port2_name);
+
+	ret = jack_port_do_connect(
+		server_ptr->engine,
+		port1_full_name,
+		port2_full_name);
+
+	if (ret != 0)
+	{
+		jack_error("jack_port_do_connect('%s', '%s') failed with %d", port1_full_name, port2_full_name, ret);
+		return false;
+	}
+
+	return true;
+}
+
+bool
+jackctl_disconnect_ports_by_name(
+	jackctl_server server,
+	const char * client1_name,
+	const char * port1_name,
+	const char * client2_name,
+	const char * port2_name)
+{
+	int ret;
+	char port1_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+	char port2_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+
+	if (strlen(client1_name) + strlen(port1_name) + 2 > JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE ||
+	    strlen(client2_name) + strlen(port2_name) + 2 > JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE)
+	{
+		jack_error("client name + port name too long");
+		return false;
+	}
+
+	sprintf(port1_full_name, "%s:%s", client1_name, port1_name);
+	sprintf(port2_full_name, "%s:%s", client2_name, port2_name);
+
+	ret = jack_port_do_disconnect(
+		server_ptr->engine,
+		port1_full_name,
+		port2_full_name);
+
+	if (ret != 0)
+	{
+		jack_error("jack_port_do_disconnect('%s', '%s') failed with %d", port1_full_name, port2_full_name, ret);
+		return false;
+	}
+
+	return true;
+}
+
+bool
+jackctl_connect_ports_by_id(
+	jackctl_server server,
+	uint64_t port1_id,
+	uint64_t port2_id)
+{
+	int ret;
+	char port1_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+	char port2_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+
+	if (!jackctl_find_client_ports_by_id(server_ptr, port1_id, port2_id, port1_full_name, port2_full_name))
+	{
+		jack_error("jackctl_find_client_ports_by_id(%"PRIu64", %"PRIu64") failed", port1_id, port2_id);
+		return false;
+	}
+
+	jack_info("Connecting %"PRIu64" (%s) to %"PRIu64" (%s)", port1_id, port1_full_name, port2_id, port2_full_name);
+
+	ret = jack_port_do_connect(
+		server_ptr->engine,
+		port1_full_name,
+		port2_full_name);
+	if (ret != 0)
+	{
+		jack_error("jack_port_do_connect('%s', '%s') failed with %d", port1_full_name, port2_full_name, ret);
+		return false;
+	}
+
+	return true;
+}
+
+bool
+jackctl_disconnect_ports_by_id(
+	jackctl_server server,
+	uint64_t port1_id,
+	uint64_t port2_id)
+{
+	int ret;
+	char port1_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+	char port2_full_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
+
+	if (!jackctl_find_client_ports_by_id(server_ptr, port1_id, port2_id, port1_full_name, port2_full_name))
+	{
+		jack_error("jackctl_find_client_ports_by_id(%"PRIu64", %"PRIu64") failed", port1_id, port2_id);
+		return false;
+	}
+
+	jack_info("Disonnecting %"PRIu64" (%s) from %"PRIu64" (%s)", port1_id, port1_full_name, port2_id, port2_full_name);
+
+	ret = jack_port_do_disconnect(
+		server_ptr->engine,
+		port1_full_name,
+		port2_full_name);
+	if (ret != 0)
+	{
+		jack_error("jack_port_do_disconnect('%s', '%s') failed with %d", port1_full_name, port2_full_name, ret);
+		return false;
+	}
+
+	return true;
+}
+
+bool
+jackctl_disconnect_ports_by_connection_id(
+	jackctl_server server,
+	uint64_t connection_id)
+{
+	jack_info("Disconnecting connection %"PRIu64, connection_id);
+	jack_error("jackctl_disconnect_ports_by_connection_id() not implemetned yet");
+	return false;
+}
+
+void jackctl_server_destroy(jackctl_server server)
+{
+	jackctl_server_free_drivers(server_ptr);
+	jackctl_server_free_parameters(server_ptr);
+	free(server_ptr->name);
+	free(server_ptr);
+}
+
+const JSList * jackctl_server_get_drivers_list(jackctl_server server)
+{
+	return server_ptr->drivers;
+}
+
+bool jackctl_server_stop(jackctl_server server)
+{
+	JSList * next_client_node_ptr;
+	struct jackctl_client * client_ptr;
+	JSList * next_port_node_ptr;
+	struct jackctl_port * port_ptr;
+
+	jack_engine_delete(server_ptr->engine);
+
+	/* clean up shared memory and files from this server instance */
+	if (server_ptr->verbose.b)
+	{
+		jack_info("cleaning up shared memory");
+	}
+
+	jack_cleanup_shm();
+
+	if (server_ptr->verbose.b)
+	{
+		jack_info("cleaning up files");
+	}
+
+	jack_cleanup_files(server_ptr->name);
+
+	if (server_ptr->verbose.b)
+	{
+		jack_info("unregistering server `%s'", server_ptr->name);
+	}
+
+	jack_unregister_server(server_ptr->name);
+
+	while (server_ptr->clients)
+	{
+		next_client_node_ptr = server_ptr->clients->next;
+
+		client_ptr = server_ptr->clients->data;
+
+		while (client_ptr->ports)
+		{
+			next_port_node_ptr = client_ptr->ports->next;
+			port_ptr = client_ptr->ports->data;
+
+			if (server_ptr->port_disappeared_callback != NULL)
+			{
+				server_ptr->port_disappeared_callback(
+					server_ptr->patchbay_context,
+					client_ptr->id,
+					client_ptr->patchbay_context,
+					port_ptr->id,
+					port_ptr->patchbay_context);
+
+			}
+
+			free(port_ptr->name);
+			free(port_ptr);
+
+			free(client_ptr->ports);
+			client_ptr->ports = next_port_node_ptr;
+		}
+
+		if (server_ptr->client_disappeared_callback != NULL)
+		{
+			server_ptr->client_disappeared_callback(
+				server_ptr->patchbay_context,
+				client_ptr->id,
+				client_ptr->patchbay_context);
+
+		}
+
+		free(client_ptr->name);
+		free(client_ptr);
+
+		free(server_ptr->clients);
+		server_ptr->clients = next_client_node_ptr;
+	}
+
+	server_ptr->engine = NULL;
+
+	return true;
+}
+
+double jackctl_server_get_load(jackctl_server server)
+{
+	return server_ptr->engine->control->cpu_load;
+}
+
+unsigned int jackctl_server_get_sample_rate(jackctl_server server)
+{
+	return server_ptr->engine->control->current_time.frame_rate;
+}
+
+double jackctl_server_get_latency(jackctl_server server)
+{
+	return server_ptr->engine->driver->period_usecs / 1000.0;
+}
+
+unsigned int
+jackctl_server_get_buffer_size(
+	jackctl_server server)
+{
+	return server_ptr->engine->control->buffer_size;
+}
+
+int
+jack_set_buffer_size_request (jack_engine_t *engine, jack_nframes_t nframes);
+
+bool
+jackctl_server_set_buffer_size(
+	jackctl_server server,
+	unsigned int nframes)
+{
+	int ret;
+	ret = jack_set_buffer_size_request(server_ptr->engine, nframes);
+	if (ret != 0)
+	{
+		jack_error("jack_set_buffer_size_request() failed.");
+		return false;
+	}
+
+	return true;
+}
+
+bool jackctl_server_is_realtime(jackctl_server server)
+{
+	return server_ptr->realtime.b;
+}
+
+unsigned int jackctl_server_get_xruns(jackctl_server server)
+{
+	return server_ptr->xruns;
+}
+
+void jackctl_server_reset_xruns(jackctl_server server)
+{
+	server_ptr->xruns = 0;
+}
+
+const JSList * jackctl_server_get_parameters(jackctl_server server)
+{
+	return server_ptr->parameters;
+}
+
+static
+void
+jackctl_port_registration_notify(
+	void * server,
+	jack_port_id_t port_id,
+	int yn)
+{
+	const char * port_full_name;
+	struct jackctl_client * client_ptr;
+	const char * port_short_name;
+	struct jackctl_port * port_ptr;
+	jack_client_internal_t * client;
+	pid_t pid;
+
+/* 	jack_info("jackctl_port_registration_notify() called."); */
+
+	port_full_name = server_ptr->engine->control->ports[port_id].name;
+
+	client = jack_client_internal_by_id(server_ptr->engine, server_ptr->engine->control->ports[port_id].client_id);
+	if (client != NULL && client->control->type == ClientExternal)
+	{
+		pid = client->control->pid;
+	}
+	else
+	{
+		pid = 0;
+	}
+
+	port_short_name = strchr(port_full_name, ':');
+	if (port_short_name == NULL)
+	{
+		jack_error("port name '%s' does not contain ':' separator char", port_full_name);
+		return;
+	}
+
+	port_short_name++;	/* skip ':' separator char */
+
+	if (yn)
+	{
+		/* appearing port */
+
+		client_ptr = jackctl_find_or_create_client(server_ptr, port_full_name, port_short_name - port_full_name - 1, pid);
+		if (client_ptr == NULL)
+		{
+			jack_error("Creation of new jackctl client failed.");
+			return;
+		}
+
+		port_ptr = malloc(sizeof(struct jackctl_port));
+		if (port_ptr == NULL)
+		{
+			jack_error("Allocation of jackctl_port structure failed.");
+			return;
+		}
+
+		port_ptr->id = server_ptr->next_port_id++;
+		port_ptr->name = strdup(port_short_name);
+		port_ptr->client_ptr = client_ptr;
+		port_ptr->flags = server_ptr->engine->control->ports[port_id].flags;
+		port_ptr->type = server_ptr->engine->control->ports[port_id].ptype_id;
+
+		client_ptr->ports = jack_slist_append(client_ptr->ports, port_ptr);
+
+		if (server_ptr->port_appeared_callback != NULL)
+		{
+			port_ptr->patchbay_context = server_ptr->port_appeared_callback(
+				server_ptr->patchbay_context,
+				client_ptr->id,
+				client_ptr->patchbay_context,
+				port_ptr->id,
+				port_ptr->name,
+				port_ptr->flags,
+				port_ptr->type);
+		}
+
+		return;
+	}
+
+	/* disappearing port */
+
+	client_ptr = jackctl_find_client(server_ptr, port_full_name, port_short_name - port_full_name - 1);
+	if (client_ptr == NULL)
+	{
+		jack_error("Port '%s' of unknown jackctl client disappeared.", port_full_name);
+		return;
+	}
+
+	jackctl_remove_port(server_ptr, client_ptr, port_short_name);
+}
+
+void
+jackctl_connection_notify(
+	void * server,
+	jack_port_id_t port1_id,
+	jack_port_id_t port2_id,
+	int connected)
+{
+	const char * port1_full_name;
+	struct jackctl_client * client1_ptr;
+	const char * port1_short_name;
+	struct jackctl_port * port1_ptr;
+	const char * port2_full_name;
+	struct jackctl_client * client2_ptr;
+	const char * port2_short_name;
+	struct jackctl_port * port2_ptr;
+	struct jackctl_connection * connection_ptr;
+	JSList * node_ptr;
+
+/*  	jack_info("jackctl_connection_notify() called."); */
+
+	port1_full_name = server_ptr->engine->control->ports[port1_id].name;
+
+	port1_short_name = strchr(port1_full_name, ':');
+	if (port1_short_name == NULL)
+	{
+		jack_error("port name '%s' does not contain ':' separator char", port1_full_name);
+		return;
+	}
+
+	port1_short_name++;	/* skip ':' separator char */
+
+	port2_full_name = server_ptr->engine->control->ports[port2_id].name;
+
+	port2_short_name = strchr(port2_full_name, ':');
+	if (port2_short_name == NULL)
+	{
+		jack_error("port name '%s' does not contain ':' separator char", port2_full_name);
+		return;
+	}
+
+	port2_short_name++;	/* skip ':' separator char */
+
+	client1_ptr = jackctl_find_client(server_ptr, port1_full_name, port1_short_name - port1_full_name - 1);
+	if (client1_ptr == NULL)
+	{
+		jack_error("Port '%s' of unknown jackctl client.", port1_full_name);
+		return;
+	}
+
+	port1_ptr = jackctl_find_client_port_by_name(client1_ptr, port1_short_name);
+	if (port1_ptr == NULL)
+	{
+		jack_error("Unknown port '%s'.", port1_full_name);
+		return;
+	}
+
+	client2_ptr = jackctl_find_client(server_ptr, port2_full_name, port2_short_name - port2_full_name - 1);
+	if (client2_ptr == NULL)
+	{
+		jack_error("Port '%s' of unknown jackctl client.", port2_full_name);
+		return;
+	}
+
+	port2_ptr = jackctl_find_client_port_by_name(client2_ptr, port2_short_name);
+	if (port2_ptr == NULL)
+	{
+		jack_error("Unknown port '%s'.", port2_full_name);
+		return;
+	}
+
+	if (connected && server_ptr->ports_connected_callback != NULL)
+	{
+		connection_ptr = malloc(sizeof(struct jackctl_connection));
+		if (connection_ptr == NULL)
+		{
+			jack_error("Allocation of jackctl_connection structure failed.");
+			return;
+		}
+
+		connection_ptr->id = server_ptr->next_connection_id++;
+		connection_ptr->port1_ptr = port1_ptr;
+		connection_ptr->port2_ptr = port2_ptr;
+
+		server_ptr->connections = jack_slist_append(server_ptr->connections, connection_ptr);
+
+		connection_ptr->patchbay_context = server_ptr->ports_connected_callback(
+			server_ptr->patchbay_context,
+			client1_ptr->id,
+			client1_ptr->patchbay_context,
+			port1_ptr->id,
+			port1_ptr->patchbay_context,
+			client2_ptr->id,
+			client2_ptr->patchbay_context,
+			port2_ptr->id,
+			port2_ptr->patchbay_context,
+			connection_ptr->id);
+	}
+
+	if (!connected && server_ptr->ports_disconnected_callback != NULL)
+	{
+		node_ptr = server_ptr->connections;
+
+		while (node_ptr != NULL)
+		{
+			connection_ptr = node_ptr->data;
+			if ((connection_ptr->port1_ptr == port1_ptr &&
+			     connection_ptr->port2_ptr == port2_ptr) ||
+			    (connection_ptr->port1_ptr == port2_ptr &&
+			     connection_ptr->port2_ptr == port1_ptr))
+			{
+				server_ptr->connections = jack_slist_remove(server_ptr->connections, connection_ptr);
+
+				server_ptr->ports_disconnected_callback(
+					server_ptr->patchbay_context,
+					client1_ptr->id,
+					client1_ptr->patchbay_context,
+					port1_ptr->id,
+					port1_ptr->patchbay_context,
+					client2_ptr->id,
+					client2_ptr->patchbay_context,
+					port2_ptr->id,
+					port2_ptr->patchbay_context,
+					connection_ptr->id,
+					connection_ptr->patchbay_context);
+				return;
+			}
+
+			node_ptr = jack_slist_next(node_ptr);
+		}
+
+		jack_error("Cannot find connection being removed");
+	}
+}
+
+#define driver_ptr ((struct jackctl_driver *)driver)
+
+bool
+jackctl_server_start(
+	jackctl_server server,
+	jackctl_driver driver,
+	void * context,
+	jackctl_client_appeared_callback client_appeared_callback,
+	jackctl_client_disappeared_callback client_disappeared_callback,
+	jackctl_port_appeared_callback port_appeared_callback,
+	jackctl_port_disappeared_callback port_disappeared_callback,
+	jackctl_ports_connected_callback ports_connected_callback,
+	jackctl_ports_disconnected_callback ports_disconnected_callback)
+{
+	int rc;
+	jack_port_type_info_t * port_type;
+
+	switch (server_ptr->clock_source.c)
+	{
+	case 'h':
+		jack_info("Using HPET timer as clock source.");
+		clock_source = JACK_TIMER_HPET;
+		break;
+	case 'c':
+		jack_info("Using Cycle Counter as clock source.");
+		clock_source = JACK_TIMER_CYCLE_COUNTER;
+		break;
+	case 's':
+		jack_info("Using System timer as clock source.");
+		clock_source = JACK_TIMER_SYSTEM_CLOCK;
+		break;
+	default:
+		jack_error(
+			"Invalid value '%c' for clock source, "
+			"valid values are "
+			"'c' for Cycle Counter, "
+			"'h' for HPET timer and "
+			"'s' for System timer",
+			server_ptr->clock_source.c);
+		return false;
+	}
+
+	port_type = &jack_builtin_port_types[JACK_MIDI_PORT_TYPE];
+	if (server_ptr->midi_buffer_size.ui != 0) {
+		port_type->buffer_size = server_ptr->midi_buffer_size.ui * jack_midi_internal_event_size ();
+		port_type->buffer_scale_factor = -1;
+		if (server_ptr->verbose.b) {
+			jack_info ("Set MIDI buffer size to %u bytes", (unsigned int)port_type->buffer_size);
+		}
+	} else {
+		port_type->buffer_scale_factor = 1;
+	}
+
+	rc = jack_register_server(server_ptr->name, server_ptr->replace_registry.b);
+	switch (rc)
+	{
+	case EEXIST:
+		jack_error("`%s' server already active", server_ptr->name);
+		goto fail;
+	case ENOSPC:
+		jack_error("too many servers already active");
+		goto fail;
+	case ENOMEM:
+		jack_error("no access to shm registry");
+		goto fail;
+	}
+
+	if (server_ptr->verbose.b)
+	{
+		jack_info ("server `%s' registered", server_ptr->name);
+	}
+
+	/* clean up shared memory and files from any previous
+	 * instance of this server name */
+	jack_cleanup_shm();
+	jack_cleanup_files(server_ptr->name);
+
+	if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0)
+		server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
+
+	/* get the engine/driver started */
+
+	server_ptr->engine = jack_engine_new(
+		server_ptr->realtime.b,
+		server_ptr->realtime_priority.i,
+		!server_ptr->no_mem_lock.b,
+		server_ptr->do_unlock.b,
+		server_ptr->name,
+		server_ptr->temporary.b,
+		server_ptr->verbose.b,
+		server_ptr->client_timeout.i,
+		server_ptr->port_max.ui,
+		getpid(),
+		server_ptr->frame_time_offset.i,
+		server_ptr->nozombies.b,
+		server_ptr->timothres.ui,
+		NULL);
+	if (server_ptr->engine == NULL)
+	{
+		jack_error("Cannot create engine!");
+		goto fail_unregister_server;
+	}
+
+	server_ptr->engine->jackctl_port_registration_notify = jackctl_port_registration_notify;
+	server_ptr->engine->jackctl_connection_notify = jackctl_connection_notify;
+	server_ptr->engine->jackctl_context = server_ptr;
+
+	server_ptr->patchbay_context = context;
+	server_ptr->client_appeared_callback = client_appeared_callback;
+	server_ptr->client_disappeared_callback = client_disappeared_callback;
+	server_ptr->port_appeared_callback = port_appeared_callback;
+	server_ptr->port_disappeared_callback = port_disappeared_callback;
+	server_ptr->ports_connected_callback = ports_connected_callback;
+	server_ptr->ports_disconnected_callback = ports_disconnected_callback;
+
+	server_ptr->clients = NULL;
+	server_ptr->connections = NULL;
+
+	jack_info("loading driver \"%s\" ...", driver_ptr->desc_ptr->name);
+
+	if (jack_engine_load_driver(server_ptr->engine, driver_ptr->desc_ptr, driver_ptr->set_parameters)) {
+		jack_error("cannot load driver module %s", driver_ptr->desc_ptr->name);
+		goto fail_delete_engine;
+	}
+
+	server_ptr->xruns = 0;
+	server_ptr->engine->driver->internal_client->private_client->control->xrun_cbset = TRUE;
+	server_ptr->engine->driver->internal_client->private_client->xrun = jackctl_xrun;
+	server_ptr->engine->driver->internal_client->private_client->xrun_arg = server_ptr;
+
+	if (server_ptr->engine->driver->start(server_ptr->engine->driver) != 0) {
+		jack_error("cannot start \"%s\" driver", driver_ptr->desc_ptr->name);
+		goto fail_delete_engine;
+	}
+
+	return true;
+
+fail_unregister_server:
+	if (server_ptr->verbose.b)
+	{
+		jack_info("cleaning up shared memory");
+	}
+
+	jack_cleanup_shm();
+
+	if (server_ptr->verbose.b)
+	{
+		jack_info("cleaning up files");
+	}
+
+	jack_cleanup_files(server_ptr->name);
+
+	if (server_ptr->verbose.b)
+	{
+		jack_info("unregistering server `%s'", server_ptr->name);
+	}
+
+	jack_unregister_server(server_ptr->name);
+
+fail_delete_engine:
+	jack_engine_delete(server_ptr->engine);
+	server_ptr->engine = NULL;
+
+fail:
+	return false;
+}
+
+int
+jackctl_get_client_pid(
+	jackctl_server server,
+	const char * name)
+{
+	struct jackctl_client * client_ptr;
+
+	client_ptr = jackctl_find_client(server_ptr, name, strlen(name));
+	if (client_ptr == NULL)
+	{
+		return 0;
+	}
+
+	return client_ptr->pid;
+}
+
+#undef server_ptr
+
+const char * jackctl_driver_get_name(jackctl_driver driver)
+{
+	return driver_ptr->desc_ptr->name;
+}
+
+const JSList * jackctl_driver_get_parameters(jackctl_driver driver)
+{
+	return driver_ptr->parameters;
+}
+
+#undef driver_ptr
+
+#define parameter_ptr ((struct jackctl_parameter *)parameter)
+
+const char * jackctl_parameter_get_name(jackctl_parameter parameter)
+{
+	return parameter_ptr->name;
+}
+
+const char * jackctl_parameter_get_short_description(jackctl_parameter parameter)
+{
+	return parameter_ptr->short_description;
+}
+
+const char * jackctl_parameter_get_long_description(jackctl_parameter parameter)
+{
+	return parameter_ptr->long_description;
+}
+
+bool jackctl_parameter_has_range_constraint(jackctl_parameter parameter)
+{
+    return false;
+    //return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0;
+}
+
+bool jackctl_parameter_has_enum_constraint(jackctl_parameter parameter)
+{
+    return false;
+    //return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0;
+}
+
+uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter parameter)
+{
+#if 0
+    if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
+    {
+        return 0;
+    }
+
+    return parameter_ptr->constraint_ptr->constraint.enumeration.count;
+#else
+    return 0;
+#endif
+}
+
+union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter parameter, uint32_t index)
+{
+    //jack_driver_param_value_t * value_ptr;
+    union jackctl_parameter_value jackctl_value;
+
+#if 0
+    value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
+
+    switch (parameter_ptr->type)
+    {
+    case JackParamInt:
+        jackctl_value.i = value_ptr->i;
+        break;
+    case JackParamUInt:
+        jackctl_value.ui = value_ptr->ui;
+        break;
+    case JackParamChar:
+        jackctl_value.c = value_ptr->c;
+        break;
+    case JackParamString:
+        strcpy(jackctl_value.str, value_ptr->str);
+        break;
+    default:
+#endif
+        jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
+        assert(0);
+#if 0
+    }
+#endif
+
+    return jackctl_value;
+}
+
+const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter parameter, uint32_t index)
+{
+    return "???";
+    //return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc;
+}
+
+void jackctl_parameter_get_range_constraint(jackctl_parameter parameter, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
+{
+#if 0
+    switch (parameter_ptr->type)
+    {
+    case JackParamInt:
+        min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
+        max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
+        return;
+    case JackParamUInt:
+        min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
+        max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
+        return;
+    default:
+#endif
+        jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
+        assert(0);
+#if 0
+    }
+#endif
+}
+
+bool jackctl_parameter_constraint_is_strict(jackctl_parameter parameter)
+{
+    return false;
+    //return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0;
+}
+
+bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter parameter)
+{
+    return false;
+    //return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0;
+}
+
+jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter parameter)
+{
+	return parameter_ptr->type;
+}
+
+bool jackctl_parameter_is_set(jackctl_parameter parameter)
+{
+	return parameter_ptr->is_set;
+}
+
+union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter parameter)
+{
+	return *parameter_ptr->value_ptr;
+}
+
+bool jackctl_parameter_reset(jackctl_parameter parameter)
+{
+    if (!parameter_ptr->is_set)
+    {
+        return true;
+    }
+
+    parameter_ptr->is_set = false;
+
+    *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
+
+    return true;
+}
+
+bool jackctl_parameter_set_value(jackctl_parameter parameter, const union jackctl_parameter_value * value_ptr)
+{
+	bool new_driver_parameter;
+
+	/* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */
+	if (parameter_ptr->driver_ptr != NULL)
+	{
+/* 		jack_info("setting driver parameter %p ...", parameter_ptr); */
+		new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL;
+		if (new_driver_parameter)
+		{
+/* 			jack_info("new driver parameter..."); */
+
+			parameter_ptr->driver_parameter_ptr = malloc(sizeof(jack_driver_param_t));
+			if (parameter_ptr->driver_parameter_ptr == NULL)
+			{
+				jack_error ("Allocation of jack_driver_param_t structure failed");
+				return false;
+			}
+
+			parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id;
+
+			parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
+		}
+
+		switch (parameter_ptr->type)
+		{
+		case JackParamInt:
+			parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i;
+			break;
+		case JackParamUInt:
+			parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui;
+			break;
+		case JackParamChar:
+			parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c;
+			break;
+		case JackParamString:
+			strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str);
+			break;
+		case JackParamBool:
+			parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b;
+			break;
+		default:
+			jack_error("unknown parameter type %i", (int)parameter_ptr->type);
+			assert(0);
+
+			if (new_driver_parameter)
+			{
+				parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
+			}
+
+			return false;
+		}
+	}
+
+	parameter_ptr->is_set = true;
+	*parameter_ptr->value_ptr = *value_ptr;
+
+	return true;
+}
+
+union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter parameter)
+{
+	return *parameter_ptr->default_value_ptr;
+}
+
+#undef parameter_ptr
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackctl.h jack1/jackd/jackctl.h
--- jack1.old/jackd/jackctl.h	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackctl.h	2013-10-06 17:44:19.785394471 +0100
@@ -0,0 +1,592 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    JACK control API
+
+    Copyright (C) 2008,2010 Nedko Arnaudov
+    Copyright (C) 2008 GRAME
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED
+#define JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED
+
+/** Parameter types, intentionally similar to jack_driver_param_type_t */
+typedef enum
+{
+    JackParamInt = 1,			/**< @brief value type is a signed integer */
+    JackParamUInt,				/**< @brief value type is an unsigned integer */
+    JackParamChar,				/**< @brief value type is a char */
+    JackParamString,			/**< @brief value type is a string with max size of ::JACK_PARAM_STRING_MAX+1 chars */
+    JackParamBool,				/**< @brief value type is a boolean */
+} jackctl_param_type_t;
+
+/** @brief Max value that jackctl_param_type_t type can have */
+#define JACK_PARAM_MAX (JackParamBool + 1)
+
+/** @brief Max length of string parameter value, excluding terminating nul char */
+#define JACK_PARAM_STRING_MAX  63
+
+/** @brief Type for parameter value */
+/* intentionally similar to jack_driver_param_value_t */
+union jackctl_parameter_value
+{
+    uint32_t ui;				/**< @brief member used for ::JackParamUInt */
+    int32_t i;					/**< @brief member used for ::JackParamInt */
+    char c;						/**< @brief member used for ::JackParamChar */
+    char str[JACK_PARAM_STRING_MAX + 1]; /**< @brief member used for ::JackParamString */
+    bool b;				/**< @brief member used for ::JackParamBool */
+};
+
+/** opaque type for server object */
+typedef struct jackctl_server jackctl_server_t;
+
+/** opaque type for driver object */
+typedef struct jackctl_driver jackctl_driver_t;
+
+/** opaque type for internal client object */
+typedef struct jackctl_internal jackctl_internal_t;
+
+/** opaque type for parameter object */
+typedef struct jackctl_parameter jackctl_parameter_t;
+
+typedef jackctl_server_t * jackctl_server;
+typedef jackctl_driver_t * jackctl_driver;
+typedef jackctl_internal_t * jackctl_internal;
+typedef jackctl_parameter_t * jackctl_parameter;
+
+typedef
+void *
+(* jackctl_client_appeared_callback)(
+	void * server_context,
+	uint64_t client_id,
+	const char * client_name);
+
+typedef
+void
+(* jackctl_client_disappeared_callback)(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context);
+
+typedef
+void *
+(* jackctl_port_appeared_callback)(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context,
+	uint64_t port_id,
+	const char * port_name,
+	uint32_t port_flags,
+	uint32_t port_type);
+
+typedef
+void
+(* jackctl_port_disappeared_callback)(
+	void * server_context,
+	uint64_t client_id,
+	void * client_context,
+	uint64_t port_id,
+	void * port_context);
+
+typedef
+void *
+(* jackctl_ports_connected_callback)(
+	void * server_context,
+	uint64_t client1_id,
+	void * client1_context,
+	uint64_t port1_id,
+	void * port1_context,
+	uint64_t client2_id,
+	void * client2_context,
+	uint64_t port2_id,
+	void * port2_context,
+	uint64_t connection_id);
+
+typedef
+void
+(* jackctl_ports_disconnected_callback)(
+	void * server_context,
+	uint64_t client1_id,
+	void * client1_context,
+	uint64_t port1_id,
+	void * port1_context,
+	uint64_t client2_id,
+	void * client2_context,
+	uint64_t port2_id,
+	void * port2_context,
+	uint64_t connection_id,
+	void * connection_context);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+} /* Adjust editor indent */
+#endif
+
+/** 
+ * Call this function to setup process signal handling. As a general
+ * rule, it is required for proper operation for the server object.
+ * 
+ * @param flags signals setup flags, use 0 for none. Currently no
+ * flags are defined
+ *
+ * @return the configurated signal set.
+ */
+sigset_t
+jackctl_setup_signals(
+    unsigned int flags);
+
+/** 
+ * Call this function to wait on a signal set.
+ * 
+ * @param signals signals set to wait on
+ */
+void
+jackctl_wait_signals(
+    sigset_t signals);
+
+/**
+ * Call this function to create server object.
+ *
+ * @return server object handle, NULL if creation of server object
+ * failed. Successfully created server object must be destroyed with
+ * paired call to ::jackctl_server_destroy
+ */
+jackctl_server_t *
+jackctl_server_create();
+
+/** 
+ * Call this function to destroy server object.
+ * 
+ * @param server server object handle to destroy
+ */
+void
+jackctl_server_destroy(
+	jackctl_server_t * server);
+
+/** 
+ * Call this function to get list of available drivers. List node data
+ * pointers is a driver object handle (::jackctl_driver_t).
+ * 
+ * @param server server object handle to get drivers for
+ *
+ * @return Single linked list of driver object handles. Must not be
+ * modified. Always same for same server object.
+ */
+const JSList *
+jackctl_server_get_drivers_list(
+	jackctl_server_t * server);
+
+/** 
+ * Call this function to start JACK server
+ * 
+ * @param server server object handle
+ * @param driver driver to use
+ * 
+ * @return success status: true - success, false - fail
+ */
+bool
+jackctl_server_start(
+    jackctl_server_t * server,
+    jackctl_driver_t * driver,
+    void * context,
+    jackctl_client_appeared_callback client_appeared_callback,
+    jackctl_client_disappeared_callback client_disappeared_callback,
+    jackctl_port_appeared_callback port_appeared_callback,
+    jackctl_port_disappeared_callback port_disappeared_callback,
+    jackctl_ports_connected_callback ports_connected_callback,
+    jackctl_ports_disconnected_callback ports_disconnected_callback);
+
+/** 
+ * Call this function to stop JACK server
+ * 
+ * @param server server object handle
+ * 
+ * @return success status: true - success, false - fail
+ */
+bool
+jackctl_server_stop(
+	jackctl_server_t * server);
+
+/** 
+ * Call this function to get list of server parameters. List node data
+ * pointers is a parameter object handle (::jackctl_parameter_t).
+ * 
+ * @param server server object handle to get parameters for
+ *
+ * @return Single linked list of parameter object handles. Must not be
+ * modified. Always same for same server object.
+ */
+const JSList *
+jackctl_server_get_parameters(
+	jackctl_server_t * server);
+
+/** 
+ * Call this function to get name of driver.
+ * 
+ * @param driver driver object handle to get name of
+ *
+ * @return driver name. Must not be modified. Always same for same
+ * driver object.
+ */
+const char *
+jackctl_driver_get_name(
+	jackctl_driver_t * driver);
+
+/** 
+ * Call this function to get list of driver parameters. List node data
+ * pointers is a parameter object handle (::jackctl_parameter_t).
+ * 
+ * @param driver driver object handle to get parameters for
+ *
+ * @return Single linked list of parameter object handles. Must not be
+ * modified. Always same for same driver object.
+ */
+const JSList *
+jackctl_driver_get_parameters(
+	jackctl_driver_t * driver);
+
+/** 
+ * Call this function to get parameter name.
+ * 
+ * @param parameter parameter object handle to get name of
+ *
+ * @return parameter name. Must not be modified. Always same for same
+ * parameter object.
+ */
+const char *
+jackctl_parameter_get_name(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to get parameter short description.
+ * 
+ * @param parameter parameter object handle to get short description of
+ *
+ * @return parameter short description. Must not be modified. Always
+ * same for same parameter object.
+ */
+const char *
+jackctl_parameter_get_short_description(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to get parameter long description.
+ * 
+ * @param parameter parameter object handle to get long description of
+ *
+ * @return parameter long description. Must not be modified. Always
+ * same for same parameter object.
+ */
+const char *
+jackctl_parameter_get_long_description(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to get parameter type.
+ * 
+ * @param parameter parameter object handle to get type of
+ *
+ * @return parameter type. Always same for same parameter object.
+ */
+jackctl_param_type_t
+jackctl_parameter_get_type(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to get parameter character.
+ * 
+ * @param parameter parameter object handle to get character of
+ *
+ * @return character. 
+ */
+char
+jackctl_parameter_get_id(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to check whether parameter has been set, or its
+ * default value is being used.
+ * 
+ * @param parameter parameter object handle to check
+ *
+ * @return true - parameter is set, false - parameter is using default
+ * value.
+ */
+bool
+jackctl_parameter_is_set(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to reset parameter to its default value.
+ * 
+ * @param parameter parameter object handle to reset value of
+ *
+ * @return success status: true - success, false - fail
+ */
+bool
+jackctl_parameter_reset(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to get parameter value.
+ * 
+ * @param parameter parameter object handle to get value of
+ *
+ * @return parameter value.
+ */
+union jackctl_parameter_value
+jackctl_parameter_get_value(
+	jackctl_parameter_t * parameter);
+
+/** 
+ * Call this function to set parameter value.
+ * 
+ * @param parameter parameter object handle to get value of
+ * @param value_ptr pointer to variable containing parameter value
+ *
+ * @return success status: true - success, false - fail
+ */
+bool
+jackctl_parameter_set_value(
+	jackctl_parameter_t * parameter,
+	const union jackctl_parameter_value * value_ptr);
+
+/** 
+ * Call this function to get parameter default value.
+ * 
+ * @param parameter parameter object handle to get default value of
+ *
+ * @return parameter default value.
+ */
+union jackctl_parameter_value
+jackctl_parameter_get_default_value(
+	jackctl_parameter_t * parameter);
+    
+/** 
+ * Call this function check whether parameter has range constraint.
+ * 
+ * @param parameter object handle of parameter to check
+ *
+ * @return whether parameter has range constraint.
+ */
+bool
+jackctl_parameter_has_range_constraint(
+	jackctl_parameter_t * parameter_ptr);
+
+/** 
+ * Call this function check whether parameter has enumeration constraint.
+ * 
+ * @param parameter object handle of parameter to check
+ *
+ * @return whether parameter has enumeration constraint.
+ */
+bool
+jackctl_parameter_has_enum_constraint(
+	jackctl_parameter_t * parameter_ptr);
+
+/** 
+ * Call this function get how many enumeration values parameter has.
+ * 
+ * @param parameter object handle of parameter
+ *
+ * @return number of enumeration values
+ */
+uint32_t
+jackctl_parameter_get_enum_constraints_count(
+	jackctl_parameter_t * parameter_ptr);
+
+/** 
+ * Call this function to get parameter enumeration value.
+ * 
+ * @param parameter object handle of parameter
+ * @param index index of parameter enumeration value
+ *
+ * @return enumeration value.
+ */
+union jackctl_parameter_value
+jackctl_parameter_get_enum_constraint_value(
+	jackctl_parameter_t * parameter_ptr,
+	uint32_t index);
+
+/** 
+ * Call this function to get parameter enumeration value description.
+ * 
+ * @param parameter object handle of parameter
+ * @param index index of parameter enumeration value
+ *
+ * @return enumeration value description.
+ */
+const char *
+jackctl_parameter_get_enum_constraint_description(
+	jackctl_parameter_t * parameter_ptr,
+	uint32_t index);
+
+/** 
+ * Call this function to get parameter range.
+ * 
+ * @param parameter object handle of parameter
+ * @param min_ptr pointer to variable receiving parameter minimum value
+ * @param max_ptr pointer to variable receiving parameter maximum value
+ */
+void
+jackctl_parameter_get_range_constraint(
+	jackctl_parameter_t * parameter_ptr,
+	union jackctl_parameter_value * min_ptr,
+	union jackctl_parameter_value * max_ptr);
+
+/** 
+ * Call this function to check whether parameter constraint is strict,
+ * i.e. whether supplying non-matching value will not work for sure.
+ * 
+ * @param parameter parameter object handle to check
+ *
+ * @return whether parameter constraint is strict.
+ */
+bool
+jackctl_parameter_constraint_is_strict(
+	jackctl_parameter_t * parameter_ptr);
+
+/** 
+ * Call this function to check whether parameter has fake values,
+ * i.e. values have no user meaningful meaning and only value
+ * description is meaningful to user.
+ * 
+ * @param parameter parameter object handle to check
+ *
+ * @return whether parameter constraint is strict.
+ */
+bool
+jackctl_parameter_constraint_is_fake_value(
+	jackctl_parameter_t * parameter_ptr);
+
+/** 
+ * Call this function to get list of available internal clients. List node data
+ * pointers is a internal client object handle (::jackctl_internal_t).
+ * 
+ * @param server server object handle to get internal clients for
+ *
+ * @return Single linked list of internal client object handles. Must not be
+ * modified. Always same for same server object.
+ */
+const JSList *
+jackctl_server_get_internals_list(
+	jackctl_server_t * server);
+
+/** 
+ * Call this function to get name of internal client.
+ * 
+ * @param internal internal object handle to get name of
+ *
+ * @return internal name. Must not be modified. Always same for same
+ * internal object.
+ */
+const char *
+jackctl_internal_get_name(
+	jackctl_internal_t * internal);
+
+/** 
+ * Call this function to get list of internal parameters. List node data
+ * pointers is a parameter object handle (::jackctl_parameter_t).
+ * 
+ * @param internal internal object handle to get parameters for
+ *
+ * @return Single linked list of parameter object handles. Must not be
+ * modified. Always same for same internal object.
+ */
+const JSList *
+jackctl_internal_get_parameters(
+	jackctl_internal_t * internal);
+
+/** 
+ * Call this function to load one internal client.
+ * 
+ * @param server server object handle
+ * @param internal internal to use
+ * 
+ * @return success status: true - success, false - fail
+ */
+bool
+jackctl_server_load_internal(
+    jackctl_server_t * server,
+    jackctl_internal_t * internal);
+
+/** 
+ * Call this function to unload one internal client.
+ * 
+ * @param server server object handle
+ * @param internal internal to unload
+ * 
+ * @return success status: true - success, false - fail
+ */
+bool
+jackctl_server_unload_internal(
+    jackctl_server_t * server,
+    jackctl_internal_t * internal);
+
+
+double jackctl_server_get_load(jackctl_server server);
+unsigned int jackctl_server_get_sample_rate(jackctl_server server);
+double jackctl_server_get_latency(jackctl_server server);
+unsigned int jackctl_server_get_buffer_size(jackctl_server server);
+bool jackctl_server_set_buffer_size(jackctl_server server, unsigned int nframes);
+bool jackctl_server_is_realtime(jackctl_server server);
+unsigned int jackctl_server_get_xruns(jackctl_server server);
+void jackctl_server_reset_xruns(jackctl_server server);
+int jackctl_get_client_pid(jackctl_server server, const char * name);
+
+bool
+jackctl_connect_ports_by_name(
+	jackctl_server server,
+	const char * client1_name,
+	const char * port1_name,
+	const char * client2_name,
+	const char * port2_name);
+
+bool
+jackctl_connect_ports_by_id(
+	jackctl_server server,
+	uint64_t port1_id,
+	uint64_t port2_id);
+
+bool
+jackctl_disconnect_ports_by_name(
+	jackctl_server server,
+	const char * client1_name,
+	const char * port1_name,
+	const char * client2_name,
+	const char * port2_name);
+
+bool
+jackctl_disconnect_ports_by_id(
+	jackctl_server server,
+	uint64_t port1_id,
+	uint64_t port2_id);
+
+bool
+jackctl_disconnect_ports_by_connection_id(
+	jackctl_server server,
+	uint64_t connection_id);
+
+#if 0
+{ /* Adjust editor indent */
+#endif
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED */
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackdbus.c jack1/jackd/jackdbus.c
--- jack1.old/jackd/jackdbus.c	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackdbus.c	2013-10-06 17:44:27.123302735 +0100
@@ -0,0 +1,894 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+    Copyright (C) 2008 Marc-Olivier Barre
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <dbus/dbus.h>
+
+#include <include/internal.h>
+
+#include "jackdbus.h"
+#include "jackcontroller.h"
+
+FILE *g_logfile;
+char *g_jackdbus_config_dir;
+size_t g_jackdbus_config_dir_len; /* without terminating '\0' char */
+char *g_jackdbus_log_dir;
+size_t g_jackdbus_log_dir_len; /* without terminating '\0' char */
+int g_exit_command;
+DBusConnection *g_connection;
+
+void
+jack_dbus_send_signal(
+	const char *sender_object_path,
+	const char *iface,
+	const char *signal_name,
+	int first_arg_type,
+	...)
+{
+	DBusMessage *message_ptr;
+	va_list ap;
+
+	va_start(ap, first_arg_type);
+
+	message_ptr = dbus_message_new_signal(sender_object_path, iface, signal_name);
+	if (message_ptr == NULL)
+	{
+		jack_error("dbus_message_new_signal() failed.");
+		goto exit;
+	}
+
+	if (!dbus_message_append_args_valist(message_ptr, first_arg_type, ap))
+	{
+		jack_error("dbus_message_append_args_valist() failed.");
+		goto unref;
+	}
+
+	/* Add message to outgoing message queue */
+	if (!dbus_connection_send(g_connection, message_ptr, NULL))
+	{
+		jack_error("dbus_connection_send() failed.");
+		goto unref;
+	}
+
+unref:
+	dbus_message_unref(message_ptr);
+
+exit:
+	va_end(ap);
+}
+
+/*
+ * Send a method return.
+ *
+ * If call->reply is NULL (i.e. a message construct method failed
+ * due to lack of memory) attempt to send a void method return.
+ */
+static
+void
+jack_dbus_send_method_return(
+	struct jack_dbus_method_call * call)
+{
+	if (call->reply)
+	{
+	retry_send:
+		if (!dbus_connection_send (call->connection, call->reply, NULL))
+		{
+			jack_error ("Ran out of memory trying to queue method return");
+		}
+
+		dbus_connection_flush (call->connection);
+		dbus_message_unref (call->reply);
+		call->reply = NULL;
+	}
+	else
+	{
+		jack_error ("send_method_return() called with a NULL message,"
+		            " trying to construct a void return...");
+
+		if ((call->reply = dbus_message_new_method_return (call->message)))
+		{
+			goto retry_send;
+		}
+		else
+		{
+			jack_error ("Failed to construct method return!");
+		}
+	}
+}
+
+#define object_ptr ((struct jack_dbus_object_descriptor *)data)
+
+/*
+ * The D-Bus message handler for object path /org/jackaudio/Controller.
+ */
+DBusHandlerResult
+jack_dbus_message_handler(
+	DBusConnection *connection,
+	DBusMessage *message,
+	void *data)
+{
+	struct jack_dbus_method_call call;
+	const char *interface_name;
+	struct jack_dbus_interface_descriptor ** interface_ptr_ptr;
+
+	/* Check if the message is a method call. If not, ignore it. */
+	if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+	{
+		goto handled;
+	}
+
+	/* Get the invoked method's name and make sure it's non-NULL. */
+	if (!(call.method_name = dbus_message_get_member (message)))
+	{
+		jack_dbus_error(
+			&call,
+			JACK_DBUS_ERROR_UNKNOWN_METHOD,
+			"Received method call with empty method name");
+		goto send_return;
+	}
+
+	/* Initialize our data. */
+	call.context = object_ptr->context;
+	call.connection = connection;
+	call.message = message;
+	call.reply = NULL;
+
+	/* Check if there's an interface specified for this method call. */
+	interface_name = dbus_message_get_interface (message);
+	if (interface_name != NULL)
+	{
+		/* Check if we can match the interface and method.
+		 * The inteface handler functions only return false if the
+		 * method name was unknown, otherwise they run the specified
+		 * method and return TRUE.
+		 */
+
+		interface_ptr_ptr = object_ptr->interfaces;
+
+		while (*interface_ptr_ptr != NULL)
+		{
+			if (strcmp(interface_name, (*interface_ptr_ptr)->name) == 0)
+			{
+				if (!(*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
+				{
+					break;
+				}
+
+				goto send_return;
+			}
+
+			interface_ptr_ptr++;
+		}
+	}
+	else
+	{
+		/* No interface was specified so we have to try them all. This is
+		 * dictated by the D-Bus specification which states that method calls
+		 * omitting the interface must never be rejected.
+		 */
+
+		interface_ptr_ptr = object_ptr->interfaces;
+
+		while (*interface_ptr_ptr != NULL)
+		{
+			if ((*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
+			{
+				goto send_return;
+			}
+
+			interface_ptr_ptr++;
+		}
+	}
+
+	jack_dbus_error(
+		&call,
+		JACK_DBUS_ERROR_UNKNOWN_METHOD,
+		"Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
+		call.method_name,
+		dbus_message_get_signature(message),
+		interface_name);
+
+send_return:
+	jack_dbus_send_method_return(&call);
+
+handled:
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+void
+jack_dbus_message_handler_unregister(
+	DBusConnection *connection,
+	void *data)
+{
+	jack_info ("Message handler was unregistered");
+}
+
+#undef object_ptr
+
+/*
+ * Check if the supplied method name exists in org.jackaudio.JackConfigure,
+ * if it does execute it and return TRUE. Otherwise return FALSE.
+ */
+bool
+jack_dbus_run_method(
+	struct jack_dbus_method_call *call,
+	const struct jack_dbus_interface_method_descriptor * methods)
+{
+	const struct jack_dbus_interface_method_descriptor * method_ptr;
+
+	method_ptr = methods;
+
+	while (method_ptr->name != NULL)
+	{
+		if (strcmp(call->method_name, method_ptr->name) == 0)
+		{
+			method_ptr->handler(call);
+			return TRUE;
+		}
+
+		method_ptr++;
+	}
+
+	return FALSE;
+}
+
+/*
+ * Read arguments from a method call.
+ * If the operation fails construct an error and return false,
+ * otherwise return true.
+ */
+bool
+jack_dbus_get_method_args(
+	struct jack_dbus_method_call *call,
+	int type,
+	...)
+{
+	va_list args;
+	DBusError error;
+	bool retval = true;
+
+	va_start (args, type);
+	dbus_error_init (&error);
+
+	if (!dbus_message_get_args_valist (call->message, &error, type, args))
+	{
+		jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
+		                 "Invalid arguments to method \"%s\"",
+		                 call->method_name);
+		retval = false;
+	}
+
+	dbus_error_free (&error);
+	va_end (args);
+
+	return retval;
+}
+
+/*
+ * Read a string and a variant argument from a method call.
+ * If the operation fails construct an error and return false,
+ * otherwise return true.
+ */
+bool
+jack_dbus_get_method_args_string_and_variant(
+	struct jack_dbus_method_call *call,
+	const char **arg1,
+	message_arg_t *arg2,
+	int *type_ptr)
+{
+	DBusMessageIter iter, sub_iter;
+
+	/* First we want a string... */
+	if (dbus_message_iter_init (call->message, &iter)
+	    && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
+	{
+		dbus_message_iter_get_basic (&iter, arg1);
+		dbus_message_iter_next (&iter);
+
+		/* ...and then a variant. */
+		if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
+		{
+			dbus_message_iter_recurse (&iter, &sub_iter);
+			dbus_message_iter_get_basic (&sub_iter, arg2);
+			*type_ptr = dbus_message_iter_get_arg_type (&sub_iter);
+
+			/* Got what we wanted. */
+			return true;
+		}
+	}
+
+	jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
+	                 "Invalid arguments to method \"%s\"",
+	                 call->method_name);
+
+	return false;
+}
+
+/*
+ * Append a variant type to a D-Bus message.
+ * Return false if something fails, true otherwise.
+ */
+bool
+jack_dbus_message_append_variant(
+	DBusMessageIter *iter,
+	int type,
+	const char *signature,
+	message_arg_t *arg)
+{
+	DBusMessageIter sub_iter;
+
+	/* Open a variant container. */
+	if (!dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, signature, &sub_iter))
+	{
+		goto fail;
+	}
+
+	/* Append the supplied value. */
+	if (!dbus_message_iter_append_basic (&sub_iter, type, (const void *) arg))
+	{
+		dbus_message_iter_close_container (iter, &sub_iter);
+		goto fail;
+	}
+
+	/* Close the container. */
+	if (!dbus_message_iter_close_container (iter, &sub_iter))
+	{
+		goto fail;
+	}
+
+	return true;
+
+fail:
+	return false;
+}
+
+/*
+ * Construct an empty method return message.
+ *
+ * The operation can only fail due to lack of memory, in which case
+ * there's no sense in trying to construct an error return. Instead,
+ * call->reply will be set to NULL and handled in send_method_return().
+ */
+void
+jack_dbus_construct_method_return_empty(
+	struct jack_dbus_method_call * call)
+{
+	call->reply = dbus_message_new_method_return (call->message);
+
+	if (call->reply == NULL)
+	{
+		jack_error ("Ran out of memory trying to construct method return");
+	}
+}
+
+/*
+ * Construct a method return which holds a single argument or, if
+ * the type parameter is DBUS_TYPE_INVALID, no arguments at all
+ * (a void message).
+ *
+ * The operation can only fail due to lack of memory, in which case
+ * there's no sense in trying to construct an error return. Instead,
+ * call->reply will be set to NULL and handled in send_method_return().
+ */
+void
+jack_dbus_construct_method_return_single(
+	struct jack_dbus_method_call *call,
+	int type,
+	message_arg_t arg)
+{
+	DBusMessageIter iter;
+	call->reply = dbus_message_new_method_return (call->message);
+
+	if (call->reply == NULL)
+	{
+		goto fail_no_mem;
+	}
+
+	/* Void method return requested by caller. */
+	if (type == DBUS_TYPE_INVALID)
+	{
+		return;
+	}
+
+	/* Prevent crash on NULL input string. */
+	else if (type == DBUS_TYPE_STRING && arg.string == NULL)
+	{
+		arg.string = "";
+	}
+
+	dbus_message_iter_init_append (call->reply, &iter);
+
+	if (!dbus_message_iter_append_basic (&iter, type, (const void *) &arg))
+	{
+		dbus_message_unref (call->reply);
+		call->reply = NULL;
+		goto fail_no_mem;
+	}
+
+	return;
+
+fail_no_mem:
+	jack_error ("Ran out of memory trying to construct method return");
+}
+
+/*
+ * Construct a method return which holds an array of strings.
+ *
+ * The operation can only fail due to lack of memory, in which case
+ * there's no sense in trying to construct an error return. Instead,
+ * call->reply will be set to NULL and handled in send_method_return().
+ */
+void
+jack_dbus_construct_method_return_array_of_strings(
+	struct jack_dbus_method_call *call,
+	unsigned int num_members,
+	const char **array)
+{
+	DBusMessageIter iter, sub_iter;
+	unsigned int i;
+
+	call->reply = dbus_message_new_method_return (call->message);
+	if (!call->reply)
+	{
+		goto fail;
+	}
+
+	dbus_message_iter_init_append (call->reply, &iter);
+
+	if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
+	{
+		goto fail_unref;
+	}
+
+	for (i = 0; i < num_members; ++i)
+	{
+		if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, (const void *) &array[i]))
+		{
+			dbus_message_iter_close_container (&iter, &sub_iter);
+			goto fail_unref;
+		}
+	}
+
+	if (!dbus_message_iter_close_container (&iter, &sub_iter))
+	{
+		goto fail_unref;
+	}
+
+	return;
+
+fail_unref:
+	dbus_message_unref (call->reply);
+	call->reply = NULL;
+
+fail:
+	jack_error ("Ran out of memory trying to construct method return");
+}
+
+void 
+jack_dbus_info_callback(const char *msg)
+{
+	time_t timestamp;
+	char timestamp_str[26];
+
+	time(&timestamp);
+	ctime_r(&timestamp, timestamp_str);
+	timestamp_str[24] = 0;
+
+	fprintf(g_logfile, "%s: %s\n", timestamp_str, msg);
+	fflush(g_logfile);
+}
+
+void 
+jack_dbus_error_callback(const char *msg)
+{
+	time_t timestamp;
+	char timestamp_str[26];
+
+	time(&timestamp);
+	ctime_r(&timestamp, timestamp_str);
+	timestamp_str[24] = 0;
+
+	fprintf(g_logfile, "%s: ERROR: %s\n", timestamp_str, msg);
+	fflush(g_logfile);
+}
+
+bool
+ensure_dir_exist(const char *dirname, int mode)
+{
+    struct stat st;
+    if (stat(dirname, &st) != 0)
+    {
+        if (errno == ENOENT)
+        {
+            printf("Directory \"%s\" does not exist. Creating...\n", dirname);
+            if (mkdir(dirname, mode) != 0)
+            {
+                fprintf(stderr, "Failed to create \"%s\" directory: %d (%s)\n", dirname, errno, strerror(errno));
+                return false;
+            }
+        }
+        else
+        {
+            fprintf(stderr, "Failed to stat \"%s\": %d (%s)\n", dirname, errno, strerror(errno));
+            return false;
+        }
+    }
+    else
+    {
+        if (!S_ISDIR(st.st_mode))
+        {
+            fprintf(stderr, "\"%s\" exists but is not directory.\n", dirname);
+            return false;
+        }
+    }
+    return true;
+}
+
+char *
+pathname_cat(const char *pathname_a, const char *pathname_b)
+{
+    char *pathname;
+    int pathname_a_len, pathname_b_len, pathname_len;
+    pathname_a_len = strlen(pathname_a);
+    pathname_b_len = strlen(pathname_b);
+    pathname = malloc(pathname_a_len + pathname_b_len + 1);
+    if (pathname == NULL)
+    {
+        fprintf(stderr, "Out of memory\n");
+        return NULL;
+    }
+    memcpy(pathname, pathname_a, pathname_a_len);
+    memcpy(pathname + pathname_a_len, pathname_b, pathname_b_len);
+    pathname_len = pathname_a_len + pathname_b_len;
+    pathname[pathname_len] = 0;
+    return pathname;
+}
+
+bool
+paths_init()
+{
+	const char *home_dir, *xdg_config_home, *xdg_log_home;
+    
+    home_dir = getenv("HOME");
+    if (home_dir == NULL)
+    {
+        fprintf(stderr, "Environment variable HOME not set\n");
+        goto fail;
+    }
+
+	xdg_config_home = getenv("XDG_CONFIG_HOME");
+	if (xdg_config_home == NULL)
+	{
+	    if (!(xdg_config_home = pathname_cat(home_dir, DEFAULT_XDG_CONFIG))) goto fail;
+	}
+
+    if (!(xdg_log_home = pathname_cat(home_dir, DEFAULT_XDG_LOG))) goto fail;
+
+	if (!(g_jackdbus_config_dir = pathname_cat(xdg_config_home, JACKDBUS_DIR))) goto fail;
+	if (!(g_jackdbus_log_dir = pathname_cat(xdg_log_home, JACKDBUS_DIR))) goto fail;
+
+    if (!ensure_dir_exist(xdg_config_home, 0700))
+    {
+        goto fail;
+    }
+    
+    if (!ensure_dir_exist(xdg_log_home, 0700))
+    {
+        goto fail;
+    }
+
+    if (!ensure_dir_exist(g_jackdbus_config_dir, 0700))
+    {
+        free(g_jackdbus_config_dir);
+        goto fail;
+    }
+    g_jackdbus_config_dir_len = strlen(g_jackdbus_config_dir);
+    
+    if (!ensure_dir_exist(g_jackdbus_log_dir, 0700))
+    {
+        free(g_jackdbus_log_dir);
+        goto fail;
+    }
+    g_jackdbus_log_dir_len = strlen(g_jackdbus_log_dir);
+
+    return true;
+
+fail:
+    return false;
+}
+
+void
+paths_uninit()
+{
+    free(g_jackdbus_config_dir);
+    free(g_jackdbus_log_dir);
+}
+
+int
+log_init()
+{
+    char *log_filename;
+    size_t log_len;
+
+    log_len = strlen(JACKDBUS_LOG);
+
+    log_filename = malloc(g_jackdbus_log_dir_len + log_len + 1);
+    if (log_filename == NULL)
+    {
+        fprintf(stderr, "Out of memory\n");
+        return FALSE;
+    }
+
+    memcpy(log_filename, g_jackdbus_log_dir, g_jackdbus_log_dir_len);
+    memcpy(log_filename + g_jackdbus_log_dir_len, JACKDBUS_LOG, log_len);
+    log_filename[g_jackdbus_log_dir_len + log_len] = 0;
+
+    g_logfile = fopen(log_filename, "a");
+    if (g_logfile == NULL)
+    {
+        fprintf(stderr, "Cannot open jackdbus log file \"%s\": %d (%s)\n", log_filename, errno, strerror(errno));
+        free(log_filename);
+        return FALSE;
+    }
+
+    free(log_filename);
+
+    return TRUE;
+}
+
+void
+log_uninit()
+{
+    fclose(g_logfile);
+}
+
+void
+jack_dbus_error(
+	void *dbus_call_context_ptr,
+	const char *error_name,
+	const char *format,
+	...)
+{
+	va_list ap;
+	char buffer[300];
+
+	va_start(ap, format);
+
+	vsnprintf(buffer, sizeof(buffer), format, ap);
+
+	jack_error_callback(buffer);
+	if (dbus_call_context_ptr != NULL)
+	{
+		((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
+			((struct jack_dbus_method_call *)dbus_call_context_ptr)->message,
+			error_name,
+			buffer);
+	}
+
+	va_end(ap);
+}
+
+static void 
+do_nothing_handler (int sig)
+{
+	/* this is used by the child (active) process, but it never
+	   gets called unless we are already shutting down after
+	   another signal.
+	*/
+	char buf[64];
+	snprintf (buf, sizeof(buf),
+		  "received signal %d during shutdown (ignored)\n", sig);
+	write (1, buf, strlen (buf));
+}
+
+void
+do_signal_magic()
+{
+	sigset_t signals;
+	sigset_t allsignals;
+	struct sigaction action;
+	int i;
+
+	/* ensure that we are in our own process group so that
+	   kill (SIG, -pgrp) does the right thing.
+	*/
+
+	setsid();
+
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+	/* what's this for?
+
+	   POSIX says that signals are delivered like this:
+
+	   * if a thread has blocked that signal, it is not
+	       a candidate to receive the signal.
+           * of all threads not blocking the signal, pick
+	       one at random, and deliver the signal.
+
+           this means that a simple-minded multi-threaded program can
+           expect to get POSIX signals delivered randomly to any one
+           of its threads,
+
+	   here, we block all signals that we think we might receive
+	   and want to catch. all "child" threads will inherit this
+	   setting. if we create a thread that calls sigwait() on the
+	   same set of signals, implicitly unblocking all those
+	   signals. any of those signals that are delivered to the
+	   process will be delivered to that thread, and that thread
+	   alone. this makes cleanup for a signal-driven exit much
+	   easier, since we know which thread is doing it and more
+	   importantly, we are free to call async-unsafe functions,
+	   because the code is executing in normal thread context
+	   after a return from sigwait().
+	*/
+
+	sigemptyset(&signals);
+	sigaddset(&signals, SIGHUP);
+	sigaddset(&signals, SIGINT);
+	sigaddset(&signals, SIGQUIT);
+	sigaddset(&signals, SIGPIPE);
+	sigaddset(&signals, SIGTERM);
+	sigaddset(&signals, SIGUSR1);
+	sigaddset(&signals, SIGUSR2);
+
+	/* all child threads will inherit this mask unless they
+	 * explicitly reset it 
+	 */
+
+	pthread_sigmask (SIG_BLOCK, &signals, 0);
+
+	/* install a do-nothing handler because otherwise pthreads
+	   behaviour is undefined when we enter sigwait.
+	*/
+
+	sigfillset (&allsignals);
+	action.sa_handler = do_nothing_handler;
+	action.sa_mask = allsignals;
+	action.sa_flags = SA_RESTART|SA_RESETHAND;
+
+	for (i = 1; i < NSIG; i++) {
+		if (sigismember (&signals, i)) {
+			sigaction (i, &action, 0);
+		} 
+	}
+}
+
+int
+main (int argc, char **argv)
+{
+	DBusError error;
+	int ret;
+        void *controller_ptr;
+
+	if (!jack_controller_settings_init())
+	{
+		ret = 1;
+		goto fail;
+	}
+
+	if (argc != 2 || strcmp(argv[1], "auto") != 0)
+	{
+		ret = 0;
+		fprintf(
+			stderr,
+			"jackdbus should be auto-executed by D-Bus message bus daemon.\n"
+			"If you want to run it manually anyway, specify \"auto\" as only parameter\n");
+		goto fail_uninit_xml;
+	}
+
+	if (!paths_init())
+	{
+		ret = 1;
+		goto fail_uninit_xml;
+	}
+
+	if (!log_init())
+	{
+		ret = 1;
+		goto fail_uninit_paths;
+	}
+
+#if !defined(DISABLE_SIGNAL_MAGIC)
+	do_signal_magic();
+#endif
+
+	jack_set_error_function(jack_dbus_error_callback);
+	jack_set_info_function(jack_dbus_info_callback);
+
+	jack_info("------------------");
+	jack_info("Controller activated. Version " VERSION);
+
+	if (!dbus_threads_init_default())
+	{
+		jack_error("dbus_threads_init_default() failed");
+		ret = 1;
+		goto fail_uninit_log;
+	}
+
+	dbus_error_init (&error);
+	g_connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
+	if (dbus_error_is_set (&error))
+	{
+		jack_error("Cannot connect to D-Bus session bus: %s", error.message);
+		ret = 1;
+		goto fail_uninit_log;
+	}
+
+	ret = dbus_bus_request_name(
+                g_connection,
+                "org.jackaudio.service",
+                DBUS_NAME_FLAG_DO_NOT_QUEUE,
+                &error);
+	if (ret == -1)
+	{
+		jack_error("Cannot request service name: %s", error.message);
+                dbus_error_free(&error);
+		ret = 1;
+		goto fail_unref_connection;
+	}
+	else if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
+	{
+		jack_error("Requested D-Bus service name already exists");
+		ret = 1;
+		goto fail_unref_connection;
+	}
+
+	controller_ptr = jack_controller_create(g_connection);
+
+	if (controller_ptr == NULL)
+	{
+		ret = 1;
+		goto fail_unref_connection;
+	}
+
+	jack_info("Listening for D-Bus messages");
+
+	g_exit_command = FALSE;
+	while (!g_exit_command && dbus_connection_read_write_dispatch (g_connection, 200));
+
+	jack_controller_destroy(controller_ptr);
+
+	jack_info("Controller deactivated.");
+
+	ret = 0;
+
+fail_unref_connection:
+	dbus_connection_unref(g_connection);
+
+fail_uninit_log:
+	log_uninit();
+
+fail_uninit_paths:
+	paths_uninit();
+
+fail_uninit_xml:
+	jack_controller_settings_uninit();
+
+fail:
+	return ret;
+}
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/jackdbus.h jack1/jackd/jackdbus.h
--- jack1.old/jackd/jackdbus.h	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/jackdbus.h	2013-10-06 17:44:19.788394434 +0100
@@ -0,0 +1,312 @@
+/* -*- mode: c; c-file-style: "bsd"; -*- */
+/*
+    Copyright (C) 2007,2008 Nedko Arnaudov
+    Copyright (C) 2007-2008 Juuso Alasuutari
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef JACKDBUS_H__3DB2458F_44B2_43EA_882A_9F888DF71A88__INCLUDED
+#define JACKDBUS_H__3DB2458F_44B2_43EA_882A_9F888DF71A88__INCLUDED
+
+#include <stdbool.h>
+
+#define JACK_DBUS_DEBUG
+
+//#define DISABLE_SIGNAL_MAGIC
+
+#define DEFAULT_XDG_CONFIG "/.config"
+#define DEFAULT_XDG_LOG "/.log"
+#define JACKDBUS_DIR "/jack"
+#define JACKDBUS_LOG "/jackdbus.log"
+#define JACKDBUS_CONF "/conf-jack1.xml"
+
+extern char *g_jackdbus_config_dir;
+extern size_t g_jackdbus_config_dir_len; /* without terminating '\0' char */
+extern int g_exit_command;
+
+bool
+jack_controller_settings_init();
+
+void
+jack_controller_settings_uninit();
+
+#define JACK_DBUS_ERROR_UNKNOWN_METHOD              "org.jackaudio.Error.UnknownMethod"
+#define JACK_DBUS_ERROR_SERVER_NOT_RUNNING          "org.jackaudio.Error.ServerNotRunning"
+#define JACK_DBUS_ERROR_UNKNOWN_DRIVER              "org.jackaudio.Error.UnknownDriver"
+#define JACK_DBUS_ERROR_UNKNOWN_INTERNAL            "org.jackaudio.Error.UnknownInternal"
+#define JACK_DBUS_ERROR_UNKNOWN_PARAMETER           "org.jackaudio.Error.UnknownParameter"
+#define JACK_DBUS_ERROR_INVALID_ARGS                "org.jackaudio.Error.InvalidArgs"
+#define JACK_DBUS_ERROR_GENERIC                     "org.jackaudio.Error.Generic"
+#define JACK_DBUS_ERROR_FATAL                       "org.jackaudio.Error.Fatal"
+
+struct jack_dbus_method_call
+{
+	void *context;
+	DBusConnection *connection;
+	const char *method_name;
+	DBusMessage *message;
+	DBusMessage *reply;
+};
+
+struct jack_dbus_interface_method_argument_descriptor
+{
+	const char * name;
+	const char * type;
+	bool direction_out;		/* true - out, false - in */
+};
+
+struct jack_dbus_interface_method_descriptor
+{
+	const char * name;
+	const struct jack_dbus_interface_method_argument_descriptor * arguments;
+	void (* handler)(struct jack_dbus_method_call * call);
+};
+
+struct jack_dbus_interface_signal_argument_descriptor
+{
+	const char * name;
+	const char * type;
+};
+
+struct jack_dbus_interface_signal_descriptor
+{
+	const char * name;
+	const struct jack_dbus_interface_signal_argument_descriptor * arguments;
+};
+
+struct jack_dbus_interface_descriptor
+{
+	const char * name;
+
+	bool
+	(* handler)(
+		struct jack_dbus_method_call * call,
+		const struct jack_dbus_interface_method_descriptor * methods);
+
+	const struct jack_dbus_interface_method_descriptor * methods;
+	const struct jack_dbus_interface_signal_descriptor * signals;
+};
+
+struct jack_dbus_object_descriptor
+{
+	struct jack_dbus_interface_descriptor ** interfaces;
+	void * context;
+};
+
+typedef union
+{
+	unsigned char byte;
+	dbus_bool_t boolean;
+	dbus_int16_t int16;
+	dbus_uint16_t uint16;
+	dbus_int32_t int32;
+	dbus_uint32_t uint32;
+	dbus_int64_t int64;
+	dbus_uint64_t uint64;
+	double doubl;
+	const char *string;
+} message_arg_t;
+
+#define JACK_DBUS_METHOD_ARGUMENTS_BEGIN(method_name)                                   \
+static                                                                                  \
+struct jack_dbus_interface_method_argument_descriptor method_name ## _arguments[] =     \
+{
+
+#define JACK_DBUS_METHOD_ARGUMENTS_BEGIN_EX(method_name, descr)                         \
+static const                                                                            \
+struct jack_dbus_interface_method_argument_descriptor method_name ## _arguments[] =     \
+{
+
+#define JACK_DBUS_METHOD_ARGUMENT(argument_name, argument_type, argument_direction_out) \
+        {                                                                               \
+                .name = argument_name,                                                  \
+                .type = argument_type,                                                  \
+                .direction_out = argument_direction_out                                 \
+        },
+
+#define JACK_DBUS_METHOD_ARGUMENT_IN(argument_name, argument_type, descr)               \
+        {                                                                               \
+                .name = argument_name,                                                  \
+                .type = argument_type,                                                  \
+                .direction_out = false                                                  \
+        },
+
+#define JACK_DBUS_METHOD_ARGUMENT_OUT(argument_name, argument_type, descr)              \
+        {                                                                               \
+                .name = argument_name,                                                  \
+                .type = argument_type,                                                  \
+                .direction_out = true                                                   \
+        },
+
+#define JACK_DBUS_METHOD_ARGUMENTS_END                                                  \
+	JACK_DBUS_METHOD_ARGUMENT(NULL, NULL, false)                                    \
+};
+
+#define JACK_DBUS_METHODS_BEGIN                                                         \
+static const                                                                            \
+struct jack_dbus_interface_method_descriptor methods_dtor[] =                           \
+{
+
+#define JACK_DBUS_METHOD_DESCRIBE(method_name, handler_name)                            \
+        {                                                                               \
+            .name = # method_name,                                                      \
+            .arguments = method_name ## _arguments,                                     \
+            .handler = handler_name                                                     \
+        },
+
+#define JACK_DBUS_METHODS_END                                                           \
+        {                                                                               \
+            .name = NULL,                                                               \
+            .arguments = NULL,                                                          \
+            .handler = NULL                                                             \
+        }                                                                               \
+};
+
+/* TODO: this should go away, JACK_DBUS_METHODS_END should be used instead */
+#define JACK_DBUS_METHOD_DESCRIBE_END                                                   \
+	{                                                                               \
+		.name = NULL,                                                           \
+		.arguments = NULL,                                                      \
+		.handler = NULL                                                         \
+	}
+
+#define JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(signal_name)                                   \
+static                                                                                  \
+struct jack_dbus_interface_signal_argument_descriptor signal_name ## _arguments[] =     \
+{
+
+#define JACK_DBUS_SIGNAL_ARGUMENT(argument_name, argument_type)                         \
+        {                                                                               \
+                .name = argument_name,                                                  \
+                .type = argument_type                                                   \
+        },
+
+#define JACK_DBUS_SIGNAL_ARGUMENTS_END                                                  \
+        JACK_DBUS_SIGNAL_ARGUMENT(NULL, NULL)                                           \
+};
+
+#define JACK_DBUS_SIGNAL_DESCRIBE(signal_name)                                          \
+        {                                                                               \
+                .name = # signal_name,                                                  \
+                .arguments = signal_name ## _arguments                                  \
+        },
+
+#define JACK_DBUS_SIGNAL_DESCRIBE_END                                                   \
+        {                                                                               \
+                .name = NULL,                                                           \
+                .arguments = NULL,                                                      \
+        }
+
+#define JACK_DBUS_IFACE_BEGIN(iface_var, iface_name)                                    \
+struct jack_dbus_interface_descriptor iface_var =                                       \
+{                                                                                       \
+        .name = iface_name,                                                             \
+        .handler = jack_dbus_run_method,
+
+#define JACK_DBUS_IFACE_HANDLER(handler_func)                                           \
+        .handler = handler_func,
+
+#define JACK_DBUS_IFACE_EXPOSE_METHODS                                                  \
+        .methods = methods_dtor,
+
+#define JACK_DBUS_IFACE_EXPOSE_SIGNALS                                                  \
+        .signals = signals_dtor,
+
+#define JACK_DBUS_IFACE_END                                                             \
+};
+
+/* TODO: this should go away, other JACK_DBUS_IFACE_XXX should be used instead */
+#define JACK_DBUS_IFACE_DESCRIBE(iface_var, iface_name, iface_methods, iface_signals)   \
+struct jack_dbus_interface_descriptor iface_var =                                       \
+{                                                                                       \
+        .name = iface_name,                                                             \
+        .handler = jack_dbus_run_method,                                                \
+        .methods = iface_methods,                                                       \
+        .signals = iface_signals                                                        \
+}
+
+DBusHandlerResult
+jack_dbus_message_handler(
+	DBusConnection *connection,
+	DBusMessage *message,
+	void *data);
+
+void
+jack_dbus_message_handler_unregister(
+	DBusConnection *connection,
+	void *data);
+
+bool
+jack_dbus_run_method(
+	struct jack_dbus_method_call * call,
+	const struct jack_dbus_interface_method_descriptor * methods);
+
+void
+jack_dbus_error(
+	void *dbus_call_context_ptr,
+	const char *error_name,
+	const char *format,
+	...);
+
+bool
+jack_dbus_get_method_args(
+	struct jack_dbus_method_call *call,
+	int type,
+	...);
+
+bool
+jack_dbus_get_method_args_string_and_variant(
+	struct jack_dbus_method_call *call,
+	const char **arg1,
+	message_arg_t *arg2,
+	int *type_ptr);
+
+bool
+jack_dbus_message_append_variant(
+	DBusMessageIter *iter,
+	int type,
+	const char *signature,
+	message_arg_t *arg);
+
+void
+jack_dbus_construct_method_return_empty(
+	struct jack_dbus_method_call * call);
+
+void
+jack_dbus_construct_method_return_single(
+	struct jack_dbus_method_call *call,
+	int type,
+	message_arg_t arg);
+
+void
+jack_dbus_construct_method_return_array_of_strings(
+	struct jack_dbus_method_call *call,
+	unsigned int num_members,
+	const char **array);
+
+void
+jack_dbus_send_signal(
+	const char *sender_object_path,
+	const char *iface,
+	const char *signal_name,
+	int first_arg_type,
+	...);
+
+#define JACK_CONTROLLER_OBJECT_PATH "/org/jackaudio/Controller"
+
+extern struct jack_dbus_interface_descriptor * g_jackcontroller_interfaces[];
+
+#endif /* #ifndef JACKDBUS_H__3DB2458F_44B2_43EA_882A_9F888DF71A88__INCLUDED */
diff -U 3 -H -b -d -r -N -- jack1.old/jackd/org.jackaudio.service.in jack1/jackd/org.jackaudio.service.in
--- jack1.old/jackd/org.jackaudio.service.in	1970-01-01 01:00:00.000000000 +0100
+++ jack1/jackd/org.jackaudio.service.in	2013-10-06 17:44:19.789394421 +0100
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.jackaudio.service
+Exec=@bindir@/jackdbus auto
diff -U 3 -H -b -d -r -N -- jack1.old/libjack/Makefile.am jack1/libjack/Makefile.am
--- jack1.old/libjack/Makefile.am	2013-10-06 16:46:26.000000000 +0100
+++ jack1/libjack/Makefile.am	2013-10-06 17:44:19.791394396 +0100
@@ -32,12 +32,13 @@
 
 noinst_HEADERS	= local.h
 
-AM_CFLAGS = $(JACK_CFLAGS) -DJACK_LOCATION=\"$(bindir)\"
+AM_CFLAGS = $(JACK_CFLAGS) $(DBUS_CFLAGS) -DJACK_LOCATION=\"$(bindir)\"
 AM_CXXFLAGS = $(JACK_CFLAGS)
 
 libjack_la_CFLAGS = $(AM_CFLAGS)
 
 libjack_la_SOURCES = $(SOURCE_FILES)
-libjack_la_LIBADD  = simd.lo -ldb @OS_LDFLAGS@
+libjack_la_LIBADD  = simd.lo -ldb @OS_LDFLAGS@ $(DBUS_LIBS)
 libjack_la_LDFLAGS  = -export-dynamic -version-info @JACK_SO_VERSION@
 
+libjack_la_LIBS = $(DBUS_LIBS)
diff -U 3 -H -b -d -r -N -- jack1.old/libjack/client.c jack1/libjack/client.c
--- jack1.old/libjack/client.c	2013-10-06 16:46:26.000000000 +0100
+++ jack1/libjack/client.c	2013-10-06 17:44:19.796394334 +0100
@@ -64,6 +64,17 @@
 #include <sysdeps/pThreadUtilities.h>
 #endif
 
+/* There is no point in attempting to start JACK server from libjackserver. */
+#if HAVE_DBUS
+#if defined(LIBJACKSERVER)
+#undef HAVE_DBUS
+#endif
+#endif
+
+#if HAVE_DBUS
+#include <dbus/dbus.h>
+#endif
+
 static pthread_mutex_t client_lock;
 static pthread_cond_t  client_ready;
 
@@ -846,6 +857,50 @@
 	return fd;
 }
 
+#if HAVE_DBUS
+static void
+start_server_dbus()
+{
+	DBusError err;
+	DBusConnection *conn;
+	DBusMessage *msg;
+
+	// initialise the errors
+	dbus_error_init(&err);
+
+	// connect to the bus
+	conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
+	if (dbus_error_is_set(&err)) {
+		fprintf(stderr, "Connection Error (%s)\n", err.message);
+		dbus_error_free(&err);
+	}
+	if (NULL == conn) {
+		exit(1);
+	}
+
+	msg = dbus_message_new_method_call(
+		"org.jackaudio.service",     // target for the method call
+		"/org/jackaudio/Controller", // object to call on
+		"org.jackaudio.JackControl", // interface to call on
+		"StartServer");              // method name
+	if (NULL == msg) {
+		fprintf(stderr, "Message Null\n");
+		exit(1);
+	}
+
+	// send message and get a handle for a reply
+	if (!dbus_connection_send(conn, msg, NULL))
+	{
+		fprintf(stderr, "Out Of Memory!\n");
+		exit(1);
+	}
+
+	dbus_message_unref(msg);
+	dbus_connection_flush(conn);
+	dbus_error_free(&err);
+}
+#endif
+
 /* Exec the JACK server in this process.  Does not return. */
 static void
 _start_server (const char *server_name)
@@ -1030,6 +1085,24 @@
 	
 	if ((*req_fd = server_connect (va->server_name)) < 0) {
 		int trys;
+#if HAVE_DBUS
+		if ((options & JackNoStartServer)
+		    || getenv("JACK_NO_START_SERVER")) {
+				*status |= (JackFailure|JackServerFailed);
+				goto fail;
+		}
+
+		start_server_dbus();
+		trys = 5;
+		do {
+			sleep(1);
+			if (--trys < 0) {
+				*status |= (JackFailure|JackServerFailed);
+				goto fail;
+			}
+		} while ((*req_fd = server_connect (va->server_name)) < 0);
+		*status |= JackServerStarted;
+#else
 		if (start_server(va->server_name, options)) {
 			*status |= (JackFailure|JackServerFailed);
 			goto fail;
@@ -1043,6 +1116,7 @@
 			}
 		} while ((*req_fd = server_connect (va->server_name)) < 0);
 		*status |= JackServerStarted;
+#endif
 	}
 
 	/* format connection request */
@@ -1274,6 +1348,8 @@
 	client->control = (jack_client_control_t *)
 		jack_shm_addr (&client->control_shm);
 
+	client->control->pid = getpid();
+
 	/* Nobody else needs to access this shared memory any more, so
 	 * destroy it.  Because we have it attached, it won't vanish
 	 * till we exit (and release it).
diff -U 3 -H -b -d -r -N -- jack1.old/tools/Makefile.am jack1/tools/Makefile.am
--- jack1.old/tools/Makefile.am	2013-10-06 16:47:09.000000000 +0100
+++ jack1/tools/Makefile.am	2013-10-06 17:44:19.797394321 +0100
@@ -53,6 +53,10 @@
 	       $(JACK_TRANSPORT) \
 	       $(NETJACK_TOOLS)
 
+if HAVE_DBUS
+dist_bin_SCRIPTS = jack_control
+endif
+
 noinst_PROGRAMS = jack_thread_wait
 
 if HAVE_SNDFILE
diff -U 3 -H -b -d -r -N -- jack1.old/tools/jack_control jack1/tools/jack_control
--- jack1.old/tools/jack_control	1970-01-01 01:00:00.000000000 +0100
+++ jack1/tools/jack_control	2013-10-06 17:44:19.798394309 +0100
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+
+name_base = 'org.jackaudio'
+control_interface_name = name_base + '.JackControl'
+configure_interface_name = name_base + '.Configure'
+service_name = name_base + '.service'
+
+import sys
+import os
+from traceback import print_exc
+
+import dbus
+
+def bool_convert(str_value):
+    if str_value.lower() == "false":
+        return False
+
+    if str_value.lower() == "off":
+        return False
+
+    if str_value.lower() == "no":
+        return False
+
+    if str_value == "0":
+        return False
+
+    if str_value.lower() == "(null)":
+        return False
+
+    return bool(str_value)
+
+def dbus_type_to_python_type(dbus_value):
+    if type(dbus_value) == dbus.Boolean:
+        return bool(dbus_value)
+    if type(dbus_value) == dbus.Int32 or type(dbus_value) == dbus.UInt32:
+        return int(dbus_value)
+    return dbus_value
+
+def python_type_to_jackdbus_type(value, type_char):
+    type_char = str(type_char)
+
+    if type_char == "b":
+        return bool_convert(value);
+    elif type_char == "y":
+        return dbus.Byte(value);
+    elif type_char == "i":
+        return dbus.Int32(value)
+    elif type_char == "u":
+        return dbus.UInt32(value)
+
+    return value
+
+def dbus_type_to_type_string(dbus_value):
+    if type(dbus_value) == dbus.Boolean:
+        return "bool"
+    if type(dbus_value) == dbus.Int32:
+        return "sint"
+    if type(dbus_value) == dbus.UInt32:
+        return "uint"
+    if type(dbus_value) == dbus.Byte:
+        return "char"
+    if type(dbus_value) == dbus.String:
+        return "str"
+
+    return None                         # throw exception here?
+
+def dbus_typesig_to_type_string(type_char):
+    type_char = str(type_char)
+    if type_char == 'i':
+        return "sint"
+    if type_char == 'u':
+        return "uint"
+    if type_char == 'y':
+        return "char"
+    if type_char == 's':
+        return "str"
+    if type_char == 'b':
+        return "bool"
+
+    print 'shit'
+    return None                         # throw exception here?
+
+def get_parameters(iface, path):
+    params = iface.GetParametersInfo(path)
+                
+    #print params
+    for param in params:
+        typestr = dbus_typesig_to_type_string(param[0])
+        name = param[1]
+        #print name
+        descr = param[2]
+        #print descr
+        isset, default, value = iface.GetParameterValue(path + [name])
+        #print typestr
+        if bool(isset):
+            isset = "set"
+        else:
+            isset = "notset"
+        value = dbus_type_to_python_type(value)
+        default = dbus_type_to_python_type(default)
+
+        print "%20s: %s (%s:%s:%s:%s)" %(name, descr, typestr, isset, default, value)
+
+def main():
+    if len(sys.argv) == 1:
+        print "Usage: %s [command] [command] ..." % os.path.basename(sys.argv[0])
+        print "Commands:"
+        print "    exit                       - exit jack dbus service (stops jack server if currently running)"
+        print "    status                     - check whether jack server is started, return value is 0 if runing and 1 otherwise"
+        print "    start                      - start jack server if not currently started"
+        print "    stop                       - stop jack server if currenly started"
+        print "    dl                         - get list of available drivers"
+        print "    dg                         - get currently selected driver"
+        print "    ds <driver>                - select driver"
+        print "    dp                         - get parameters of currently selected driver"
+        print "    dpd <param>                - get long description for driver parameter"
+        print "    dps <param> <value>        - set driver parameter"
+        print "    il                         - get list of available internals"
+        print "    ip <name>                  - get parameters of given internal"
+        print "    ipd <name> <param>         - get long description for internal parameter"
+        print "    ips <name> <param> <value> - set internal parameter"
+        print "    iload <name>               - load internal"
+        print "    iunload <name>             - unload internal"
+        print "    ep                         - get engine parameters"
+        print "    epd <param>                - get long description for engine parameter"
+        print "    eps <param> <value>        - set engine parameter"
+        sys.exit(0)
+    
+    bus = dbus.SessionBus()
+
+    controller = bus.get_object(service_name, "/org/jackaudio/Controller")
+    control_iface = dbus.Interface(controller, control_interface_name)
+    configure_iface = dbus.Interface(controller, configure_interface_name)
+
+    # check arguments
+    index = 1
+    while index < len(sys.argv):
+        arg = sys.argv[index]
+        index += 1
+        try:
+            if arg == "exit":
+                print "--- exit"
+                control_iface.Exit()
+            elif arg == "status":
+                print "--- status"
+                if control_iface.IsStarted():
+                    print "started"
+                    sys.exit(0)
+                else:
+                    print "stopped"
+                    sys.exit(1)
+            elif arg == 'start':
+                print "--- start"
+                control_iface.StartServer()
+            elif arg == 'stop':
+                print "--- stop"
+                control_iface.StopServer()
+            elif arg == 'ism':
+                if control_iface.IsManuallyActivated():
+                    print "Manually activated"
+                else:
+                    print "Automatically activated"
+            elif arg == 'dl':
+                print "--- drivers list"
+                is_range, is_strict, is_fake_values, values = configure_iface.GetParameterConstraint(['engine', 'driver'])
+                for value in values:
+                    print value[1]
+            elif arg == 'dg':
+                print "--- get selected driver"
+                isset, default, value = configure_iface.GetParameterValue(['engine', 'driver'])
+                print value
+            elif arg == 'ds':
+                if index >= len(sys.argv):
+                    print "driver select command requires driver name argument"
+                    sys.exit()
+
+                arg = sys.argv[index]
+                index += 1
+
+                print "--- driver select \"%s\"" % arg
+                configure_iface.SetParameterValue(['engine', 'driver'], dbus.String(arg))
+            elif arg == 'dp':
+                print "--- get driver parameters (type:isset:default:value)"
+                get_parameters(configure_iface, ['driver'])
+            elif arg == 'dpd':
+                if index >= len(sys.argv):
+                    print "get driver parameter long description command requires parameter name argument"
+                    sys.exit()
+
+                param = sys.argv[index]
+                index += 1
+
+                print "--- get driver parameter description (%s)" % param
+                type_char, name, short_descr, long_descr = configure_iface.GetParameterInfo(['driver', param])
+                print long_descr,
+            elif arg == 'dps':
+                if index + 1 >= len(sys.argv):
+                    print "driver parameter set command requires parameter name and value arguments"
+                    sys.exit()
+
+                param = sys.argv[index]
+                index += 1
+                value = sys.argv[index]
+                index += 1
+
+                print "--- driver param set \"%s\" -> \"%s\"" % (param, value)
+
+                type_char, name, short_descr, long_descr = configure_iface.GetParameterInfo(['driver', param])
+                configure_iface.SetParameterValue(['driver', param], python_type_to_jackdbus_type(value, type_char))
+            elif arg == 'ep':
+                print "--- get engine parameters (type:isset:default:value)"
+                get_parameters(configure_iface, ['engine'])
+            elif arg == 'epd':
+                if index >= len(sys.argv):
+                    print "get engine parameter long description command requires parameter name argument"
+                    sys.exit()
+
+                param_name = sys.argv[index]
+                index += 1
+
+                print "--- get engine parameter description (%s)" % param_name
+
+                type_char, name, short_descr, long_descr = configure_iface.GetParameterInfo(['engine', param_name])
+                print long_descr,
+            elif arg == 'eps':
+                if index + 1 >= len(sys.argv):
+                    print "engine parameter set command requires parameter name and value arguments"
+                    sys.exit()
+
+                param = sys.argv[index]
+                index += 1
+                value = sys.argv[index]
+                index += 1
+
+                print "--- engine param set \"%s\" -> \"%s\"" % (param, value)
+
+                type_char, name, short_descr, long_descr = configure_iface.GetParameterInfo(['engine', param])
+                configure_iface.SetParameterValue(['engine', param], python_type_to_jackdbus_type(value, type_char))
+            elif arg == 'il':
+                print "--- internals list"
+                is_leaf, internals = configure_iface.ReadContainer(['internals'])
+                for internal in internals:
+                    print internal
+            elif arg == 'ip':
+                print "--- get internal parameters (type:isset:default:value)"
+
+                if index >= len(sys.argv):
+                    print "internal parameters command requires internal name argument"
+                    sys.exit()
+
+                internal_name = sys.argv[index]
+                index += 1
+
+                get_parameters(configure_iface, ['internals', internal_name])
+            elif arg == 'ipd':
+                if index + 1 >= len(sys.argv):
+                    print "get internal parameter long description command requires internal and parameter name arguments"
+                    sys.exit()
+
+                name = sys.argv[index]
+                index += 1
+                param = sys.argv[index]
+                index += 1
+
+                print "--- get internal parameter description (%s)" % param
+                type_char, name, short_descr, long_descr = configure_iface.GetParameterInfo(['internals', name, param])
+                print long_descr
+            elif arg == 'ips':
+                if index + 2 >= len(sys.argv):
+                    print "get internal parameter long description command requires internal, parameter name and value arguments"
+                    sys.exit()
+
+                internal_name = sys.argv[index]
+                index += 1
+                param = sys.argv[index]
+                index += 1
+                value = sys.argv[index]
+                index += 1
+                
+                print "--- internal param set \"%s\" -> \"%s\"" % (param, value)
+
+                type_char, name, short_descr, long_descr = configure_iface.GetParameterInfo(['internals', internal_name, param])
+                configure_iface.SetParameterValue(['internals', internal_name, param], python_type_to_jackdbus_type(value, type_char))
+            elif arg == 'iload':
+                print "--- load internal"
+
+                if index >= len(sys.argv):
+                    print "load internal command requires internal name argument"
+                    sys.exit()
+
+                name = sys.argv[index]
+                index += 1
+                result = control_iface.LoadInternal(name)
+            elif arg == 'iunload':
+                print "--- unload internal"
+
+                if index >= len(sys.argv):
+                    print "unload internal command requires internal name argument"
+                    sys.exit()
+
+                name = sys.argv[index]
+                index += 1
+                result = control_iface.UnloadInternal(name)
+            else:
+                print "Unknown command '%s'" % arg
+        except dbus.DBusException, e:
+            print "DBus exception: %s" % str(e)
+
+if __name__ == '__main__':
+    main()
