diff --git a/daemon/cmd_load_studio.c b/daemon/cmd_load_studio.c index cf6ab083..123a07f9 100644 --- a/daemon/cmd_load_studio.c +++ b/daemon/cmd_load_studio.c @@ -47,6 +47,8 @@ #define PARSE_CONTEXT_PORT 8 #define PARSE_CONTEXT_DICT 9 #define PARSE_CONTEXT_KEY 10 +#define PARSE_CONTEXT_CONNECTIONS 11 +#define PARSE_CONTEXT_CONNECTION 12 #define MAX_STACK_DEPTH 10 #define MAX_DATA_SIZE 1024 @@ -62,6 +64,7 @@ struct parse_context ladish_client_handle client; ladish_port_handle port; ladish_dict_handle dict; + uint64_t connection_id; }; #define context_ptr ((struct parse_context *)data) @@ -91,6 +94,9 @@ static void callback_chrdata(void * data, const XML_Char * s, int len) static void callback_elstart(void * data, const char * el, const char ** attr) { uuid_t uuid; + uuid_t uuid2; + ladish_port_handle port1; + ladish_port_handle port2; if (context_ptr->error) { @@ -375,6 +381,73 @@ static void callback_elstart(void * data, const char * el, const char ** attr) return; } + if (strcmp(el, "connections") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTIONS; + return; + } + + if (strcmp(el, "connection") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTION; + + if (attr[0] == NULL || + attr[1] == NULL || + attr[2] == NULL || + attr[3] == NULL || + attr[4] != NULL || + strcmp(attr[0], "port1") != 0 || + strcmp(attr[2], "port2") != 0) + { + log_error("studio/connections/connection XML element must contain exactly two attributes, named \"port1\" and \"port2\", in this order"); + context_ptr->error = XML_TRUE; + return; + } + + if (uuid_parse(attr[1], uuid) != 0) + { + log_error("cannot parse uuid \"%s\"", attr[1]); + context_ptr->error = XML_TRUE; + return; + } + + if (uuid_parse(attr[3], uuid2) != 0) + { + log_error("cannot parse uuid \"%s\"", attr[3]); + context_ptr->error = XML_TRUE; + return; + } + + log_info("studio connection between port %s and port %s", attr[1], attr[3]); + + port1 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid); + if (port1 == NULL) + { + log_error("studio client with unknown port %s", attr[1]); + context_ptr->error = XML_TRUE; + return; + } + + port2 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid2); + if (port2 == NULL) + { + log_error("studio client with unknown port %s", attr[3]); + context_ptr->error = XML_TRUE; + return; + } + + context_ptr->connection_id = ladish_graph_add_connection(g_studio.studio_graph, port1, port2, true); + if (context_ptr->connection_id == 0) + { + log_error("ladish_graph_add_connection() failed."); + return; + } + + return; + } + if (strcmp(el, "dict") == 0) { //log_info(""); @@ -407,6 +480,13 @@ static void callback_elstart(void * data, const char * el, const char ** attr) context_ptr->dict = ladish_port_get_dict(context_ptr->port); ASSERT(context_ptr->dict != NULL); } + else if (context_ptr->depth > 0 && + context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CONNECTION) + { + ASSERT(context_ptr->port != NULL); + context_ptr->dict = ladish_graph_get_connection_dict(g_studio.studio_graph, context_ptr->connection_id); + ASSERT(context_ptr->dict != NULL); + } else { log_error("unexpected dict XML element"); diff --git a/daemon/cmd_save_studio.c b/daemon/cmd_save_studio.c index 979a6c5b..db6b6671 100644 --- a/daemon/cmd_save_studio.c +++ b/daemon/cmd_save_studio.c @@ -498,6 +498,68 @@ save_studio_port( return true; } +bool save_studio_connection(void * context, ladish_port_handle port1_handle, ladish_port_handle port2_handle, ladish_dict_handle dict) +{ + uuid_t uuid; + char str[37]; + + log_info("saving studio connection"); + + if (!write_string(fd, " \n")) + { + return false; + } + } + else + { + if (!write_string(fd, "\">\n")) + { + return false; + } + + if (!write_dict(fd, " ", dict)) + { + return false; + } + + if (!write_string(fd, " \n")) + { + return false; + } + } + + return true; + return true; +} + #undef indent #undef fd @@ -689,6 +751,22 @@ static bool run(void * command_context) goto close; } + if (!write_string(fd, " \n")) + { + goto close; + } + + if (!ladish_graph_iterate_connections(g_studio.studio_graph, &save_context, save_studio_connection)) + { + log_error("ladish_graph_iterate_connections() failed"); + goto close; + } + + if (!write_string(fd, " \n")) + { + goto close; + } + if (!write_dict(fd, " ", ladish_graph_get_dict(g_studio.studio_graph))) { return false; diff --git a/daemon/graph.c b/daemon/graph.c index 4c42b79f..3fd8c926 100644 --- a/daemon/graph.c +++ b/daemon/graph.c @@ -60,6 +60,7 @@ struct ladish_graph_connection bool hidden; struct ladish_graph_port * port1_ptr; struct ladish_graph_port * port2_ptr; + ladish_dict_handle dict; }; struct ladish_graph @@ -329,6 +330,11 @@ static void get_graph(struct dbus_method_call * call_ptr) { connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings); + if (connection_ptr->hidden) + { + continue; + } + if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter)) { goto nomem_close_connections_array; @@ -824,6 +830,42 @@ ladish_dict_handle ladish_graph_get_dict(ladish_graph_handle graph_handle) return graph_ptr->dict; } +void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id) +{ + struct ladish_graph_connection * connection_ptr; + + log_info("ladish_graph_show_connection() called."); + + connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id); + if (connection_ptr == NULL) + { + ASSERT_NO_PASS; + return; + } + + ASSERT(graph_ptr->opath != NULL); + ASSERT(connection_ptr->hidden); + connection_ptr->hidden = false; + graph_ptr->graph_version++; + + dbus_signal_emit( + g_dbus_connection, + graph_ptr->opath, + JACKDBUS_IFACE_PATCHBAY, + "PortsConnected", + "ttstststst", + &graph_ptr->graph_version, + &connection_ptr->port1_ptr->client_ptr->id, + &connection_ptr->port1_ptr->client_ptr->name, + &connection_ptr->port1_ptr->id, + &connection_ptr->port1_ptr->name, + &connection_ptr->port2_ptr->client_ptr->id, + &connection_ptr->port2_ptr->client_ptr->name, + &connection_ptr->port2_ptr->id, + &connection_ptr->port2_ptr->name, + &connection_ptr->id); +} + void ladish_graph_show_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle) { struct ladish_graph_port * port_ptr; @@ -1150,6 +1192,13 @@ ladish_graph_add_connection( return 0; } + if (!ladish_dict_create(&connection_ptr->dict)) + { + log_error("ladish_dict_create() failed for connection"); + free(connection_ptr); + return 0; + } + connection_ptr->id = graph_ptr->next_connection_id++; connection_ptr->port1_ptr = port1_ptr; connection_ptr->port2_ptr = port2_ptr; @@ -1218,6 +1267,7 @@ ladish_graph_remove_connection( &connection_ptr->id); } + ladish_dict_destroy(connection_ptr->dict); free(connection_ptr); } @@ -1242,6 +1292,19 @@ ladish_graph_get_connection_ports( return true; } +ladish_dict_handle ladish_graph_get_connection_dict(ladish_graph_handle graph_handle, uint64_t connection_id) +{ + struct ladish_graph_connection * connection_ptr; + + connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id); + if (connection_ptr == NULL) + { + return NULL; + } + + return connection_ptr->dict; +} + bool ladish_graph_find_connection( ladish_graph_handle graph_handle, @@ -1583,6 +1646,28 @@ ladish_graph_iterate_nodes( return true; } +bool +ladish_graph_iterate_connections( + ladish_graph_handle graph_handle, + void * callback_context, + bool (* callback)(void * context, ladish_port_handle port1_handle, ladish_port_handle port2_handle, ladish_dict_handle dict)) +{ + struct list_head * node_ptr; + struct ladish_graph_connection * connection_ptr; + + list_for_each(node_ptr, &graph_ptr->connections) + { + connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings); + + if (!callback(callback_context, connection_ptr->port1_ptr->port, connection_ptr->port2_ptr->port, connection_ptr->dict)) + { + return false; + } + } + + return true; +} + static bool dump_dict_entry( @@ -1615,6 +1700,8 @@ void ladish_graph_dump(ladish_graph_handle graph_handle) struct ladish_graph_client * client_ptr; struct list_head * port_node_ptr; struct ladish_graph_port * port_ptr; + struct list_head * connection_node_ptr; + struct ladish_graph_connection * connection_ptr; log_info("graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK"); log_info(" version %"PRIu64, graph_ptr->graph_version); @@ -1634,6 +1721,20 @@ void ladish_graph_dump(ladish_graph_handle graph_handle) dump_dict(" ", ladish_port_get_dict(port_ptr->port)); } } + log_info(" connections:"); + list_for_each(connection_node_ptr, &graph_ptr->connections) + { + connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings); + + log_info( + " %s connection '%s':'%s' - '%s':'%s'", + connection_ptr->hidden ? "invisible" : "visible", + connection_ptr->port1_ptr->client_ptr->name, + connection_ptr->port1_ptr->name, + connection_ptr->port2_ptr->client_ptr->name, + connection_ptr->port2_ptr->name); + dump_dict(" ", ladish_port_get_dict(port_ptr->port)); + } } #undef graph_ptr diff --git a/daemon/graph.h b/daemon/graph.h index 45f592e3..2f6fc53f 100644 --- a/daemon/graph.h +++ b/daemon/graph.h @@ -60,6 +60,7 @@ ladish_graph_set_connection_handlers( void ladish_graph_clear(ladish_graph_handle graph_handle, bool destroy_ports); void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle); ladish_dict_handle ladish_graph_get_dict(ladish_graph_handle graph_handle); +ladish_dict_handle ladish_graph_get_connection_dict(ladish_graph_handle graph_handle, uint64_t connection_id); bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name, bool hidden); void @@ -127,6 +128,7 @@ void ladish_graph_hide_port(ladish_graph_handle graph_handle, ladish_port_handle void ladish_graph_show_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle); void ladish_graph_hide_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle); void ladish_graph_adjust_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle, uint32_t type, uint32_t flags); +void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id); void ladish_graph_dump(ladish_graph_handle graph_handle); @@ -157,6 +159,12 @@ ladish_graph_iterate_nodes( const char * client_name, void * client_iteration_context_ptr)); +bool +ladish_graph_iterate_connections( + ladish_graph_handle graph_handle, + void * callback_context, + bool (* callback)(void * context, ladish_port_handle port1_handle, ladish_port_handle port2_handle, ladish_dict_handle dict)); + extern const struct dbus_interface_descriptor g_interface_patchbay; #endif /* #ifndef PATCHBAY_H__30334B9A_8847_4E8C_AFF9_73DB13406C8E__INCLUDED */ diff --git a/daemon/graph_dict.c b/daemon/graph_dict.c index 73969b37..364adb46 100644 --- a/daemon/graph_dict.c +++ b/daemon/graph_dict.c @@ -36,6 +36,7 @@ bool find_dict(struct dbus_method_call * call_ptr, uint32_t object_type, uint64_ { ladish_client_handle client; ladish_port_handle port; + ladish_dict_handle dict; switch (object_type) { @@ -61,7 +62,13 @@ bool find_dict(struct dbus_method_call * call_ptr, uint32_t object_type, uint64_ *dict_handle_ptr = ladish_port_get_dict(port); return true; case GRAPH_DICT_OBJECT_TYPE_CONNECTION: - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "find_dict() not implemented for connections."); + dict = ladish_graph_get_connection_dict(graph_handle, object_id); + if (dict == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "cannot find connection %"PRIu64".", object_id); + } + + *dict_handle_ptr = dict; return false; } diff --git a/daemon/virtualizer.c b/daemon/virtualizer.c index d1d9958f..3d400598 100644 --- a/daemon/virtualizer.c +++ b/daemon/virtualizer.c @@ -358,6 +358,7 @@ static void ports_connected(void * context, uint64_t client1_id, uint64_t port1_ { ladish_port_handle port1; ladish_port_handle port2; + uint64_t connection_id; log_info("ports_connected %"PRIu64":%"PRIu64" %"PRIu64":%"PRIu64"", client1_id, port1_id, client2_id, port2_id); @@ -376,7 +377,17 @@ static void ports_connected(void * context, uint64_t client1_id, uint64_t port1_ } ladish_graph_add_connection(virtualizer_ptr->jack_graph, port1, port2, false); - ladish_graph_add_connection(virtualizer_ptr->studio_graph, port1, port2, false); + + if (ladish_graph_find_connection(virtualizer_ptr->studio_graph, port1, port2, &connection_id)) + { + log_info("showing hidden connection"); + ladish_graph_show_connection(virtualizer_ptr->studio_graph, connection_id); + } + else + { + log_info("creating new connection"); + ladish_graph_add_connection(virtualizer_ptr->studio_graph, port1, port2, false); + } } static void ports_disconnected(void * context, uint64_t client1_id, uint64_t port1_id, uint64_t client2_id, uint64_t port2_id)