From 3fb3fcc75e99f8f3707d6f157999797fcdff911b Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Sun, 6 Sep 2009 00:13:05 +0300 Subject: [PATCH] Virtual clients in studio graph --- daemon/client.c | 259 +++++++++++++++++++++++++++++++++++++++++++ daemon/client.h | 81 ++++++++++++++ daemon/common.h | 17 --- daemon/graph_iface.c | 112 +++++++++++++++++-- daemon/graph_iface.h | 13 ++- daemon/studio.c | 67 +++++++---- wscript | 1 + 7 files changed, 493 insertions(+), 57 deletions(-) create mode 100644 daemon/client.c create mode 100644 daemon/client.h diff --git a/daemon/client.c b/daemon/client.c new file mode 100644 index 00000000..c2b4357b --- /dev/null +++ b/daemon/client.c @@ -0,0 +1,259 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2009 Nedko Arnaudov + * + ************************************************************************** + * This file contains the implementation of the client 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 "common.h" +#include "client.h" + +struct ladish_client_graph_name +{ + struct list_head siblings; + char * graph_opath; + char * client_name; +}; + +struct ladish_client +{ + struct list_head siblings_studio_all; /* link for the studio::all_clients list */ + struct list_head siblings_room; /* link for the room::clients list */ + struct list_head siblings_graph; + struct list_head ports; /* List of ports that belong to the client */ + uint64_t graph_id; + uuid_t uuid; /* The UUID of the client */ + uint64_t jack_id; /* JACK client ID */ + char * jack_name; /* JACK name, not valid for virtual clients */ + char * human_name; /* User assigned name, not valid for studio-room link clients */ + bool virtual:1; /* Whether client is virtual */ + bool link:1; /* Whether client is a studio-room link */ + bool system:1; /* Whether client is system (server in-process) */ + pid_t pid; /* process id. Not valid for system and virtual clients */ + struct room * room_ptr; /* Room this client belongs to. If NULL, client belongs only to studio guts. */ + struct list_head graph_names; +}; + +bool +ladish_client_create( + uuid_t uuid_ptr, + bool virtual, + bool link, + bool system, + ladish_client_handle * client_handle_ptr) +{ + struct ladish_client * client_ptr; + + client_ptr = malloc(sizeof(struct ladish_client)); + if (client_ptr == NULL) + { + lash_error("malloc() failed to allocate struct ladish_client"); + return false; + } + + if (uuid_ptr == NULL) + { + uuid_generate(client_ptr->uuid); + } + else + { + uuid_copy(client_ptr->uuid, uuid_ptr); + } + + INIT_LIST_HEAD(&client_ptr->siblings_studio_all); + INIT_LIST_HEAD(&client_ptr->siblings_room); + INIT_LIST_HEAD(&client_ptr->siblings_graph); + INIT_LIST_HEAD(&client_ptr->ports); + client_ptr->graph_id = 0; + client_ptr->jack_id = 0; + client_ptr->jack_name = NULL; + client_ptr->human_name = NULL; + client_ptr->virtual = virtual; + client_ptr->link = link; + client_ptr->system = system; + client_ptr->pid = 0; + client_ptr->room_ptr = NULL; + INIT_LIST_HEAD(&client_ptr->graph_names); + + *client_handle_ptr = (ladish_client_handle)client_ptr; + return true; +} + +#define client_ptr ((struct ladish_client *)client_handle) + +bool +ladish_client_set_graph_name( + ladish_client_handle client_handle, + const char * opath, + const char * name) +{ + struct ladish_client_graph_name * graph_name; + + lash_info("setting %s name of client %p to '%s'", opath, client_handle, name); + + graph_name = malloc(sizeof(struct ladish_client_graph_name)); + if (graph_name == NULL) + { + lash_error("malloc() failed for struct ladish_client_graph_name"); + return false; + } + + graph_name->graph_opath = strdup(opath); + if (graph_name->graph_opath == NULL) + { + lash_error("strdup() failed for graph opath"); + free(graph_name); + return false; + } + + graph_name->client_name = strdup(name); + if (graph_name->client_name == NULL) + { + lash_error("strdup() failed for graph client name"); + free(graph_name->graph_opath); + free(graph_name); + return false; + } + + list_add_tail(&graph_name->siblings, &client_ptr->graph_names); + return true; +} + +void +ladish_client_drop_graph_name( + ladish_client_handle client_handle, + const char * opath) +{ + struct list_head * node_ptr; + struct ladish_client_graph_name * graph_name; + + list_for_each(node_ptr, &client_ptr->graph_names) + { + graph_name = list_entry(node_ptr, struct ladish_client_graph_name, siblings); + if (strcmp(opath, graph_name->graph_opath) == 0) + { + list_del(node_ptr); + free(graph_name->client_name); + free(graph_name->graph_opath); + free(graph_name); + return; + } + } +} + +const char * +ladish_client_get_graph_name( + ladish_client_handle client_handle, + const char * opath) +{ + struct list_head * node_ptr; + struct ladish_client_graph_name * graph_name; + + list_for_each(node_ptr, &client_ptr->graph_names) + { + graph_name = list_entry(node_ptr, struct ladish_client_graph_name, siblings); + if (strcmp(opath, graph_name->graph_opath) == 0) + { + return graph_name->client_name; + } + } + + return NULL; +} + +void +ladish_client_set_graph_id( + ladish_client_handle client_handle, + uint64_t id) +{ + client_ptr->graph_id = id; +} + +uint64_t +ladish_client_get_graph_id( + ladish_client_handle client_handle) +{ + assert(client_ptr->graph_id != 0); /* nobody set it yet */ + return client_ptr->graph_id; +} + +struct list_head * +ladish_client_get_graph_link( + ladish_client_handle client_handle) +{ + return &client_ptr->siblings_graph; +} + +ladish_client_handle +ladish_client_get_by_graph_link( + struct list_head * link) +{ + return (ladish_client_handle)list_entry(link, struct ladish_client, siblings_graph); +} + +void +ladish_client_detach( + ladish_client_handle client_handle) +{ + if (!list_empty(&client_ptr->siblings_graph)) + { + list_del_init(&client_ptr->siblings_graph); + } +} + +void +ladish_client_destroy( + ladish_client_handle client_handle) +{ + struct list_head * node_ptr; + struct ladish_client_graph_name * graph_name; + + ladish_client_detach(client_handle); + + assert(list_empty(&client_ptr->ports)); + assert(list_empty(&client_ptr->siblings_studio_all)); + assert(list_empty(&client_ptr->siblings_room)); + + while (!list_empty(&client_ptr->graph_names)) + { + node_ptr = client_ptr->graph_names.next; + graph_name = list_entry(node_ptr, struct ladish_client_graph_name, siblings); + list_del(node_ptr); + free(graph_name->client_name); + free(graph_name->graph_opath); + free(graph_name); + } + + if (client_ptr->jack_name != NULL) + { + free(client_ptr->jack_name); + } + + if (client_ptr->human_name != NULL) + { + free(client_ptr->human_name); + } + + free(client_ptr); +} + +#undef client_ptr diff --git a/daemon/client.h b/daemon/client.h new file mode 100644 index 00000000..59b7612d --- /dev/null +++ b/daemon/client.h @@ -0,0 +1,81 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2009 Nedko Arnaudov + * + ************************************************************************** + * This file contains the interface of the client 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 CLIENT_H__2160B4BA_D6D1_464D_9DC5_ECA50B0958AD__INCLUDED +#define CLIENT_H__2160B4BA_D6D1_464D_9DC5_ECA50B0958AD__INCLUDED + +typedef struct ladish_client_tag { int unused; } * ladish_client_handle; + +bool +ladish_client_create( + uuid_t uuid_ptr, + bool virtual, + bool link, + bool system, + ladish_client_handle * client_handle_ptr); + +bool +ladish_client_set_graph_name( + ladish_client_handle client_handle, + const char * opath, + const char * name); + +const char * +ladish_client_get_graph_name( + ladish_client_handle client_handle, + const char * opath); + +void +ladish_client_drop_graph_name( + ladish_client_handle client_handle, + const char * opath); + +void +ladish_client_set_graph_id( + ladish_client_handle client_handle, + uint64_t id); + +uint64_t +ladish_client_get_graph_id( + ladish_client_handle client_handle); + +struct list_head * +ladish_client_get_graph_link( + ladish_client_handle client_handle); + +ladish_client_handle +ladish_client_get_by_graph_link( + struct list_head * link); + +void +ladish_client_detach( + ladish_client_handle client_handle); + +void +ladish_client_destroy( + ladish_client_handle client_handle); + +#endif /* #ifndef CLIENT_H__2160B4BA_D6D1_464D_9DC5_ECA50B0958AD__INCLUDED */ diff --git a/daemon/common.h b/daemon/common.h index f548b043..e53c1ef0 100644 --- a/daemon/common.h +++ b/daemon/common.h @@ -78,23 +78,6 @@ struct connection struct port * playback_port_ptr; /* The playback input port */ }; -struct client -{ - struct list_head siblings_studio_all; /* link for the studio::all_clients list */ - struct list_head siblings_room; /* link for the room::clients list */ - struct list_head ports; /* List of ports that belong to the client */ - uuid_t uuid; /* The UUID of the client */ - uint64_t jack_id; /* JACK client ID */ - char * jack_name; /* JACK name, not valid for virtual clients */ - char * human_name; /* User assigned name, not valid for studio-room link clients */ - bool virtual:1; /* Whether client is virtual */ - bool link:1; /* Whether client is a studio-room link */ - bool system:1; /* Whether client is system (server in-process) */ - pid_t pid; /* process id. Not valid for system and virtual clients */ - struct room * room_ptr; /* Room this client belongs to. If NULL, client belongs only to studio guts. */ - struct studio * studio_ptr; /* Studio this client belongs to. For room clients this points to studio connected to the room */ -}; - struct room { struct list_head siblings; /* link for studio::rooms list */ diff --git a/daemon/graph_iface.c b/daemon/graph_iface.c index d92bdaf9..a8d959af 100644 --- a/daemon/graph_iface.c +++ b/daemon/graph_iface.c @@ -28,6 +28,17 @@ #include "common.h" #include "graph_iface.h" #include "../dbus/error.h" +#include "../dbus_constants.h" + +struct graph_implementator +{ + char * opath; + struct list_head clients; + uint64_t graph_version; + uint64_t next_client_id; + uint64_t next_port_id; + uint64_t next_connection_id; +}; #define impl_ptr ((struct graph_implementator *)call_ptr->iface_context) @@ -70,9 +81,13 @@ static void get_graph(struct dbus_method_call * call_ptr) DBusMessageIter iter; DBusMessageIter clients_array_iter; DBusMessageIter connections_array_iter; -#if 0 - DBusMessageIter ports_array_iter; DBusMessageIter client_struct_iter; + struct list_head * client_node_ptr; + ladish_client_handle client_handle; + uint64_t id; + const char * name; + DBusMessageIter ports_array_iter; +#if 0 DBusMessageIter port_struct_iter; DBusMessageIter connection_struct_iter; #endif @@ -97,7 +112,7 @@ static void get_graph(struct dbus_method_call * call_ptr) dbus_message_iter_init_append(call_ptr->reply, &iter); - current_version = impl_ptr->get_graph_version(impl_ptr->this); + current_version = impl_ptr->graph_version; if (known_version > current_version) { lash_dbus_error( @@ -121,22 +136,24 @@ static void get_graph(struct dbus_method_call * call_ptr) if (known_version < current_version) { -#if 0 - list_for_each(client_node_ptr, &patchbay_ptr->graph.clients) + list_for_each(client_node_ptr, &impl_ptr->clients) { - client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings); + client_handle = ladish_client_get_by_graph_link(client_node_ptr); 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)) + id = ladish_client_get_graph_id(client_handle); + if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &id)) { goto nomem_close_client_struct; } - if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name)) + name = ladish_client_get_graph_name(client_handle, impl_ptr->opath); + lash_info("client '%s' (%u)", name, (unsigned int)id); + if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &name)) { goto nomem_close_client_struct; } @@ -146,6 +163,7 @@ 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); @@ -180,6 +198,7 @@ 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)) { @@ -191,7 +210,6 @@ static void get_graph(struct dbus_method_call * call_ptr) goto nomem_close_clients_array; } } -#endif } if (!dbus_message_iter_close_container(&iter, &clients_array_iter)) @@ -289,13 +307,13 @@ nomem_close_port_struct: 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); nomem_close_clients_array: dbus_message_iter_close_container(&iter, &clients_array_iter); -#endif nomem: dbus_message_unref(call_ptr->reply); @@ -337,6 +355,78 @@ static void get_client_pid(struct dbus_method_call * call_ptr) method_return_new_single(call_ptr, DBUS_TYPE_INT64, &pid); } +#undef impl_ptr + +bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * opath) +{ + struct graph_implementator * impl_ptr; + + impl_ptr = malloc(sizeof(struct graph_implementator)); + if (impl_ptr == NULL) + { + lash_error("malloc() failed to allocate struct graph_implementator"); + return false; + } + + impl_ptr->opath = strdup(opath); + if (impl_ptr->opath == NULL) + { + free(impl_ptr); + return false; + } + + INIT_LIST_HEAD(&impl_ptr->clients); + + impl_ptr->graph_version = 1; + impl_ptr->next_client_id = 1; + impl_ptr->next_port_id = 1; + impl_ptr->next_connection_id = 1; + + *graph_handle_ptr = (ladish_graph_handle)impl_ptr; + return true; +} + +#define impl_ptr ((struct graph_implementator *)graph_handle) + +void ladish_graph_destroy(ladish_graph_handle graph_handle) +{ + free(impl_ptr->opath); + free(impl_ptr); +} + +void ladish_graph_clear(ladish_graph_handle graph_handle) +{ +} + +void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle) +{ + return graph_handle; +} + +void ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client, const char * opath) +{ + const char * name; + + ladish_client_set_graph_id(client, impl_ptr->next_client_id++); + list_add_tail(ladish_client_get_graph_link(client), &impl_ptr->clients); + impl_ptr->graph_version++; + + name = ladish_client_get_graph_name(client, opath); + lash_info("adding client '%s' (%p)", name, client); + assert(name != NULL); + dbus_signal_emit( + g_dbus_connection, + opath, + JACKDBUS_IFACE_PATCHBAY, + "ClientAppeared", + "tts", + &impl_ptr->graph_version, + &impl_ptr->next_client_id, + &name); +} + +#undef impl_ptr + METHOD_ARGS_BEGIN(GetAllPorts, "Get all ports") METHOD_ARG_DESCRIBE_IN("ports_list", "as", "List of all ports") METHOD_ARGS_END @@ -462,7 +552,7 @@ SIGNALS_BEGIN SIGNAL_DESCRIBE(PortsDisconnected) SIGNALS_END -INTERFACE_BEGIN(g_interface_patchbay, "org.jackaudio.JackPatchbay") +INTERFACE_BEGIN(g_interface_patchbay, JACKDBUS_IFACE_PATCHBAY) INTERFACE_DEFAULT_HANDLER INTERFACE_EXPOSE_METHODS INTERFACE_EXPOSE_SIGNALS diff --git a/daemon/graph_iface.h b/daemon/graph_iface.h index 522420b6..9e2938cb 100644 --- a/daemon/graph_iface.h +++ b/daemon/graph_iface.h @@ -27,12 +27,15 @@ #ifndef PATCHBAY_H__30334B9A_8847_4E8C_AFF9_73DB13406C8E__INCLUDED #define PATCHBAY_H__30334B9A_8847_4E8C_AFF9_73DB13406C8E__INCLUDED -struct graph_implementator -{ - void * this; +#include "client.h" - uint64_t (* get_graph_version)(void * this); -}; +typedef struct ladish_graph_tag { int unused; } * ladish_graph_handle; + +bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * opath); +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); +void ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * opath); extern const struct dbus_interface_descriptor g_interface_patchbay; diff --git a/daemon/studio.c b/daemon/studio.c index 597fcce0..bb8c335a 100644 --- a/daemon/studio.c +++ b/daemon/studio.c @@ -51,8 +51,6 @@ extern const struct dbus_interface_descriptor g_interface_studio; struct studio { - struct graph_implementator graph_impl; - struct list_head all_connections; /* All connections (studio guts and all rooms). Including superconnections. */ struct list_head all_ports; /* All ports (studio guts and all rooms) */ struct list_head all_clients; /* All clients (studio guts and all rooms) */ @@ -80,6 +78,7 @@ struct studio char * filename; graph_proxy_handle jack_graph_proxy; + ladish_graph_handle graph; } g_studio; #define EVENT_JACK_START 0 @@ -500,7 +499,11 @@ studio_publish(void) assert(g_studio.name != NULL); - object = dbus_object_path_new(STUDIO_OBJECT_PATH, &g_interface_studio, &g_studio, &g_interface_patchbay, &g_studio.graph_impl, NULL); + object = dbus_object_path_new( + STUDIO_OBJECT_PATH, + &g_interface_studio, &g_studio, + &g_interface_patchbay, ladish_graph_get_dbus_context(g_studio.graph), + NULL); if (object == NULL) { lash_error("dbus_object_path_new() failed"); @@ -577,6 +580,8 @@ static bool studio_stop(void) void studio_clear(void) { + ladish_graph_clear(g_studio.graph); + g_studio.modified = false; g_studio.persisted = false; g_studio.automatic = false; @@ -646,7 +651,23 @@ void on_event_jack_started(void) if (!graph_proxy_create(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, &g_studio.jack_graph_proxy)) { - lash_error("graph_create() failed for jackdbus"); + lash_error("graph_proxy_create() failed for jackdbus"); + } + else + { +#if 1 /* XXX */ + ladish_client_handle capture_client; + ladish_client_handle playback_client; + + ladish_client_create( NULL, true, false, true, &capture_client); + ladish_client_create(NULL, true, false, true, &playback_client); + + ladish_client_set_graph_name(capture_client, STUDIO_OBJECT_PATH, "Hardware Capture"); + ladish_client_set_graph_name(playback_client, STUDIO_OBJECT_PATH, "Hardware Playback"); + + ladish_graph_add_client(g_studio.graph, capture_client, STUDIO_OBJECT_PATH); + ladish_graph_add_client(g_studio.graph, playback_client, STUDIO_OBJECT_PATH); +#endif } } @@ -728,18 +749,6 @@ static void on_jack_server_disappeared(void) lash_info("JACK controller disappeared."); } -#define studio_ptr ((struct studio *)this) - -uint64_t -studio_get_graph_version( - void * this) -{ - //lash_info("studio_get_graph_version() called"); - return 1; -} - -#undef studio_ptr - bool studio_init(void) { lash_info("studio object construct"); @@ -748,18 +757,14 @@ bool studio_init(void) if (g_studios_dir == NULL) { lash_error("catdup failed for '%s' and '%s'", g_base_dir, STUDIOS_DIR); - return false; + goto fail; } if (!ensure_dir_exist(g_studios_dir, 0700)) { - free(g_studios_dir); - return false; + goto free_studios_dir; } - g_studio.graph_impl.this = &g_studio; - g_studio.graph_impl.get_graph_version = studio_get_graph_version; - INIT_LIST_HEAD(&g_studio.all_connections); INIT_LIST_HEAD(&g_studio.all_ports); INIT_LIST_HEAD(&g_studio.all_clients); @@ -779,8 +784,15 @@ bool studio_init(void) g_studio.name = NULL; g_studio.filename = NULL; g_studio.jack_running = false; + studio_clear(); + if (!ladish_graph_create(&g_studio.graph, STUDIO_OBJECT_PATH)) + { + lash_error("ladish_graph_create() failed."); + goto free_studios_dir; + } + if (!jack_proxy_init( on_jack_server_started, on_jack_server_stopped, @@ -788,11 +800,18 @@ bool studio_init(void) on_jack_server_disappeared)) { lash_error("jack_proxy_init() failed."); - studio_clear(); - return false; + goto graph_destroy; } return true; + +graph_destroy: + ladish_graph_destroy(g_studio.graph); +free_studios_dir: + studio_clear(); + free(g_studios_dir); +fail: + return false; } void studio_uninit(void) diff --git a/wscript b/wscript index f626581b..74a33f81 100644 --- a/wscript +++ b/wscript @@ -200,6 +200,7 @@ def build(bld): 'control.c', 'studio.c', 'graph_iface.c', + 'client.c', ]: daemon.source.append(os.path.join("daemon", source))