summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac25
-rw-r--r--src/JackDbusDriver.cpp1066
-rw-r--r--src/JackDbusDriver.hpp179
-rw-r--r--src/JackDriver.cpp29
-rw-r--r--src/JackDriver.hpp4
-rw-r--r--src/Makefile.am20
-rw-r--r--src/Patchage.cpp42
-rw-r--r--src/PatchageCanvas.cpp7
-rw-r--r--src/PatchageEvent.cpp5
-rw-r--r--src/PatchageEvent.hpp2
-rw-r--r--src/main.cpp1
-rw-r--r--src/patchage.glade3
12 files changed, 1347 insertions, 36 deletions
diff --git a/configure.ac b/configure.ac
index 01f1e0d..86e77a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -100,15 +100,31 @@ CFLAGS="$CFLAGS -std=c99 -pipe -fmessage-length=999 -DCONFIG_H_PATH=\\\"$CONFIG_
#################### GENERIC OPTIONS
+# Jack D-Bus support
+build_jack_dbus="no"
+AC_ARG_ENABLE(dbus,
+ [AS_HELP_STRING(--enable-dbus, [Use Jack D-Bus instead of libjack])],
+ [ if test x$enable_dbus = xyes ; then build_jack_dbus=yes ; fi ])
+if test "x$build_jack_dbus" = "xyes"; then
+ PKG_CHECK_MODULES(DBUS, dbus-glib-1, [build_jack_dbus="yes"], [build_jack_dbus="no"])
+ if test "x$build_jack_dbus" = "xyes"; then
+ AC_DEFINE([HAVE_JACKDBUS], 1, [Defined if Jack D-Bus driver needs to be built])
+ fi
+fi
+AM_CONDITIONAL(WITH_JACKDBUS, [test "$build_jack_dbus"="yes"])
+
# Jack support
build_jack="yes"
AC_ARG_ENABLE(enable-jack,
[AS_HELP_STRING(--enable-jack, [Enable Jack support (yes)])],
[ if test x$enable_jack = xno ; then build_jack=no ; fi ])
-if test "$build_jack" = "yes"; then
- PKG_CHECK_MODULES(JACK, jack >= 0.107.0)
- AC_DEFINE(HAVE_JACK_MIDI, 1, [Has Jack MIDI])
+if test "x$build_jack" = "xyes"; then
+ PKG_CHECK_MODULES(JACK, jack >= 0.107.0, [build_jack="yes"], [build_jack="no"])
+ if test "x$build_jack" = "xyes"; then
+ AC_DEFINE(HAVE_JACK, 1, [Has Jack])
+ AC_DEFINE(HAVE_JACK_MIDI, 1, [Has Jack MIDI])
+ fi
fi
# ALSA support
@@ -152,7 +168,7 @@ fi
AM_CONDITIONAL(WITH_ALSA, [test "$ALSA_FOUND" = "yes"])
AM_CONDITIONAL(WITH_LASH, [test "$have_lash" = "yes"])
AM_CONDITIONAL(WITH_JACK, [test "$build_jack" = "yes"])
-
+AM_CONDITIONAL(WITH_JACKDBUS, [test "$build_jack" = "dbus"])
############# PATCHAGE
PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
@@ -184,6 +200,7 @@ AC_MSG_RESULT([*****************************************************************
AC_MSG_RESULT([Configuration:])
AC_MSG_RESULT([])
AC_MSG_RESULT([Jack support: $build_jack])
+AC_MSG_RESULT([Jack D-Bus: $build_jack_dbus])
AC_MSG_RESULT([LASH support: $build_lash])
AC_MSG_RESULT([ALSA support: $ALSA_FOUND])
AC_MSG_RESULT([])
diff --git a/src/JackDbusDriver.cpp b/src/JackDbusDriver.cpp
new file mode 100644
index 0000000..07a301f
--- /dev/null
+++ b/src/JackDbusDriver.cpp
@@ -0,0 +1,1066 @@
+// -*- Mode: C++ ; indent-tabs-mode: t -*-
+/* This file is part of Patchage.
+ * Copyright (C) 2008 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * Patchage 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, or (at your option) any later
+ * version.
+ *
+ * Patchage 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 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
+ */
+
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <set>
+#include <iostream>
+
+#include CONFIG_H_PATH
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <boost/format.hpp>
+#include <raul/SharedPtr.hpp>
+
+#include "PatchageCanvas.hpp"
+#include "PatchageEvent.hpp"
+#include "Patchage.hpp"
+#include "PatchageModule.hpp"
+#include "Driver.hpp"
+#include "JackDbusDriver.hpp"
+
+using namespace std;
+using namespace FlowCanvas;
+
+#define JACKDBUS_SERVICE "org.jackaudio.service"
+#define JACKDBUS_OBJECT "/org/jackaudio/Controller"
+#define JACKDBUS_IFACE_CONTROL "org.jackaudio.JackControl"
+#define JACKDBUS_IFACE_PATCHBAY "org.jackaudio.JackPatchbay"
+#define JACKDBUS_CALL_DEFAULT_TIMEOUT 1000 // in milliseconds
+
+#define JACKDBUS_PORT_FLAG_INPUT 0x00000001
+#define JACKDBUS_PORT_FLAG_OUTPUT 0x00000002
+#define JACKDBUS_PORT_FLAG_PHYSICAL 0x00000004
+#define JACKDBUS_PORT_FLAG_CAN_MONITOR 0x00000008
+#define JACKDBUS_PORT_FLAG_TERMINAL 0x00000010
+
+#define JACKDBUS_PORT_TYPE_AUDIO 0
+#define JACKDBUS_PORT_TYPE_MIDI 1
+
+//#define LOG_TO_STD
+#define LOG_TO_STATUS
+
+//#define USE_FULL_REFRESH
+
+JackDriver::JackDriver(Patchage* app)
+ : Driver(128)
+ , _app(app)
+ , _dbus_connection(0)
+ , _server_started(false)
+ , _server_responding(false)
+ , _graph_version(0)
+ , _max_dsp_load(0.0)
+{
+ //info_msg(__func__);
+
+ dbus_error_init(&_dbus_error);
+}
+
+JackDriver::~JackDriver()
+{
+ //info_msg(__func__);
+
+ detach();
+
+ if (dbus_error_is_set(&_dbus_error)) {
+ dbus_error_free(&_dbus_error);
+ }
+}
+
+/** Destroy all JACK (canvas) ports.
+ */
+void
+JackDriver::destroy_all_ports()
+{
+ ItemList modules = _app->canvas()->items(); // copy
+ for (ItemList::iterator m = modules.begin(); m != modules.end(); ++m) {
+ SharedPtr<Module> module = PtrCast<Module>(*m);
+ if (!module)
+ continue;
+ PortVector ports = module->ports(); // copy
+ for (PortVector::iterator p = ports.begin(); p != ports.end(); ++p) {
+ boost::shared_ptr<PatchagePort> port = boost::dynamic_pointer_cast<PatchagePort>(*p);
+ if (port && port->type() == JACK_AUDIO || port->type() == JACK_MIDI) {
+ module->remove_port(port);
+ port->hide();
+ }
+ }
+
+ if (module->ports().empty())
+ _app->canvas()->remove_item(module);
+ else
+ module->resize();
+ }
+}
+
+DBusHandlerResult
+JackDriver::dbus_message_hook(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *jack_driver)
+{
+ 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;
+ dbus_uint64_t client2_id;
+ const char *client2_name;
+ dbus_uint64_t port2_id;
+ const char *port2_name;
+ dbus_uint64_t connection_id;
+
+ assert(jack_driver);
+ JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
+ assert(me->_dbus_connection);
+
+ //me->info_msg("dbus_message_hook() called.");
+
+ // Handle signals we have subscribed for in attach()
+
+#if defined(USE_FULL_REFRESH)
+ if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "GraphChanged")) {
+ if (!dbus_message_get_args(message, &me->_dbus_error, DBUS_TYPE_UINT64, &new_graph_version, DBUS_TYPE_INVALID)) {
+ me->error_msg(str(boost::format("dbus_message_get_args() failed to extract GraphChanged signal arguments (%s)") % me->_dbus_error.message));
+ dbus_error_free(&me->_dbus_error);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ //me->info_msg(str(boost::format("GraphChanged, new version is %llu") % new_graph_version));
+
+ if (new_graph_version > me->_graph_version) {
+ me->refresh_internal(false);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+#else
+// if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "ClientAppeared")) {
+// me->info_msg("ClientAppeared");
+// return DBUS_HANDLER_RESULT_HANDLED;
+// }
+
+// if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "ClientDisappeared")) {
+// me->info_msg("ClientDisappeared");
+// return DBUS_HANDLER_RESULT_HANDLED;
+// }
+
+ if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "PortAppeared")) {
+ if (!dbus_message_get_args(
+ message,
+ &me->_dbus_error,
+ 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)) {
+ me->error_msg(str(boost::format("dbus_message_get_args() failed to extract PortAppeared signal arguments (%s)") % me->_dbus_error.message));
+ dbus_error_free(&me->_dbus_error);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ //me->info_msg(str(boost::format("PortAppeared, %s(%llu):%s(%llu), %lu, %lu") % client_name % client_id % port_name % port_id % port_flags % port_type));
+
+ me->add_port(client_id, client_name, port_id, port_name, port_flags, port_type);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "PortDisappeared")) {
+ if (!dbus_message_get_args(
+ message,
+ &me->_dbus_error,
+ 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)) {
+ me->error_msg(str(boost::format("dbus_message_get_args() failed to extract PortDisappeared signal arguments (%s)") % me->_dbus_error.message));
+ dbus_error_free(&me->_dbus_error);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ //me->info_msg(str(boost::format("PortDisappeared, %s(%llu):%s(%llu)") % client_name % client_id % port_name % port_id));
+
+ me->remove_port(client_id, client_name, port_id, port_name);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "PortsConnected")) {
+ if (!dbus_message_get_args(
+ message,
+ &me->_dbus_error,
+ 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_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)) {
+ me->error_msg(str(boost::format("dbus_message_get_args() failed to extract PortsConnected signal arguments (%s)") % me->_dbus_error.message));
+ dbus_error_free(&me->_dbus_error);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+// me->info_msg(str(boost::format("ports connected (%llu) %s(%llu):%s(%llu) <-> %s(%llu):%s(%llu)") %
+// connection_id %
+// client_name %
+// client_id %
+// port_name %
+// port_id %
+// client2_name %
+// client2_id %
+// port2_name %
+// port2_id));
+
+ me->connect_ports(
+ connection_id,
+ client_id,
+ client_name,
+ port_id,
+ port_name,
+ client2_id,
+ client2_name,
+ port2_id,
+ port2_name);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (dbus_message_is_signal(message, JACKDBUS_IFACE_PATCHBAY, "PortsDisconnected")) {
+ if (!dbus_message_get_args(
+ message,
+ &me->_dbus_error,
+ 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_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)) {
+ me->error_msg(str(boost::format("dbus_message_get_args() failed to extract PortsConnected signal arguments (%s)") % me->_dbus_error.message));
+ dbus_error_free(&me->_dbus_error);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+// me->info_msg(str(boost::format("ports disconnected (%llu) %s(%llu):%s(%llu) <-> %s(%llu):%s(%llu)") %
+// connection_id %
+// client_name %
+// client_id %
+// port_name %
+// port_id %
+// client2_name %
+// client2_id %
+// port2_name %
+// port2_id));
+
+ me->disconnect_ports(
+ connection_id,
+ client_id,
+ client_name,
+ port_id,
+ port_name,
+ client2_id,
+ client2_name,
+ port2_id,
+ port2_name);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+#endif
+
+ //me->info_msg("not yet handled.");
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+bool
+JackDriver::call(
+ const char* iface,
+ const char* method,
+ DBusMessage ** reply_ptr_ptr,
+ int in_type,
+ ...)
+{
+ DBusMessage* request_ptr;
+ DBusMessage* reply_ptr;
+ va_list ap;
+
+ request_ptr = dbus_message_new_method_call(
+ JACKDBUS_SERVICE,
+ JACKDBUS_OBJECT,
+ iface,
+ method);
+ if (!request_ptr) {
+ throw std::runtime_error("dbus_message_new_method_call() returned 0");
+ }
+
+ va_start(ap, in_type);
+
+ dbus_message_append_args_valist(
+ request_ptr,
+ in_type,
+ ap);
+
+ va_end(ap);
+
+ // send message and get a handle for a reply
+ reply_ptr = dbus_connection_send_with_reply_and_block(_dbus_connection, request_ptr, JACKDBUS_CALL_DEFAULT_TIMEOUT, &_dbus_error);
+
+ dbus_message_unref(request_ptr);
+
+ if (!reply_ptr) {
+ error_msg(_dbus_error.message);
+ _server_responding = false;
+ dbus_error_free(&_dbus_error);
+ } else {
+ _server_responding = true;
+ *reply_ptr_ptr = reply_ptr;
+ }
+
+ return reply_ptr;
+}
+
+bool
+JackDriver::is_started()
+{
+ DBusMessage* reply_ptr;
+ dbus_bool_t started;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "IsStarted", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ if (!dbus_message_get_args(reply_ptr, &_dbus_error, DBUS_TYPE_BOOLEAN, &started, DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply_ptr);
+ dbus_error_free(&_dbus_error);
+ error_msg("decoding reply of IsStarted failed.");
+ return false;
+ }
+
+ dbus_message_unref(reply_ptr);
+
+ return started;
+}
+
+void
+JackDriver::attach(bool launch_daemon)
+{
+ // connect to the bus
+ _dbus_connection = dbus_bus_get(DBUS_BUS_SESSION, &_dbus_error);
+ if (dbus_error_is_set(&_dbus_error)) {
+ error_msg("dbus_bus_get() failed");
+ error_msg(_dbus_error.message);
+ dbus_error_free(&_dbus_error);
+ return;
+ }
+
+ dbus_connection_setup_with_g_main(_dbus_connection, NULL);
+
+#if defined(USE_FULL_REFRESH)
+ dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=GraphChanged", NULL);
+#else
+// dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=ClientAppeared", NULL);
+// dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=ClientDisappeared", NULL);
+ dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=PortAppeared", NULL);
+ dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=PortDisappeared", NULL);
+ dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=PortsConnected", NULL);
+ dbus_bus_add_match(_dbus_connection, "type='signal',interface='" JACKDBUS_IFACE_PATCHBAY "',member=PortsDisconnected", NULL);
+#endif
+ dbus_connection_add_filter(_dbus_connection, dbus_message_hook, this, NULL);
+
+ _server_started = is_started();
+
+ if (_server_responding) {
+ signal_attached.emit();
+ }
+}
+
+void
+JackDriver::detach()
+{
+ if (_dbus_connection) {
+ dbus_connection_flush(_dbus_connection);
+ _dbus_connection = NULL;
+ signal_detached.emit();
+ }
+}
+
+bool
+JackDriver::is_attached() const
+{
+ return _dbus_connection && _server_responding;
+}
+
+void
+JackDriver::add_port(
+ boost::shared_ptr<PatchageModule>& module,
+ PortType type,
+ const std::string& name,
+ bool is_input)
+{
+ if (module->get_port(name)) {
+ return;
+ }
+
+ module->add_port(
+ boost::shared_ptr<PatchagePort>(
+ new PatchagePort(
+ module,
+ type,
+ name,
+ is_input,
+ _app->state_manager()->get_port_color(type))));
+
+ module->resize();
+}
+
+void
+JackDriver::add_port(
+ 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)
+{
+ PortType local_port_type;
+
+ switch (port_type) {
+ case JACKDBUS_PORT_TYPE_AUDIO:
+ local_port_type = JACK_AUDIO;
+ break;
+ case JACKDBUS_PORT_TYPE_MIDI:
+ local_port_type = JACK_MIDI;
+ break;
+ default:
+ error_msg("Unknown JACK D-Bus port type");
+ return;
+ }
+
+ ModuleType type = InputOutput;
+ if (_app->state_manager()->get_module_split(client_name, port_flags & JACKDBUS_PORT_FLAG_TERMINAL)) {
+ if (port_flags & JACKDBUS_PORT_FLAG_INPUT) {
+ type = Input;
+ } else {
+ type = Output;
+ }
+ }
+
+ boost::shared_ptr<PatchageModule> module = find_or_create_module(type, client_name);
+
+ add_port(module, local_port_type, port_name, port_flags & JACKDBUS_PORT_FLAG_INPUT);
+}
+
+void
+JackDriver::remove_port(
+ dbus_uint64_t client_id,
+ const char *client_name,
+ dbus_uint64_t port_id,
+ const char *port_name)
+{
+ boost::shared_ptr<PatchagePort> port = PtrCast<PatchagePort>(_app->canvas()->get_port(client_name, port_name));
+ if (!port) {
+ error_msg("Unable to remove unknown port");
+ return;
+ }
+
+ boost::shared_ptr<PatchageModule> module = PtrCast<PatchageModule>(port->module().lock());
+
+ module->remove_port(port);
+ port.reset();
+
+ // No empty modules (for now)
+ if (module->num_ports() == 0) {
+ _app->canvas()->remove_item(module);
+ module.reset();
+ } else {
+ module->resize();
+ }
+}
+
+boost::shared_ptr<PatchageModule>
+JackDriver::find_or_create_module(
+ ModuleType type,
+ const std::string& name)
+{
+ boost::shared_ptr<PatchageModule> module = _app->canvas()->find_module(name, type);
+
+ if (!module) {
+ module = boost::shared_ptr<PatchageModule>(new PatchageModule(_app, name, type));
+ module->load_location();
+ _app->canvas()->add_item(module);
+ }
+
+ return module;
+}
+
+void
+JackDriver::connect_ports(
+ dbus_uint64_t connection_id,
+ 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)
+{
+ boost::shared_ptr<PatchagePort> port1 = PtrCast<PatchagePort>(_app->canvas()->get_port(client1_name, port1_name));
+ if (!port1) {
+ error_msg((string)"Unable to connect unknown port '" + port1_name + "' of client '" + client1_name + "'");
+ return;
+ }
+
+ boost::shared_ptr<PatchagePort> port2 = PtrCast<PatchagePort>(_app->canvas()->get_port(client2_name, port2_name));
+ if (!port2) {
+ error_msg((string)"Unable to connect unknown port '" + port2_name + "' of client '" + client2_name + "'");
+ return;
+ }
+
+ _app->canvas()->add_connection(port1, port2, port1->color() + 0x22222200);
+}
+
+void
+JackDriver::disconnect_ports(
+ dbus_uint64_t connection_id,
+ 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)
+{
+ boost::shared_ptr<PatchagePort> port1 = PtrCast<PatchagePort>(_app->canvas()->get_port(client1_name, port1_name));
+ if (!port1) {
+ error_msg((string)"Unable to disconnect unknown port '" + port1_name + "' of client '" + client1_name + "'");
+ return;
+ }
+
+ boost::shared_ptr<PatchagePort> port2 = PtrCast<PatchagePort>(_app->canvas()->get_port(client2_name, port2_name));
+ if (!port2) {
+ error_msg((string)"Unable to disconnect unknown port '" + port2_name + "' of client '" + client2_name + "'");
+ return;
+ }
+
+ _app->canvas()->remove_connection(port1, port2);
+}
+
+void
+JackDriver::refresh_internal(bool force)
+{
+ DBusMessage* reply_ptr;
+ DBusMessageIter iter;
+ int type;
+ dbus_uint64_t version;
+ const char * reply_signature;
+ DBusMessageIter clients_array_iter;
+ DBusMessageIter client_struct_iter;
+ DBusMessageIter ports_array_iter;
+ DBusMessageIter port_struct_iter;
+ DBusMessageIter connections_array_iter;
+ DBusMessageIter connection_struct_iter;
+ 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;
+ dbus_uint64_t client2_id;
+ const char *client2_name;
+ dbus_uint64_t port2_id;
+ const char *port2_name;
+ dbus_uint64_t connection_id;
+
+ if (force) {
+ version = 0; // workaround module split/join stupidity
+ } else {
+ version = _graph_version;
+ }
+
+ if (!call(JACKDBUS_IFACE_PATCHBAY, "GetGraph", &reply_ptr, DBUS_TYPE_UINT64, &version, DBUS_TYPE_INVALID)) {
+ error_msg("GetGraph() failed.");
+ return;
+ }
+
+ reply_signature = dbus_message_get_signature(reply_ptr);
+
+ if (strcmp(reply_signature, "ta(tsa(tsuu))a(tstststst)") != 0) {
+ error_msg((string )"GetGraph() reply signature mismatch. " + reply_signature);
+ goto unref;
+ }
+
+ dbus_message_iter_init(reply_ptr, &iter);
+
+ //info_msg((string)"version " + (char)dbus_message_iter_get_arg_type(&iter));
+ dbus_message_iter_get_basic(&iter, &version);
+ dbus_message_iter_next(&iter);
+
+ if (!force && version <= _graph_version) {
+ goto unref;
+ }
+
+ destroy_all_ports();
+
+// info_msg(str(boost::format("got new graph version %llu") % version));
+ _graph_version = version;
+
+ //info_msg((string)"clients " + (char)dbus_message_iter_get_arg_type(&iter));
+
+ for (dbus_message_iter_recurse(&iter, &clients_array_iter);
+ dbus_message_iter_get_arg_type(&clients_array_iter) != DBUS_TYPE_INVALID;
+ dbus_message_iter_next(&clients_array_iter)) {
+ //info_msg((string)"a client " + (char)dbus_message_iter_get_arg_type(&clients_array_iter));
+ dbus_message_iter_recurse(&clients_array_iter, &client_struct_iter);
+
+ dbus_message_iter_get_basic(&client_struct_iter, &client_id);
+ dbus_message_iter_next(&client_struct_iter);
+
+ dbus_message_iter_get_basic(&client_struct_iter, &client_name);
+ dbus_message_iter_next(&client_struct_iter);
+
+// info_msg((string)"client '" + client_name + "'");
+
+ for (dbus_message_iter_recurse(&client_struct_iter, &ports_array_iter);
+ dbus_message_iter_get_arg_type(&ports_array_iter) != DBUS_TYPE_INVALID;
+ dbus_message_iter_next(&ports_array_iter)) {
+ //info_msg((string)"a port " + (char)dbus_message_iter_get_arg_type(&ports_array_iter));
+ dbus_message_iter_recurse(&ports_array_iter, &port_struct_iter);
+
+ dbus_message_iter_get_basic(&port_struct_iter, &port_id);
+ dbus_message_iter_next(&port_struct_iter);
+
+ dbus_message_iter_get_basic(&port_struct_iter, &port_name);
+ dbus_message_iter_next(&port_struct_iter);
+
+ dbus_message_iter_get_basic(&port_struct_iter, &port_flags);
+ dbus_message_iter_next(&port_struct_iter);
+
+ dbus_message_iter_get_basic(&port_struct_iter, &port_type);
+ dbus_message_iter_next(&port_struct_iter);
+
+// info_msg((string)"port: " + port_name);
+
+ add_port(client_id, client_name, port_id, port_name, port_flags, port_type);
+ }
+
+ dbus_message_iter_next(&client_struct_iter);
+ }
+
+ dbus_message_iter_next(&iter);
+
+ for (dbus_message_iter_recurse(&iter, &connections_array_iter);
+ dbus_message_iter_get_arg_type(&connections_array_iter) != DBUS_TYPE_INVALID;
+ dbus_message_iter_next(&connections_array_iter)) {
+ //info_msg((string)"a connection " + (char)dbus_message_iter_get_arg_type(&connections_array_iter));
+ dbus_message_iter_recurse(&connections_array_iter, &connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &client_id);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &client_name);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &port_id);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &port_name);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &client2_id);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &client2_name);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &port2_id);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &port2_name);
+ dbus_message_iter_next(&connection_struct_iter);
+
+ dbus_message_iter_get_basic(&connection_struct_iter, &connection_id);
+ dbus_message_iter_next(&connection_struct_iter);
+
+// info_msg(str(boost::format("connection(%llu) %s(%llu):%s(%llu) <-> %s(%llu):%s(%llu)") %
+// connection_id %
+// client_name %
+// client_id %
+// port_name %
+// port_id %
+// client2_name %
+// client2_id %
+// port2_name %
+// port2_id));
+
+ connect_ports(
+ connection_id,
+ client_id,
+ client_name,
+ port_id,
+ port_name,
+ client2_id,
+ client2_name,
+ port2_id,
+ port2_name);
+ }
+
+unref:
+ dbus_message_unref(reply_ptr);
+}
+
+void
+JackDriver::refresh()
+{
+ refresh_internal(true);
+}
+
+bool
+JackDriver::connect(
+ boost::shared_ptr<PatchagePort> src,
+ boost::shared_ptr<PatchagePort> dst)
+{
+ const char *client1_name;
+ const char *port1_name;
+ const char *client2_name;
+ const char *port2_name;
+ DBusMessage* reply_ptr;
+
+ client1_name = src->module().lock()->name().c_str();
+ port1_name = src->name().c_str();
+ client2_name = dst->module().lock()->name().c_str();
+ port2_name = dst->name().c_str();
+
+ if (!call(
+ JACKDBUS_IFACE_PATCHBAY,
+ "ConnectPortsByName",
+ &reply_ptr,
+ DBUS_TYPE_STRING,
+ &client1_name,
+ DBUS_TYPE_STRING,
+ &port1_name,
+ DBUS_TYPE_STRING,
+ &client2_name,
+ DBUS_TYPE_STRING,
+ &port2_name,
+ DBUS_TYPE_INVALID)) {
+ error_msg("ConnectPortsByName() failed.");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+JackDriver::disconnect(
+ boost::shared_ptr<PatchagePort> src,
+ boost::shared_ptr<PatchagePort> dst)
+{
+ const char *client1_name;
+ const char *port1_name;
+ const char *client2_name;
+ const char *port2_name;
+ DBusMessage* reply_ptr;
+
+ client1_name = src->module().lock()->name().c_str();
+ port1_name = src->name().c_str();
+ client2_name = dst->module().lock()->name().c_str();
+ port2_name = dst->name().c_str();
+
+ if (!call(
+ JACKDBUS_IFACE_PATCHBAY,
+ "DisconnectPortsByName",
+ &reply_ptr,
+ DBUS_TYPE_STRING,
+ &client1_name,
+ DBUS_TYPE_STRING,
+ &port1_name,
+ DBUS_TYPE_STRING,
+ &client2_name,
+ DBUS_TYPE_STRING,
+ &port2_name,
+ DBUS_TYPE_INVALID)) {
+ error_msg("DisconnectPortsByName() failed.");
+ return false;
+ }
+
+ return true;
+}
+
+jack_nframes_t
+JackDriver::buffer_size()
+{
+ DBusMessage* reply_ptr;
+ dbus_uint32_t buffer_size;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "GetBufferSize", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ if (!dbus_message_get_args(reply_ptr, &_dbus_error, DBUS_TYPE_UINT32, &buffer_size, DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply_ptr);
+ dbus_error_free(&_dbus_error);
+ error_msg("decoding reply of GetBufferSize failed.");
+ return false;
+ }
+
+ dbus_message_unref(reply_ptr);
+
+ return buffer_size;
+}
+
+bool
+JackDriver::set_buffer_size(jack_nframes_t size)
+{
+ DBusMessage* reply_ptr;
+ dbus_uint32_t buffer_size;
+
+ buffer_size = size;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "SetBufferSize", &reply_ptr, DBUS_TYPE_UINT32, &buffer_size, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ dbus_message_unref(reply_ptr);
+}
+
+float
+JackDriver::sample_rate()
+{
+ DBusMessage* reply_ptr;
+ double sample_rate;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "GetSampleRate", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ if (!dbus_message_get_args(reply_ptr, &_dbus_error, DBUS_TYPE_DOUBLE, &sample_rate, DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply_ptr);
+ dbus_error_free(&_dbus_error);
+ error_msg("decoding reply of GetSampleRate failed.");
+ return false;
+ }
+
+ dbus_message_unref(reply_ptr);
+
+ return sample_rate;
+}
+
+bool
+JackDriver::is_realtime() const
+{
+ DBusMessage* reply_ptr;
+ dbus_bool_t realtime;
+
+ if (!((JackDriver *)this)->call(JACKDBUS_IFACE_CONTROL, "IsRealtime", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ if (!dbus_message_get_args(reply_ptr, &((JackDriver *)this)->_dbus_error, DBUS_TYPE_BOOLEAN, &realtime, DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply_ptr);
+ dbus_error_free(&((JackDriver *)this)->_dbus_error);
+ error_msg("decoding reply of IsRealtime failed.");
+ return false;
+ }
+
+ dbus_message_unref(reply_ptr);
+
+ return realtime;
+}
+
+size_t
+JackDriver::xruns()
+{
+ DBusMessage* reply_ptr;
+ dbus_uint32_t xruns;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "GetXruns", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ if (!dbus_message_get_args(reply_ptr, &_dbus_error, DBUS_TYPE_UINT32, &xruns, DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply_ptr);
+ dbus_error_free(&_dbus_error);
+ error_msg("decoding reply of GetXruns failed.");
+ return 0;
+ }
+
+ dbus_message_unref(reply_ptr);
+
+ return xruns;
+}
+
+void
+JackDriver::reset_xruns()
+{
+ DBusMessage* reply_ptr;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "ResetXruns", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return;
+ }
+
+ dbus_message_unref(reply_ptr);
+}
+
+float
+JackDriver::get_max_dsp_load()
+{
+ DBusMessage* reply_ptr;
+ double load;
+
+ if (!call(JACKDBUS_IFACE_CONTROL, "GetLoad", &reply_ptr, DBUS_TYPE_INVALID)) {
+ return false;
+ }
+
+ if (!dbus_message_get_args(reply_ptr, &_dbus_error, DBUS_TYPE_DOUBLE, &load, DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply_ptr);
+ dbus_error_free(&_dbus_error);
+ error_msg("decoding reply of GetLoad failed.");
+ return false;
+ }
+
+ dbus_message_unref(reply_ptr);
+
+ load /= 100.0; // dbus returns it in percents, we use 0..1
+
+ if (load > _max_dsp_load)
+ {
+ _max_dsp_load = load;
+ }
+
+ return _max_dsp_load;
+}
+
+void
+JackDriver::reset_max_dsp_load()
+{
+ _max_dsp_load = 0.0;
+}
+
+void
+JackDriver::start_transport()
+{
+// info_msg(__func__);
+}
+
+void
+JackDriver::stop_transport()
+{
+// info_msg(__func__);
+}
+
+void
+JackDriver::rewind_transport()
+{
+// info_msg(__func__);
+}
+
+boost::shared_ptr<PatchagePort>
+JackDriver::find_port_view(
+ Patchage * patchage,
+ const PatchageEvent::PortRef& ref)
+{
+ assert(false); // we dont use events at all
+}
+
+boost::shared_ptr<PatchagePort>
+JackDriver::create_port_view(
+ Patchage * patchage,
+ const PatchageEvent::PortRef& ref)
+{
+ assert(false); // we dont use events at all
+}
+
+void
+JackDriver::error_msg(const std::string& msg) const
+{
+#if defined(LOG_TO_STATUS)
+ _app->status_message((std::string)"[JACKDBUS] " + msg);
+#endif
+
+#if defined(LOG_TO_STD)
+ cerr << (std::string)"[JACKDBUS] " << msg << endl;
+#endif
+}
+
+void
+JackDriver::info_msg(const std::string& msg) const
+{
+#if defined(LOG_TO_STATUS)
+ _app->status_message((std::string)"[JACKDBUS] " + msg);
+#endif
+
+#if defined(LOG_TO_STD)
+ cerr << (std::string)"[JACKDBUS] " << msg << endl;
+#endif
+}
diff --git a/src/JackDbusDriver.hpp b/src/JackDbusDriver.hpp
new file mode 100644
index 0000000..3a5ccea
--- /dev/null
+++ b/src/JackDbusDriver.hpp
@@ -0,0 +1,179 @@
+// -*- Mode: C++ ; indent-tabs-mode: t -*-
+/* This file is part of Patchage.
+ * Copyright (C) 2008 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * Patchage 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, or (at your option) any later
+ * version.
+ *
+ * Patchage 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 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 JACKDBUSDRIVER_HPP__B02CBCEF_31D6_4546_9457_C7DF6D6B0300__INCLUDED
+#define JACKDBUSDRIVER_HPP__B02CBCEF_31D6_4546_9457_C7DF6D6B0300__INCLUDED
+
+#include <iostream>
+#include <boost/shared_ptr.hpp>
+#include <jack/jack.h>
+#include <jack/statistics.h>
+#include <glibmm/thread.h>
+#include <raul/AtomicPtr.hpp>
+#include <dbus/dbus.h>
+
+#include "Driver.hpp"
+#include "Patchage.hpp"
+#include "PatchageModule.hpp"
+
+class PatchageEvent;
+class PatchageFlowCanvas;
+class PatchagePort;
+
+class JackDriver : public Driver
+{
+public:
+ JackDriver(Patchage* app);
+ ~JackDriver();
+
+ void attach(bool launch_daemon);
+ void detach();
+
+ bool is_attached() const;
+ bool is_realtime() const;
+
+ void refresh();
+
+ bool
+ connect(
+ boost::shared_ptr<PatchagePort> src,
+ boost::shared_ptr<PatchagePort> dst);
+
+ bool
+ disconnect(
+ boost::shared_ptr<PatchagePort> src,
+ boost::shared_ptr<PatchagePort> dst);
+ void start_transport();
+ void stop_transport();
+ void rewind_transport();
+
+ void reset_xruns();
+
+ jack_nframes_t buffer_size();
+ bool set_buffer_size(jack_nframes_t size);
+
+ float sample_rate();
+
+ size_t xruns();
+
+ float get_max_dsp_load();
+ void reset_max_dsp_load();
+
+ boost::shared_ptr<PatchagePort>
+ find_port_view(
+ Patchage * patchage,
+ const PatchageEvent::PortRef& ref);
+
+ boost::shared_ptr<PatchagePort>
+ create_port_view(
+ Patchage * patchage,
+ const PatchageEvent::PortRef& ref);
+
+private:
+ void error_msg(const std::string& msg) const;
+ void info_msg(const std::string& msg) const;
+
+ boost::shared_ptr<PatchageModule>
+ find_or_create_module(
+ ModuleType type,
+ const std::string& name);
+
+ void
+ add_port(
+ boost::shared_ptr<PatchageModule>& module,
+ PortType type,
+ const std::string& name,
+ bool is_input);
+
+ void
+ add_port(
+ 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);
+
+ void
+ remove_port(
+ dbus_uint64_t client_id,
+ const char *client_name,
+ dbus_uint64_t port_id,
+ const char *port_name);
+
+ void
+ connect_ports(
+ dbus_uint64_t connection_id,
+ 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);
+
+ void
+ disconnect_ports(
+ dbus_uint64_t connection_id,
+ 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);
+
+ bool
+ call(
+ const char* iface,
+ const char* method,
+ DBusMessage ** reply_ptr_ptr,
+ int in_type,
+ ...);
+
+ bool
+ is_started();
+
+ void
+ destroy_all_ports();
+
+ void refresh_internal(bool force);
+
+ static
+ DBusHandlerResult
+ dbus_message_hook(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *me);
+
+private:
+ Patchage* _app;
+ DBusError _dbus_error;
+ DBusConnection* _dbus_connection;
+
+ bool _server_responding;
+ bool _server_started;
+
+ dbus_uint64_t _graph_version;
+
+ float _max_dsp_load;
+};
+
+#endif // #ifndef JACKDBUSDRIVER_HPP__B02CBCEF_31D6_4546_9457_C7DF6D6B0300__INCLUDED
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
index f77fd32..fc6472b 100644
--- a/src/JackDriver.cpp
+++ b/src/JackDriver.cpp
@@ -489,7 +489,7 @@ JackDriver::jack_buffer_size_cb(jack_nframes_t buffer_size, void* jack_driver)
me->_buffer_size = buffer_size;
me->reset_xruns();
- me->reset_delay();
+ me->reset_max_dsp_load();
return 0;
}
@@ -570,3 +570,30 @@ JackDriver::set_buffer_size(jack_nframes_t size)
}
}
+float
+JackDriver::get_max_dsp_load()
+{
+ float max_load;
+ float max_delay;
+
+ max_delay = jack_get_max_delayed_usecs(_client);
+
+ const float rate = sample_rate();
+ const float size = buffer_size();
+ const float period = size / rate * 1000000; // usec
+
+ if (max_delay > period) {
+ max_load = 1.0;
+ jack_reset_max_delayed_usecs(_client);
+ } else {
+ max_load = max_delay / period;
+ }
+
+ return max_load;
+}
+
+void
+JackDriver::reset_max_dsp_load()
+{
+ jack_reset_max_delayed_usecs(_client);
+}
diff --git a/src/JackDriver.hpp b/src/JackDriver.hpp
index b75c826..6fc74d1 100644
--- a/src/JackDriver.hpp
+++ b/src/JackDriver.hpp
@@ -69,7 +69,7 @@ public:
void stop_transport() { jack_transport_stop(_client); }
void reset_xruns();
- void reset_delay() { jack_reset_max_delayed_usecs(_client); }
+ void reset_max_dsp_load();
void rewind_transport() {
jack_position_t zero;
@@ -87,7 +87,7 @@ public:
inline size_t xruns() { return _xruns; }
- inline float max_delay() { return jack_get_max_delayed_usecs(_client); }
+ float get_max_dsp_load();
private:
diff --git a/src/Makefile.am b/src/Makefile.am
index a87563b..3d8c76b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
-AM_CXXFLAGS = -I.. -I$(top_srcdir)/raul -I$(top_srcdir)/flowcanvas -DDATA_DIR=\"$(pkgdatadir)\" @GTHREAD_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @JACK_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@
-patchage_LDADD = @GTHREAD_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @JACK_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @RAUL_LIBS@ @FLOWCANVAS_LIBS@
+AM_CXXFLAGS = -I.. -I$(top_srcdir)/raul -I$(top_srcdir)/flowcanvas -DDATA_DIR=\"$(pkgdatadir)\" @GTHREAD_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@
+patchage_LDADD = @GTHREAD_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @RAUL_LIBS@ @FLOWCANVAS_LIBS@
EXTRA_DIST = patchage.gladep
@@ -10,8 +10,6 @@ bin_PROGRAMS = patchage
patchage_SOURCES = \
Driver.hpp \
GladeFile.hpp \
- JackDriver.cpp \
- JackDriver.hpp \
JackSettingsDialog.hpp \
Patchage.cpp \
Patchage.hpp \
@@ -26,6 +24,20 @@ patchage_SOURCES = \
Widget.hpp \
main.cpp
+if WITH_JACK_DBUS
+AM_CXXFLAGS += @DBUS_CFLAGS@
+patchage_SOURCES += JackDbusDriver.cpp
+patchage_SOURCES += JackDbusDriver.hpp
+patchage_LDADD += @DBUS_LIBS@
+else
+if WITH_JACK
+AM_CXXFLAGS += @JACK_CFLAGS@
+patchage_SOURCES += JackDriver.cpp
+patchage_SOURCES += JackDriver.hpp
+patchage_LDADD += @JACK_LIBS@
+endif
+endif
+
if WITH_LASH
patchage_SOURCES += LashDriver.hpp LashDriver.cpp
endif
diff --git a/src/Patchage.cpp b/src/Patchage.cpp
index 6396526..3803a6b 100644
--- a/src/Patchage.cpp
+++ b/src/Patchage.cpp
@@ -27,7 +27,12 @@
#include CONFIG_H_PATH
#include "GladeFile.hpp"
+#ifdef HAVE_JACK
#include "JackDriver.hpp"
+#endif
+#ifdef HAVE_JACKDBUS
+#include "JackDbusDriver.hpp"
+#endif
#include "JackSettingsDialog.hpp"
#include "Patchage.hpp"
#include "PatchageCanvas.hpp"
@@ -168,10 +173,6 @@ Patchage::Patchage(int argc, char** argv)
sigc::mem_fun(_canvas.get(), &PatchageCanvas::zoom_full));
_menu_jack_settings->signal_activate().connect(sigc::hide_return(
sigc::mem_fun(_jack_settings_dialog, &JackSettingsDialog::run)));
- _menu_jack_connect->signal_activate().connect(sigc::bind(
- sigc::mem_fun(_jack_driver, &JackDriver::attach), true));
- _menu_jack_disconnect->signal_activate().connect(
- sigc::mem_fun(_jack_driver, &JackDriver::detach));
#ifdef HAVE_LASH
_menu_open_session->signal_activate().connect(
@@ -234,6 +235,11 @@ Patchage::Patchage(int argc, char** argv)
_jack_driver = new JackDriver(this);
_jack_driver->signal_detached.connect(sigc::mem_fun(this, &Patchage::queue_refresh));
+
+ _menu_jack_connect->signal_activate().connect(sigc::bind(
+ sigc::mem_fun(_jack_driver, &JackDriver::attach), true));
+ _menu_jack_disconnect->signal_activate().connect(
+ sigc::mem_fun(_jack_driver, &JackDriver::detach));
#ifdef HAVE_ALSA
_alsa_driver = new AlsaDriver(this);
@@ -346,28 +352,18 @@ Patchage::update_load()
if (!_jack_driver->is_attached())
return true;
- static float last_delay = 0;
+ char tmp_buf[8];
+ snprintf(tmp_buf, 8, "%zd", _jack_driver->xruns());
- const float max_delay = _jack_driver->max_delay();
+ _main_xrun_progress->set_text(string(tmp_buf) + " Dropouts");
- if (max_delay != last_delay) {
- const float sample_rate = _jack_driver->sample_rate();
- const float buffer_size = _jack_driver->buffer_size();
- const float period = buffer_size / sample_rate * 1000000; // usec
-
- _main_xrun_progress->set_fraction(max_delay / period);
+ static float last_max_dsp_load = 0;
- char tmp_buf[8];
- snprintf(tmp_buf, 8, "%zd", _jack_driver->xruns());
-
- _main_xrun_progress->set_text(string(tmp_buf) + " Dropouts");
-
- if (max_delay > period) {
- _main_xrun_progress->set_fraction(1.0);
- _jack_driver->reset_delay();
- }
+ const float max_dsp_load = _jack_driver->get_max_dsp_load();
- last_delay = max_delay;
+ if (max_dsp_load != last_max_dsp_load) {
+ _main_xrun_progress->set_fraction(max_dsp_load);
+ last_max_dsp_load = max_dsp_load;
}
return true;
@@ -430,7 +426,7 @@ Patchage::clear_load()
{
_main_xrun_progress->set_fraction(0.0);
_jack_driver->reset_xruns();
- _jack_driver->reset_delay();
+ _jack_driver->reset_max_dsp_load();
}
diff --git a/src/PatchageCanvas.cpp b/src/PatchageCanvas.cpp
index ffc5627..aa7ef64 100644
--- a/src/PatchageCanvas.cpp
+++ b/src/PatchageCanvas.cpp
@@ -19,7 +19,12 @@
#include CONFIG_H_PATH
#include "PatchageCanvas.hpp"
#include "Patchage.hpp"
+#ifdef HAVE_JACK
#include "JackDriver.hpp"
+#endif
+#ifdef HAVE_JACKDBUS
+#include "JackDbusDriver.hpp"
+#endif
#include "PatchageModule.hpp"
#include "PatchagePort.hpp"
#ifdef HAVE_ALSA
@@ -72,6 +77,7 @@ PatchageCanvas::find_port(const PatchageEvent::PortRef& ref)
// TODO: filthy. keep a port map and make this O(log(n))
switch (ref.type) {
+#if HAVE_JACK
case PatchageEvent::PortRef::JACK_ID:
jack_port = jack_port_by_id(_app->jack_driver()->client(), ref.id.jack_id);
if (!jack_port)
@@ -88,6 +94,7 @@ PatchageCanvas::find_port(const PatchageEvent::PortRef& ref)
return boost::shared_ptr<PatchagePort>();
break;
+#endif
#ifdef HAVE_ALSA
case PatchageEvent::PortRef::ALSA_ADDR:
diff --git a/src/PatchageEvent.cpp b/src/PatchageEvent.cpp
index d123188..afab9ae 100644
--- a/src/PatchageEvent.cpp
+++ b/src/PatchageEvent.cpp
@@ -22,7 +22,12 @@
#include "PatchageModule.hpp"
#include "PatchageEvent.hpp"
#include "Driver.hpp"
+#ifdef HAVE_JACK
#include "JackDriver.hpp"
+#endif
+#ifdef HAVE_JACKDBUS
+#include "JackDbusDriver.hpp"
+#endif
#ifdef HAVE_ALSA
#include "AlsaDriver.hpp"
#endif
diff --git a/src/PatchageEvent.hpp b/src/PatchageEvent.hpp
index e9357ba..3fe0623 100644
--- a/src/PatchageEvent.hpp
+++ b/src/PatchageEvent.hpp
@@ -74,8 +74,10 @@ public:
struct PortRef {
PortRef() : type(NULL_PORT_REF) { memset(&id, 0, sizeof(id)); }
+#ifdef HAVE_JACK
PortRef(jack_port_id_t jack_id, bool ign=false)
: type(JACK_ID) { id.jack_id = jack_id; }
+#endif
#ifdef HAVE_ALSA
PortRef(snd_seq_addr_t addr, bool in)
diff --git a/src/main.cpp b/src/main.cpp
index 6cf479c..0e61d9d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,7 +22,6 @@
#include <glibmm/exception.h>
#include "Patchage.hpp"
-#include "JackDriver.hpp"
#ifdef HAVE_LASH
#include <lash/lash.h>
diff --git a/src/patchage.glade b/src/patchage.glade
index 9872708..963ce5d 100644
--- a/src/patchage.glade
+++ b/src/patchage.glade
@@ -566,7 +566,8 @@ You should have received a copy of the GNU General Public License
along with Patchage; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
</property>
- <property name="authors">Dave Robillard &lt;dave@drobilla.net&gt;</property>
+ <property name="authors">Dave Robillard &lt;dave@drobilla.net&gt;
+JACK D-Bus driver by Nedko Arnaudov &lt;nedko@arnaudov.name&gt;</property>
<property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with your names, one name per line.">translator-credits</property>
<property name="artists">Icon:
Lapo Calamandrei</property>