/* -*- Mode: C ; c-basic-offset: 4 -*- */ /* Copyright (C) 2008 Nedko Arnaudov Copyright (C) 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. */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #define _GNU_SOURCE /* PTHREAD_MUTEX_RECURSIVE */ #include #include #include #include #include #include #include #include "jackdbus.h" #include "controller_internal.h" #include "list.h" #define JACK_DBUS_IFACE_NAME "org.jackaudio.JackPatchbay" /* FIXME: these need to be retrieved from common headers */ #define JACK_CLIENT_NAME_SIZE 64 #define JACK_PORT_NAME_SIZE 256 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; uint64_t next_client_id; uint64_t next_port_id; uint64_t next_connection_id; }; 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); } void jack_controller_patchbay_send_signal_port_renamed( dbus_uint64_t new_graph_version, dbus_uint64_t client_id, const char * client_name, dbus_uint64_t port_id, const char * port_old_name, const char * port_new_name) { jack_dbus_send_signal( JACK_CONTROLLER_OBJECT_PATH, JACK_DBUS_IFACE_NAME, "PortRenamed", 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_old_name, DBUS_TYPE_STRING, &port_new_name, DBUS_TYPE_INVALID); } static struct jack_graph_client * jack_controller_patchbay_find_client( struct jack_controller_patchbay *patchbay_ptr, const char *client_name, /* not '\0' terminated */ size_t client_name_len) /* without terminating '\0' */ { 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 (strlen(client_ptr->name) == client_name_len && strncmp(client_ptr->name, client_name, client_name_len) == 0) { return client_ptr; } } return NULL; } 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; } static struct jack_graph_client * jack_controller_patchbay_create_client( struct jack_controller_patchbay *patchbay_ptr, const char *client_name, /* not '\0' terminated */ size_t client_name_len) /* without terminating '\0' */ { struct jack_graph_client * client_ptr; 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 = malloc(client_name_len + 1); if (client_ptr->name == NULL) { jack_error("malloc() failed to allocate memory for client name."); goto fail_free_client; } memcpy(client_ptr->name, client_name, client_name_len); client_ptr->name[client_name_len] = 0; client_ptr->pid = jack_get_client_pid(client_ptr->name); jack_info("New client '%s' with PID %d", client_ptr->name, client_ptr->pid); client_ptr->id = patchbay_ptr->next_client_id++; INIT_LIST_HEAD(&client_ptr->ports); 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_ptr->id, client_ptr->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; } static void jack_controller_patchbay_destroy_client( struct jack_controller_patchbay *patchbay_ptr, struct jack_graph_client *client_ptr) { jack_info("Client '%s' with PID %d is out", client_ptr->name, client_ptr->pid); 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_ptr->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); } static void jack_controller_patchbay_destroy_client_by_name( struct jack_controller_patchbay *patchbay_ptr, const char *client_name) /* '\0' terminated */ { struct jack_graph_client *client_ptr; client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, client_name, strlen(client_name)); if (client_ptr == NULL) { jack_error("Cannot destroy unknown client '%s'", client_name); return; } jack_controller_patchbay_destroy_client(patchbay_ptr, client_ptr); } static void jack_controller_patchbay_new_port( struct jack_controller_patchbay *patchbay_ptr, const char *port_full_name, uint32_t port_flags, uint32_t port_type) { struct jack_graph_client *client_ptr; struct jack_graph_port *port_ptr; const char *port_short_name; size_t client_name_len; //jack_info("new port: %s", port_full_name); 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 */ client_name_len = port_short_name - port_full_name - 1; /* without terminating '\0' */ client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, port_full_name, client_name_len); if (client_ptr == NULL) { client_ptr = jack_controller_patchbay_create_client(patchbay_ptr, port_full_name, client_name_len); if (client_ptr == NULL) { jack_error("Creation of new jack_graph client failed."); return; } } port_ptr = malloc(sizeof(struct jack_graph_port)); if (port_ptr == NULL) { jack_error("Memory allocation of jack_graph_port structure failed."); return; } port_ptr->name = strdup(port_short_name); if (port_ptr->name == NULL) { jack_error("strdup() call for port name '%s' failed.", port_short_name); free(port_ptr); return; } port_ptr->id = patchbay_ptr->next_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_ptr->id, client_ptr->name, port_ptr->id, port_ptr->name, port_ptr->flags, port_ptr->type); jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version); pthread_mutex_unlock(&patchbay_ptr->lock); } static void jack_controller_patchbay_remove_port( struct jack_controller_patchbay *patchbay_ptr, struct jack_graph_port *port_ptr) { //jack_info("remove port: %s", port_ptr->name); 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, port_ptr->client->id, port_ptr->client->name, port_ptr->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); } static struct jack_graph_port * jack_controller_patchbay_find_port_by_id( struct jack_controller_patchbay *patchbay_ptr, uint64_t port_id) { struct list_head *node_ptr; struct jack_graph_port *port_ptr; list_for_each(node_ptr, &patchbay_ptr->graph.ports) { port_ptr = list_entry(node_ptr, struct jack_graph_port, siblings_graph); if (port_ptr->id == port_id) { return port_ptr; } } return NULL; } static struct jack_graph_port * jack_controller_patchbay_find_client_port_by_name( struct jack_controller_patchbay *patchbay_ptr, struct jack_graph_client *client_ptr, const char *port_name) { struct list_head *node_ptr; struct jack_graph_port *port_ptr; list_for_each(node_ptr, &client_ptr->ports) { port_ptr = list_entry(node_ptr, struct jack_graph_port, siblings_client); if (strcmp(port_ptr->name, port_name) == 0) { return port_ptr; } } return NULL; } static struct jack_graph_port * jack_controller_patchbay_find_port_by_full_name( struct jack_controller_patchbay *patchbay_ptr, const char *port_full_name) { const char *port_short_name; size_t client_name_len; struct jack_graph_client *client_ptr; //jack_info("name: %s", port_full_name); 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 NULL; } port_short_name++; /* skip ':' separator char */ client_name_len = port_short_name - port_full_name - 1; /* without terminating '\0' */ client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, port_full_name, client_name_len); if (client_ptr == NULL) { jack_error("cannot find client of port '%s'", port_full_name); return NULL; } return jack_controller_patchbay_find_client_port_by_name(patchbay_ptr, client_ptr, port_short_name); } static struct jack_graph_port * jack_controller_patchbay_find_port_by_names( struct jack_controller_patchbay *patchbay_ptr, const char *client_name, const char *port_name) { struct jack_graph_client *client_ptr; client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, client_name, strlen(client_name)); if (client_ptr == NULL) { jack_error("cannot find client '%s'", client_name); return NULL; } return jack_controller_patchbay_find_client_port_by_name(patchbay_ptr, client_ptr, port_name); } static struct jack_graph_connection * jack_controller_patchbay_create_connection( struct jack_controller_patchbay *patchbay_ptr, struct jack_graph_port *port1_ptr, struct jack_graph_port *port2_ptr) { struct jack_graph_connection * connection_ptr; 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 = patchbay_ptr->next_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, port1_ptr->client->id, port1_ptr->client->name, port1_ptr->id, port1_ptr->name, port2_ptr->client->id, port2_ptr->client->name, port2_ptr->id, port2_ptr->name, connection_ptr->id); jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version); pthread_mutex_unlock(&patchbay_ptr->lock); return connection_ptr; } static void jack_controller_patchbay_destroy_connection( struct jack_controller_patchbay *patchbay_ptr, struct jack_graph_connection *connection_ptr) { 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, connection_ptr->port1->client->id, connection_ptr->port1->client->name, connection_ptr->port1->id, connection_ptr->port1->name, connection_ptr->port2->client->id, connection_ptr->port2->client->name, connection_ptr->port2->id, connection_ptr->port2->name, connection_ptr->id); jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version); pthread_mutex_unlock(&patchbay_ptr->lock); free(connection_ptr); } static struct jack_graph_connection * jack_controller_patchbay_find_connection( struct jack_controller_patchbay *patchbay_ptr, struct jack_graph_port *port1_ptr, struct jack_graph_port *port2_ptr) { struct list_head *node_ptr; struct jack_graph_connection *connection_ptr; list_for_each(node_ptr, &patchbay_ptr->graph.connections) { connection_ptr = list_entry(node_ptr, struct jack_graph_connection, siblings); if ((connection_ptr->port1 == port1_ptr && connection_ptr->port2 == port2_ptr) || (connection_ptr->port1 == port2_ptr && connection_ptr->port2 == port1_ptr)) { return connection_ptr; } } return NULL; } static struct jack_graph_connection * jack_controller_patchbay_find_connection_by_id( struct jack_controller_patchbay *patchbay_ptr, uint64_t connection_id) { struct list_head *node_ptr; struct jack_graph_connection *connection_ptr; list_for_each(node_ptr, &patchbay_ptr->graph.connections) { connection_ptr = list_entry(node_ptr, struct jack_graph_connection, siblings); if (connection_ptr->id == connection_id) { return connection_ptr; } } return NULL; } static bool jack_controller_patchbay_connect( struct jack_dbus_method_call *dbus_call_ptr, struct jack_controller *controller_ptr, struct jack_graph_port *port1_ptr, struct jack_graph_port *port2_ptr) { int ret; char port1_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char port2_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; sprintf(port1_name, "%s:%s", port1_ptr->client->name, port1_ptr->name); sprintf(port2_name, "%s:%s", port2_ptr->client->name, port2_ptr->name); ret = jack_connect(controller_ptr->client, port1_name, port2_name); if (ret != 0) { jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_connect() failed with %d", ret); return false; } return true; } static bool jack_controller_patchbay_disconnect( struct jack_dbus_method_call *dbus_call_ptr, struct jack_controller *controller_ptr, struct jack_graph_port *port1_ptr, struct jack_graph_port *port2_ptr) { int ret; char port1_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char port2_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; sprintf(port1_name, "%s:%s", port1_ptr->client->name, port1_ptr->name); sprintf(port2_name, "%s:%s", port2_ptr->client->name, port2_ptr->name); ret = jack_disconnect(controller_ptr->client, port1_name, port2_name); if (ret != 0) { jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_disconnect() failed with %d", ret); return false; } return true; } #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; if (!controller_ptr->started) { jack_dbus_error( call, JACK_DBUS_ERROR_SERVER_NOT_RUNNING, "Can't execute this method with stopped JACK server"); return; } 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 (!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, &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; struct jack_graph_port *port1_ptr; struct jack_graph_port *port2_ptr; /* 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); */ pthread_mutex_lock(&patchbay_ptr->lock); port1_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client1_name, port1_name); if (port1_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client1_name, port1_name); goto unlock; } port2_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client2_name, port2_name); if (port2_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client2_name, port2_name); goto unlock; } if (!jack_controller_patchbay_connect( call, controller_ptr, port1_ptr, port2_ptr)) { /* jack_controller_patchbay_connect() constructed error reply */ goto unlock; } jack_dbus_construct_method_return_empty(call); unlock: pthread_mutex_unlock(&patchbay_ptr->lock); } static void jack_controller_dbus_connect_ports_by_id( struct jack_dbus_method_call * call) { dbus_uint64_t port1_id; dbus_uint64_t port2_id; struct jack_graph_port *port1_ptr; struct jack_graph_port *port2_ptr; /* 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_id, DBUS_TYPE_UINT64, &port2_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); port1_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port1_id); if (port1_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port1_id); goto unlock; } port2_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port2_id); if (port2_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port2_id); goto unlock; } if (!jack_controller_patchbay_connect( call, controller_ptr, port1_ptr, port2_ptr)) { /* jack_controller_patchbay_connect() constructed error reply */ goto unlock; } jack_dbus_construct_method_return_empty(call); unlock: pthread_mutex_unlock(&patchbay_ptr->lock); } 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; struct jack_graph_port *port1_ptr; struct jack_graph_port *port2_ptr; /* 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); */ pthread_mutex_lock(&patchbay_ptr->lock); port1_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client1_name, port1_name); if (port1_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client1_name, port1_name); goto unlock; } port2_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client2_name, port2_name); if (port2_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client2_name, port2_name); goto unlock; } if (!jack_controller_patchbay_disconnect( call, controller_ptr, port1_ptr, port2_ptr)) { /* jack_controller_patchbay_connect() constructed error reply */ goto unlock; } jack_dbus_construct_method_return_empty(call); unlock: pthread_mutex_unlock(&patchbay_ptr->lock); } static void jack_controller_dbus_disconnect_ports_by_id( struct jack_dbus_method_call * call) { dbus_uint64_t port1_id; dbus_uint64_t port2_id; struct jack_graph_port *port1_ptr; struct jack_graph_port *port2_ptr; /* 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_id, DBUS_TYPE_UINT64, &port2_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); port1_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port1_id); if (port1_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port1_id); goto unlock; } port2_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port2_id); if (port2_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port2_id); goto unlock; } if (!jack_controller_patchbay_disconnect( call, controller_ptr, port1_ptr, port2_ptr)) { /* jack_controller_patchbay_connect() constructed error reply */ goto unlock; } jack_dbus_construct_method_return_empty(call); unlock: pthread_mutex_unlock(&patchbay_ptr->lock); } static void jack_controller_dbus_disconnect_ports_by_connection_id( struct jack_dbus_method_call * call) { dbus_uint64_t connection_id; struct jack_graph_connection *connection_ptr; /* jack_info("jack_controller_dbus_disconnect_ports_by_id() called."); */ if (!jack_dbus_get_method_args( call, DBUS_TYPE_UINT64, &connection_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); connection_ptr = jack_controller_patchbay_find_connection_by_id(patchbay_ptr, connection_id); if (connection_ptr == NULL) { jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find connection %" PRIu64, connection_id); goto unlock; } if (!jack_controller_patchbay_disconnect( call, controller_ptr, connection_ptr->port1, connection_ptr->port2)) { /* jack_controller_patchbay_connect() constructed error reply */ goto unlock; } jack_dbus_construct_method_return_empty(call); unlock: pthread_mutex_unlock(&patchbay_ptr->lock); } 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 #define controller_ptr ((struct jack_controller *)context) static int jack_controller_graph_order_callback( void *context) { const char **ports; int i; jack_port_t *port_ptr; if (patchbay_ptr->graph.version > 1) { /* we use this only for initial catchup */ return 0; } ports = jack_get_ports(controller_ptr->client, NULL, NULL, 0); if (ports) { for (i = 0; ports[i]; ++i) { jack_info("graph reorder: new port '%s'", ports[i]); port_ptr = jack_port_by_name(controller_ptr->client, ports[i]);; jack_controller_patchbay_new_port(patchbay_ptr, ports[i], jack_port_flags(port_ptr), jack_port_type_id(port_ptr)); } free(ports); } if (patchbay_ptr->graph.version == 1) { /* we have empty initial graph, increment graph version, so we don't do jack_get_ports() again, on next next graph change */ patchbay_ptr->graph.version++; } return 0; } void jack_controller_client_registration_callback( const char *client_name, int created, void *context) { if (created) { jack_log("client '%s' created", client_name); jack_controller_patchbay_create_client(patchbay_ptr, client_name, strlen(client_name)); } else { jack_log("client '%s' destroyed", client_name); jack_controller_patchbay_destroy_client_by_name(patchbay_ptr, client_name); } } void jack_controller_port_registration_callback( jack_port_id_t port_id, int created, void *context) { jack_port_t *port_ptr; struct jack_graph_port *graph_port_ptr; const char *port_name; port_ptr = jack_port_by_id(controller_ptr->client, port_id); port_name = jack_port_name(port_ptr); if (created) { jack_log("port '%s' created", port_name); jack_controller_patchbay_new_port(patchbay_ptr, port_name, jack_port_flags(port_ptr), jack_port_type_id(port_ptr)); } else { jack_log("port '%s' destroyed", port_name); graph_port_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port_name); if (graph_port_ptr == NULL) { jack_error("Failed to find port '%s' to destroy", port_name); return; } jack_controller_patchbay_remove_port(patchbay_ptr, graph_port_ptr); } } void jack_controller_port_connect_callback( jack_port_id_t port1_id, jack_port_id_t port2_id, int connect, void *context) { jack_port_t *port1; jack_port_t *port2; const char *port1_name; const char *port2_name; struct jack_graph_port *port1_ptr; struct jack_graph_port *port2_ptr; struct jack_graph_connection *connection_ptr; port1 = jack_port_by_id(controller_ptr->client, port1_id); port2 = jack_port_by_id(controller_ptr->client, port2_id); port1_name = jack_port_name(port1); port2_name = jack_port_name(port2); port1_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port1_name); if (port1_ptr == NULL) { jack_error("Failed to find port '%s' to [dis]connect", port1_name); return; } port2_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port2_name); if (port2_ptr == NULL) { jack_error("Failed to find port '%s' to [dis]connect", port2_name); return; } if (connect) { jack_info("Connecting '%s' to '%s'", port1_name, port2_name); connection_ptr = jack_controller_patchbay_find_connection(patchbay_ptr, port1_ptr, port2_ptr); if (connection_ptr != NULL) { jack_error("'%s' and '%s' are already connected", port1_name, port2_name); return; } jack_controller_patchbay_create_connection(patchbay_ptr, port1_ptr, port2_ptr); } else { jack_info("Disconnecting '%s' from '%s'", port1_name, port2_name); connection_ptr = jack_controller_patchbay_find_connection(patchbay_ptr, port1_ptr, port2_ptr); if (connection_ptr == NULL) { jack_error("Cannot find connection being removed"); return; } jack_controller_patchbay_destroy_connection(patchbay_ptr, connection_ptr); } } void jack_controller_port_rename_callback(jack_port_id_t port, const char * old_name, const char * new_name, void * context) { struct jack_graph_port * port_ptr; const char * port_new_short_name; const char * port_old_short_name; char * name_buffer; jack_info("port renamed: '%s' -> '%s'", old_name, new_name); port_new_short_name = strchr(new_name, ':'); if (port_new_short_name == NULL) { jack_error("renamed port new name '%s' does not contain ':' separator char", new_name); return; } port_new_short_name++; /* skip ':' separator char */ port_old_short_name = strchr(old_name, ':'); if (port_old_short_name == NULL) { jack_error("renamed port old name '%s' does not contain ':' separator char", old_name); return; } port_old_short_name++; /* skip ':' separator char */ port_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, old_name); if (port_ptr == NULL) { jack_error("renamed port '%s' not found", old_name); return; } name_buffer = strdup(port_new_short_name); if (name_buffer == NULL) { jack_error("strdup() call for port name '%s' failed.", port_new_short_name); return; } free(port_ptr->name); port_ptr->name = name_buffer; pthread_mutex_lock(&patchbay_ptr->lock); patchbay_ptr->graph.version++; jack_controller_patchbay_send_signal_port_renamed( patchbay_ptr->graph.version, port_ptr->client->id, port_ptr->client->name, port_ptr->id, port_old_short_name, port_ptr->name); jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version); pthread_mutex_unlock(&patchbay_ptr->lock); } #undef controller_ptr void jack_controller_patchbay_uninit( struct jack_controller * controller_ptr) { struct jack_graph_client *client_ptr; struct jack_graph_port *port_ptr; /* jack_info("jack_controller_patchbay_uninit() called"); */ while (!list_empty(&patchbay_ptr->graph.ports)) { port_ptr = list_entry(patchbay_ptr->graph.ports.next, struct jack_graph_port, siblings_graph); jack_controller_patchbay_remove_port(patchbay_ptr, port_ptr); } while (!list_empty(&patchbay_ptr->graph.clients)) { client_ptr = list_entry(patchbay_ptr->graph.clients.next, struct jack_graph_client, siblings); jack_controller_patchbay_destroy_client(patchbay_ptr, client_ptr); } pthread_mutex_destroy(&patchbay_ptr->lock); } #undef patchbay_ptr bool jack_controller_patchbay_init( struct jack_controller * controller_ptr) { int ret; struct jack_controller_patchbay * patchbay_ptr; pthread_mutexattr_t attr; /* 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."); goto fail; } ret = pthread_mutexattr_init(&attr); if (ret != 0) { goto fail; } ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); if (ret != 0) { goto fail; } pthread_mutex_init(&patchbay_ptr->lock, &attr); 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; patchbay_ptr->next_client_id = 1; patchbay_ptr->next_port_id = 1; patchbay_ptr->next_connection_id = 1; controller_ptr->patchbay_context = patchbay_ptr; ret = jack_set_graph_order_callback(controller_ptr->client, jack_controller_graph_order_callback, controller_ptr); if (ret != 0) { jack_error("jack_set_graph_order_callback() failed with error %d", ret); goto fail_uninit_mutex; } ret = jack_set_client_registration_callback(controller_ptr->client, jack_controller_client_registration_callback, controller_ptr); if (ret != 0) { jack_error("jack_set_client_registration_callback() failed with error %d", ret); goto fail_uninit_mutex; } ret = jack_set_port_registration_callback(controller_ptr->client, jack_controller_port_registration_callback, controller_ptr); if (ret != 0) { jack_error("jack_set_port_registration_callback() failed with error %d", ret); goto fail_uninit_mutex; } ret = jack_set_port_connect_callback(controller_ptr->client, jack_controller_port_connect_callback, controller_ptr); if (ret != 0) { jack_error("jack_set_port_connect_callback() failed with error %d", ret); goto fail_uninit_mutex; } ret = jack_set_port_rename_callback(controller_ptr->client, jack_controller_port_rename_callback, controller_ptr); if (ret != 0) { jack_error("jack_set_port_rename_callback() failed with error %d", ret); goto fail_uninit_mutex; } return true; fail_uninit_mutex: pthread_mutex_destroy(&patchbay_ptr->lock); fail: return false; } 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 JACK_DBUS_METHODS_BEGIN 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_METHODS_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 JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortRenamed) JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING) JACK_DBUS_SIGNAL_ARGUMENT("port_id", 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_old_name", DBUS_TYPE_STRING_AS_STRING) JACK_DBUS_SIGNAL_ARGUMENT("port_new_name", DBUS_TYPE_STRING_AS_STRING) JACK_DBUS_SIGNAL_ARGUMENTS_END JACK_DBUS_SIGNALS_BEGIN 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(PortRenamed) JACK_DBUS_SIGNALS_END JACK_DBUS_IFACE_BEGIN(g_jack_controller_iface_patchbay, JACK_DBUS_IFACE_NAME) JACK_DBUS_IFACE_EXPOSE_METHODS JACK_DBUS_IFACE_EXPOSE_SIGNALS JACK_DBUS_IFACE_END