diff --git a/daemon/common.h b/daemon/common.h index e53c1ef0..56017a30 100644 --- a/daemon/common.h +++ b/daemon/common.h @@ -38,29 +38,6 @@ #define BASE_DIR "/." BASE_NAME extern char * g_base_dir; -/* JACK port or virtual port */ -struct port -{ - struct list_head siblings_studio_all; /* link for the studio::all_ports list */ - struct list_head siblings_studio; /* link for the studio::ports list */ - struct list_head siblings_room; /* link for the room::ports list */ - struct list_head siblings_client; /* link for the port list of the client */ - struct list_head siblings_vclient; /* link for the port list of the virtual client */ - - uuid_t uuid; /* The UUID of the port */ - bool virtual; /* Whether the port is virtual or JACK port */ - char * jack_name; /* JACK name (short). Not valid for virtual ports. */ - uint64_t jack_id; /* JACK port ID. Not valid for virtual ports. */ - char * human_name; /* User assigned name */ - - struct client * client_ptr; /* JACK client this port belongs to. Not valid for virtual ports. */ - struct client * vclient_ptr; /* Virtual client this port belongs to. NULL if there is no virtual client associated. */ - - /* superconnections are not in these lists */ - struct list_head input_connections; /* list of input connections, i.e. connections that play to this port */ - struct list_head output_connections; /* list of output connections, i.e. connections that capture from this port */ -}; - /* connection between two ports */ /* virtual connection is connection where at least one the ports is virtual */ /* superconnection is connection that implements virtual connection chain at JACK level */ diff --git a/daemon/graph.c b/daemon/graph.c index 1c6a5826..a523b781 100644 --- a/daemon/graph.c +++ b/daemon/graph.c @@ -30,18 +30,31 @@ #include "../dbus/error.h" #include "../dbus_constants.h" +struct ladish_graph_port +{ + struct list_head siblings_client; + struct list_head siblings_graph; + char * name; + uint32_t type; + uint32_t flags; + uint64_t id; + ladish_port_handle port; +}; + struct ladish_graph_client { struct list_head siblings; char * name; uint64_t id; ladish_client_handle client; + struct list_head ports; }; struct ladish_graph { char * opath; struct list_head clients; + struct list_head ports; uint64_t graph_version; uint64_t next_client_id; uint64_t next_port_id; @@ -93,10 +106,10 @@ static void get_graph(struct dbus_method_call * call_ptr) struct list_head * client_node_ptr; struct ladish_graph_client * client_ptr; DBusMessageIter ports_array_iter; -#if 0 + struct list_head * port_node_ptr; + struct ladish_graph_port * port_ptr; DBusMessageIter port_struct_iter; - DBusMessageIter connection_struct_iter; -#endif + //DBusMessageIter connection_struct_iter; //lash_info("get_graph() called"); @@ -167,10 +180,9 @@ static void get_graph(struct dbus_method_call * call_ptr) goto nomem_close_client_struct; } -#if 0 list_for_each(port_node_ptr, &client_ptr->ports) { - port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client); + port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client); if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter)) { @@ -202,7 +214,6 @@ static void get_graph(struct dbus_method_call * call_ptr) goto nomem_close_ports_array; } } -#endif if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter)) { @@ -305,13 +316,13 @@ nomem_close_connection_struct: nomem_close_connections_array: dbus_message_iter_close_container(&iter, &connections_array_iter); goto nomem_unlock; +#endif 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); -#endif nomem_close_client_struct: dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter); @@ -380,6 +391,7 @@ bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * op } INIT_LIST_HEAD(&graph_ptr->clients); + INIT_LIST_HEAD(&graph_ptr->ports); graph_ptr->graph_version = 1; graph_ptr->next_client_id = 1; @@ -411,11 +423,52 @@ ladish_graph_find_client( return NULL; } +void +ladish_graph_remove_port_internal( + struct ladish_graph * graph_ptr, + struct ladish_graph_client * client_ptr, + struct ladish_graph_port * port_ptr, + bool destroy) +{ + if (destroy) + { + ladish_port_destroy(port_ptr->port); + } + + list_del(&port_ptr->siblings_client); + list_del(&port_ptr->siblings_graph); + + lash_info("removing port '%s':'%s' (%llu:%llu)", client_ptr->name, port_ptr->name, (unsigned long long)client_ptr->id, (unsigned long long)port_ptr->id); + dbus_signal_emit( + g_dbus_connection, + graph_ptr->opath, + JACKDBUS_IFACE_PATCHBAY, + "PortDisappeared", + "ttsts", + &graph_ptr->graph_version, + &client_ptr->id, + &client_ptr->name, + &port_ptr->id, + &port_ptr->name); + + free(port_ptr->name); + free(port_ptr); +} + void ladish_graph_remove_client_internal( struct ladish_graph * graph_ptr, - struct ladish_graph_client * client_ptr) + struct ladish_graph_client * client_ptr, + bool destroy_ports) { + struct ladish_graph_port * port_ptr; + + while (!list_empty(&client_ptr->ports)) + { + port_ptr = list_entry(client_ptr->ports.next, struct ladish_graph_port, siblings_client); + ladish_graph_remove_port_internal(graph_ptr, client_ptr, port_ptr, destroy_ports); + } + graph_ptr->graph_version++; list_del(&client_ptr->siblings); lash_info("removing client '%s' (%llu)", client_ptr->name, (unsigned long long)client_ptr->id); @@ -428,6 +481,7 @@ ladish_graph_remove_client_internal( &graph_ptr->graph_version, &client_ptr->id, &client_ptr->name); + free(client_ptr->name); free(client_ptr); } @@ -450,7 +504,7 @@ void ladish_graph_clear(ladish_graph_handle graph_handle) while (!list_empty(&graph_ptr->clients)) { client_ptr = list_entry(graph_ptr->clients.next, struct ladish_graph_client, siblings); - ladish_graph_remove_client_internal(graph_ptr, client_ptr); + ladish_graph_remove_client_internal(graph_ptr, client_ptr, true); } } @@ -468,7 +522,7 @@ bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_han client_ptr = malloc(sizeof(struct ladish_graph_client)); if (client_ptr == NULL) { - lash_error("malloc() failed for struct ladish_client_link_ptr"); + lash_error("malloc() failed for struct ladish_graph_client"); return false; } @@ -484,6 +538,8 @@ bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_han client_ptr->client = client_handle; graph_ptr->graph_version++; + INIT_LIST_HEAD(&client_ptr->ports); + list_add_tail(&client_ptr->siblings, &graph_ptr->clients); dbus_signal_emit( @@ -499,7 +555,11 @@ bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_han return true; } -void ladish_graph_remove_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle) +void +ladish_graph_remove_client( + ladish_graph_handle graph_handle, + ladish_client_handle client_handle, + bool destroy_ports) { struct ladish_graph_client * client_ptr; @@ -508,7 +568,7 @@ void ladish_graph_remove_client(ladish_graph_handle graph_handle, ladish_client_ client_ptr = ladish_graph_find_client(graph_ptr, client_handle); if (client_ptr != NULL) { - ladish_graph_remove_client_internal(graph_ptr, client_ptr); + ladish_graph_remove_client_internal(graph_ptr, client_ptr, destroy_ports); } else { @@ -516,6 +576,70 @@ void ladish_graph_remove_client(ladish_graph_handle graph_handle, ladish_client_ } } +bool +ladish_graph_add_port( + ladish_graph_handle graph_handle, + ladish_client_handle client_handle, + ladish_port_handle port_handle, + const char * name, + uint32_t type, + uint32_t flags) +{ + struct ladish_graph_client * client_ptr; + struct ladish_graph_port * port_ptr; + + client_ptr = ladish_graph_find_client(graph_ptr, client_handle); + if (client_ptr == NULL) + { + lash_error("cannot find client to add port to"); + assert(false); + return false; + } + + lash_info("adding port '%s':'%s' (%p)to graph %s", client_ptr->name, name, port_handle, graph_ptr->opath); + + port_ptr = malloc(sizeof(struct ladish_graph_port)); + if (port_ptr == NULL) + { + lash_error("malloc() failed for struct ladish_graph_port"); + return false; + } + + port_ptr->name = strdup(name); + if (port_ptr->name == NULL) + { + lash_error("strdup() failed for graph port name"); + free(port_ptr); + return false; + } + + port_ptr->type = type; + port_ptr->flags = flags; + + port_ptr->id = graph_ptr->next_port_id++; + port_ptr->port = port_handle; + graph_ptr->graph_version++; + + list_add_tail(&port_ptr->siblings_client, &client_ptr->ports); + list_add_tail(&port_ptr->siblings_graph, &graph_ptr->ports); + + dbus_signal_emit( + g_dbus_connection, + graph_ptr->opath, + JACKDBUS_IFACE_PATCHBAY, + "PortAppeared", + "ttstsuu", + &graph_ptr->graph_version, + &client_ptr->id, + &client_ptr->name, + &port_ptr->id, + &port_ptr->name, + &flags, + &type); + + return true; +} + #undef graph_ptr METHOD_ARGS_BEGIN(GetAllPorts, "Get all ports") diff --git a/daemon/graph.h b/daemon/graph.h index 3a781028..8c42f609 100644 --- a/daemon/graph.h +++ b/daemon/graph.h @@ -28,6 +28,7 @@ #define PATCHBAY_H__30334B9A_8847_4E8C_AFF9_73DB13406C8E__INCLUDED #include "client.h" +#include "port.h" typedef struct ladish_graph_tag { int unused; } * ladish_graph_handle; @@ -36,7 +37,27 @@ void ladish_graph_destroy(ladish_graph_handle graph_handle); void ladish_graph_clear(ladish_graph_handle graph_handle); void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle); bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name); -void ladish_graph_remove_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle); + +void +ladish_graph_remove_client( + ladish_graph_handle graph_handle, + ladish_client_handle client_handle, + bool destroy_ports); + +bool +ladish_graph_add_port( + ladish_graph_handle graph_handle, + ladish_client_handle client_handle, + ladish_port_handle port_handle, + const char * name, + uint32_t type, + uint32_t flags); + +void +ladish_graph_remove_port( + ladish_graph_handle graph_handle, + ladish_client_handle client_handle, + ladish_port_handle port_handle); extern const struct dbus_interface_descriptor g_interface_patchbay; diff --git a/daemon/jack_dispatch.c b/daemon/jack_dispatch.c index 269fe67d..7fe6a5bc 100644 --- a/daemon/jack_dispatch.c +++ b/daemon/jack_dispatch.c @@ -25,6 +25,7 @@ */ #include "jack_dispatch.h" +#include "../dbus_constants.h" struct jack_dispatcher { @@ -71,21 +72,80 @@ static void client_disappeared(void * context, uint64_t id) static void port_appeared(void * context, uint64_t client_id, uint64_t port_id, const char * port_name, bool is_input, bool is_terminal, bool is_midi) { + ladish_client_handle client; + ladish_port_handle port; + uint32_t type; + uint32_t flags; + lash_info("port_appeared(%llu, %llu, %s (%s, %s))", (unsigned long long)client_id, (unsigned long long)port_id, port_name, is_input ? "in" : "out", is_midi ? "midi" : "audio"); if (client_id == dispatcher_ptr->system_client_id) { - if (!is_input && dispatcher_ptr->system_capture_client == NULL) + if (!is_input) { - ladish_client_create(NULL, true, false, true, &dispatcher_ptr->system_capture_client); - ladish_graph_add_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_capture_client, "Hardware Capture"); + if (dispatcher_ptr->system_capture_client == NULL) + { + if (!ladish_client_create(NULL, true, false, true, &dispatcher_ptr->system_capture_client)) + { + lash_error("ladish_client_create() failed."); + return; + } + + if (!ladish_graph_add_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_capture_client, "Hardware Capture")) + { + lash_error("ladish_graph_add_client() failed."); + ladish_graph_remove_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_capture_client, true); + dispatcher_ptr->system_capture_client = NULL; + return; + } + } + + client = dispatcher_ptr->system_capture_client; } - else if (is_input && dispatcher_ptr->system_playback_client == NULL) + else { - ladish_client_create(NULL, true, false, true, &dispatcher_ptr->system_playback_client); - ladish_graph_add_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_playback_client, "Hardware Playback"); + if (dispatcher_ptr->system_playback_client == NULL) + { + if (!ladish_client_create(NULL, true, false, true, &dispatcher_ptr->system_playback_client)) + { + lash_error("ladish_client_create() failed."); + return; + } + + if (!ladish_graph_add_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_playback_client, "Hardware Playback")) + { + ladish_graph_remove_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_playback_client, true); + dispatcher_ptr->system_playback_client = NULL; + return; + } + } + + client = dispatcher_ptr->system_playback_client; } } + else + { + return; /* TODO: find client by client_id */ + } + + type = is_midi ? JACKDBUS_PORT_TYPE_MIDI : JACKDBUS_PORT_TYPE_AUDIO; + flags = is_input ? JACKDBUS_PORT_FLAG_INPUT : JACKDBUS_PORT_FLAG_OUTPUT; + if (is_terminal) + { + flags |= JACKDBUS_PORT_FLAG_TERMINAL; + } + + if (!ladish_port_create(NULL, &port)) + { + lash_error("ladish_port_create() failed."); + return; + } + + if (!ladish_graph_add_port(dispatcher_ptr->studio_graph, client, port, port_name, type, flags)) + { + lash_error("ladish_graph_add_port() failed."); + return; + } } static void port_disappeared(void * context, uint64_t client_id, uint64_t port_id) @@ -155,12 +215,12 @@ ladish_jack_dispatcher_destroy( if (dispatcher_ptr->system_capture_client != NULL) { - ladish_graph_remove_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_capture_client); + ladish_graph_remove_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_capture_client, true); } if (dispatcher_ptr->system_playback_client != NULL) { - ladish_graph_remove_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_playback_client); + ladish_graph_remove_client(dispatcher_ptr->studio_graph, dispatcher_ptr->system_playback_client, true); } } diff --git a/daemon/port.c b/daemon/port.c new file mode 100644 index 00000000..87af54cb --- /dev/null +++ b/daemon/port.c @@ -0,0 +1,93 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2009 Nedko Arnaudov + * + ************************************************************************** + * This file contains the implementation of the port objects + ************************************************************************** + * + * LADI Session Handler 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. + * + * LADI Session Handler 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 LADI Session Handler. If not, see + * or write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "port.h" + +/* JACK port or virtual port */ +struct ladish_port +{ + struct list_head siblings_studio_all; /* link for the studio::all_ports list */ + struct list_head siblings_studio; /* link for the studio::ports list */ + struct list_head siblings_room; /* link for the room::ports list */ + struct list_head siblings_client; /* link for the port list of the client */ + struct list_head siblings_vclient; /* link for the port list of the virtual client */ + + uuid_t uuid; /* The UUID of the port */ + bool virtual; /* Whether the port is virtual or JACK port */ + char * jack_name; /* JACK name (short). Not valid for virtual ports. */ + uint64_t jack_id; /* JACK port ID. Not valid for virtual ports. */ + char * human_name; /* User assigned name */ + + struct client * client_ptr; /* JACK client this port belongs to. Not valid for virtual ports. */ + struct client * vclient_ptr; /* Virtual client this port belongs to. NULL if there is no virtual client associated. */ + + /* superconnections are not in these lists */ + struct list_head input_connections; /* list of input connections, i.e. connections that play to this port */ + struct list_head output_connections; /* list of output connections, i.e. connections that capture from this port */ +}; + +bool +ladish_port_create( + uuid_t uuid_ptr, + ladish_port_handle * port_handle_ptr) +{ + struct ladish_port * port_ptr; + + port_ptr = malloc(sizeof(struct ladish_port)); + if (port_ptr == NULL) + { + lash_error("malloc() failed to allocate struct ladish_port"); + return false; + } + + if (uuid_ptr == NULL) + { + uuid_generate(port_ptr->uuid); + } + else + { + uuid_copy(port_ptr->uuid, uuid_ptr); + } + + INIT_LIST_HEAD(&port_ptr->siblings_studio_all); + INIT_LIST_HEAD(&port_ptr->siblings_room); + port_ptr->jack_id = 0; + port_ptr->jack_name = NULL; + port_ptr->human_name = NULL; + port_ptr->virtual = true; + + *port_handle_ptr = (ladish_port_handle)port_ptr; + return true; +} + +#define port_ptr ((struct ladish_port * )port_handle) + +void ladish_port_destroy(ladish_port_handle port_handle) +{ + free(port_ptr); +} + +#undef port_ptr diff --git a/daemon/port.h b/daemon/port.h new file mode 100644 index 00000000..d2120663 --- /dev/null +++ b/daemon/port.h @@ -0,0 +1,37 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2009 Nedko Arnaudov + * + ************************************************************************** + * This file contains the interface of the port objects + ************************************************************************** + * + * LADI Session Handler 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. + * + * LADI Session Handler 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 LADI Session Handler. If not, see + * or write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PORT_H__62F81E7C_91FA_44AB_94A9_E0E2D226ED58__INCLUDED +#define PORT_H__62F81E7C_91FA_44AB_94A9_E0E2D226ED58__INCLUDED + +#include "common.h" + +typedef struct ladish_port_tag { int unused; } * ladish_port_handle; + +bool ladish_port_create(uuid_t uuid_ptr, ladish_port_handle * port_handle_ptr); +void ladish_port_destroy(ladish_port_handle port_handle); + +#endif /* #ifndef PORT_H__62F81E7C_91FA_44AB_94A9_E0E2D226ED58__INCLUDED */ diff --git a/dbus_constants.h b/dbus_constants.h index 92fa75ec..519d331a 100644 --- a/dbus_constants.h +++ b/dbus_constants.h @@ -44,4 +44,13 @@ #define APPLICATION_OBJECT_PATH DBUS_BASE_PATH "/Application" #define IFACE_APPLICATION DBUS_NAME_BASE ".App" +#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 + #endif /* #ifndef DBUS_CONSTANTS_H__C21DE0EE_C19C_42F0_8D63_D613E4806C0E__INCLUDED */ diff --git a/graph_proxy.c b/graph_proxy.c index 2ec1b0e8..ee680300 100644 --- a/graph_proxy.c +++ b/graph_proxy.c @@ -35,15 +35,6 @@ #include "dbus/helpers.h" #include "dbus_constants.h" -#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 - struct monitor { struct list_head siblings; diff --git a/wscript b/wscript index a5f51c00..7f076653 100644 --- a/wscript +++ b/wscript @@ -201,6 +201,7 @@ def build(bld): 'studio.c', 'graph.c', 'client.c', + 'port.c', 'jack_dispatch.c', ]: daemon.source.append(os.path.join("daemon", source))