ladishd: clear project even if room project state is 'unloaded'. Fix for #117
[ladish.git] / daemon / graph.c
blob460f49dc34158d218922e2744f7ac36f145e3769
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2008 Juuso Alasuutari
8 **************************************************************************
9 * This file contains implementation of the D-Bus patchbay interface helpers
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "common.h"
29 #include "graph.h"
30 #include "../dbus/error.h"
31 #include "../dbus_constants.h"
32 #include "virtualizer.h"
34 struct ladish_graph_port
36 struct list_head siblings_client;
37 struct list_head siblings_graph;
38 struct ladish_graph_client * client_ptr;
39 char * name;
40 uint32_t type;
41 uint32_t flags;
42 uint64_t id;
43 ladish_port_handle port;
44 bool hidden;
45 bool link;
46 uuid_t link_uuid_override;
49 struct ladish_graph_client
51 struct list_head siblings;
52 char * name;
53 uint64_t id;
54 ladish_client_handle client;
55 struct list_head ports;
56 bool hidden;
59 struct ladish_graph_connection
61 struct list_head siblings;
62 uint64_t id;
63 bool hidden;
64 struct ladish_graph_port * port1_ptr;
65 struct ladish_graph_port * port2_ptr;
66 ladish_dict_handle dict;
67 bool changing;
70 struct ladish_graph
72 char * opath;
73 ladish_dict_handle dict;
74 struct list_head clients;
75 struct list_head ports;
76 struct list_head connections;
77 uint64_t graph_version;
78 uint64_t next_client_id;
79 uint64_t next_port_id;
80 uint64_t next_connection_id;
81 bool persist;
83 void * context;
84 ladish_graph_connect_request_handler connect_handler;
85 ladish_graph_disconnect_request_handler disconnect_handler;
88 static void ladish_graph_emit_ports_disconnected(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
90 ASSERT(graph_ptr->opath != NULL);
92 dbus_signal_emit(
93 g_dbus_connection,
94 graph_ptr->opath,
95 JACKDBUS_IFACE_PATCHBAY,
96 "PortsDisconnected",
97 "ttstststst",
98 &graph_ptr->graph_version,
99 &connection_ptr->port1_ptr->client_ptr->id,
100 &connection_ptr->port1_ptr->client_ptr->name,
101 &connection_ptr->port1_ptr->id,
102 &connection_ptr->port1_ptr->name,
103 &connection_ptr->port2_ptr->client_ptr->id,
104 &connection_ptr->port2_ptr->client_ptr->name,
105 &connection_ptr->port2_ptr->id,
106 &connection_ptr->port2_ptr->name,
107 &connection_ptr->id);
110 static void ladish_graph_emit_ports_connected(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
112 ASSERT(graph_ptr->opath != NULL);
114 dbus_signal_emit(
115 g_dbus_connection,
116 graph_ptr->opath,
117 JACKDBUS_IFACE_PATCHBAY,
118 "PortsConnected",
119 "ttstststst",
120 &graph_ptr->graph_version,
121 &connection_ptr->port1_ptr->client_ptr->id,
122 &connection_ptr->port1_ptr->client_ptr->name,
123 &connection_ptr->port1_ptr->id,
124 &connection_ptr->port1_ptr->name,
125 &connection_ptr->port2_ptr->client_ptr->id,
126 &connection_ptr->port2_ptr->client_ptr->name,
127 &connection_ptr->port2_ptr->id,
128 &connection_ptr->port2_ptr->name,
129 &connection_ptr->id);
132 static void ladish_graph_emit_client_appeared(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
134 ASSERT(graph_ptr->opath != NULL);
136 dbus_signal_emit(
137 g_dbus_connection,
138 graph_ptr->opath,
139 JACKDBUS_IFACE_PATCHBAY,
140 "ClientAppeared",
141 "tts",
142 &graph_ptr->graph_version,
143 &client_ptr->id,
144 &client_ptr->name);
147 static void ladish_graph_emit_client_disappeared(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
149 ASSERT(graph_ptr->opath != NULL);
151 dbus_signal_emit(
152 g_dbus_connection,
153 graph_ptr->opath,
154 JACKDBUS_IFACE_PATCHBAY,
155 "ClientDisappeared",
156 "tts",
157 &graph_ptr->graph_version,
158 &client_ptr->id,
159 &client_ptr->name);
162 static void ladish_graph_emit_port_appeared(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
164 ASSERT(graph_ptr->opath != NULL);
166 dbus_signal_emit(
167 g_dbus_connection,
168 graph_ptr->opath,
169 JACKDBUS_IFACE_PATCHBAY,
170 "PortAppeared",
171 "ttstsuu",
172 &graph_ptr->graph_version,
173 &port_ptr->client_ptr->id,
174 &port_ptr->client_ptr->name,
175 &port_ptr->id,
176 &port_ptr->name,
177 &port_ptr->flags,
178 &port_ptr->type);
181 static void ladish_graph_emit_port_disappeared(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
183 ASSERT(graph_ptr->opath != NULL);
185 dbus_signal_emit(
186 g_dbus_connection,
187 graph_ptr->opath,
188 JACKDBUS_IFACE_PATCHBAY,
189 "PortDisappeared",
190 "ttsts",
191 &graph_ptr->graph_version,
192 &port_ptr->client_ptr->id,
193 &port_ptr->client_ptr->name,
194 &port_ptr->id,
195 &port_ptr->name);
198 static struct ladish_graph_port * ladish_graph_find_port_by_id_internal(struct ladish_graph * graph_ptr, uint64_t port_id)
200 struct list_head * node_ptr;
201 struct ladish_graph_port * port_ptr;
203 list_for_each(node_ptr, &graph_ptr->ports)
205 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
206 if (port_ptr->id == port_id)
208 return port_ptr;
212 return NULL;
215 //#define LOG_PORT_LOOKUP
217 static struct ladish_graph_port *
218 ladish_graph_find_port_by_uuid_internal(
219 struct ladish_graph * graph_ptr,
220 struct ladish_graph_client * client_ptr,
221 const uuid_t uuid,
222 bool use_link_override_uuids,
223 void * vgraph_filter)
225 struct list_head * node_ptr;
226 struct ladish_graph_port * port_ptr;
227 uuid_t current_uuid;
228 #if defined(LOG_PORT_LOOKUP)
229 char uuid1_str[37];
230 char uuid2_str[37];
232 log_info("searching by uuid for port in graph %s", ladish_graph_get_description((ladish_graph_handle)graph_ptr));
233 uuid_unparse(uuid, uuid1_str);
234 #endif
236 list_for_each(node_ptr, &graph_ptr->ports)
238 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
240 if (client_ptr != NULL && port_ptr->client_ptr != client_ptr)
242 continue;
245 if (vgraph_filter != NULL && ladish_port_get_vgraph(port_ptr->port) != vgraph_filter)
247 continue;
250 #if defined(LOG_PORT_LOOKUP)
251 if (port_ptr->link)
253 uuid_unparse(port_ptr->link_uuid_override, uuid2_str);
254 log_info("comparing link uuid %s with %s", uuid2_str, uuid1_str);
256 #endif
258 if (use_link_override_uuids && port_ptr->link && uuid_compare(port_ptr->link_uuid_override, uuid) == 0)
260 #if defined(LOG_PORT_LOOKUP)
261 log_info("found link port %p of client '%s'", port_ptr->port, port_ptr->client_ptr->name);
262 #endif
263 return port_ptr;
266 ladish_port_get_uuid(port_ptr->port, current_uuid);
267 #if defined(LOG_PORT_LOOKUP)
268 uuid_unparse(current_uuid, uuid2_str);
269 log_info("comparing port uuid %s with %s", uuid2_str, uuid1_str);
270 #endif
271 if (uuid_compare(current_uuid, uuid) == 0)
273 #if defined(LOG_PORT_LOOKUP)
274 log_info("found port %p of client '%s'", port_ptr->port, port_ptr->client_ptr->name);
275 #endif
276 return port_ptr;
280 return NULL;
283 static struct ladish_graph_connection * ladish_graph_find_connection_by_id(struct ladish_graph * graph_ptr, uint64_t connection_id)
285 struct list_head * node_ptr;
286 struct ladish_graph_connection * connection_ptr;
288 list_for_each(node_ptr, &graph_ptr->connections)
290 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
291 if (connection_ptr->id == connection_id)
293 return connection_ptr;
297 return NULL;
300 static
301 struct ladish_graph_connection *
302 ladish_graph_find_connection_by_ports(
303 struct ladish_graph * graph_ptr,
304 struct ladish_graph_port * port1_ptr,
305 struct ladish_graph_port * port2_ptr)
307 struct list_head * node_ptr;
308 struct ladish_graph_connection * connection_ptr;
310 list_for_each(node_ptr, &graph_ptr->connections)
312 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
313 if ((connection_ptr->port1_ptr == port1_ptr && connection_ptr->port2_ptr == port2_ptr) ||
314 (connection_ptr->port1_ptr == port2_ptr && connection_ptr->port2_ptr == port1_ptr))
316 return connection_ptr;
320 return NULL;
323 #define graph_ptr ((struct ladish_graph *)call_ptr->iface_context)
325 static void get_all_ports(struct dbus_method_call * call_ptr)
327 DBusMessageIter iter, sub_iter;
329 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
330 if (call_ptr->reply == NULL)
332 goto fail;
335 dbus_message_iter_init_append(call_ptr->reply, &iter);
337 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
339 goto fail_unref;
342 if (!dbus_message_iter_close_container(&iter, &sub_iter))
344 goto fail_unref;
347 return;
349 fail_unref:
350 dbus_message_unref(call_ptr->reply);
351 call_ptr->reply = NULL;
353 fail:
354 log_error("Ran out of memory trying to construct method return");
357 static void get_graph(struct dbus_method_call * call_ptr)
359 dbus_uint64_t known_version;
360 dbus_uint64_t current_version;
361 DBusMessageIter iter;
362 DBusMessageIter clients_array_iter;
363 DBusMessageIter connections_array_iter;
364 DBusMessageIter client_struct_iter;
365 struct list_head * client_node_ptr;
366 struct ladish_graph_client * client_ptr;
367 DBusMessageIter ports_array_iter;
368 struct list_head * port_node_ptr;
369 struct ladish_graph_port * port_ptr;
370 DBusMessageIter port_struct_iter;
371 struct list_head * connection_node_ptr;
372 struct ladish_graph_connection * connection_ptr;
373 DBusMessageIter connection_struct_iter;
375 //log_info("get_graph() called");
377 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &known_version, DBUS_TYPE_INVALID))
379 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
380 dbus_error_free(&g_dbus_error);
381 return;
384 //log_info("Getting graph, known version is %" PRIu64, known_version);
386 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
387 if (call_ptr->reply == NULL)
389 log_error("Ran out of memory trying to construct method return");
390 goto exit;
393 dbus_message_iter_init_append(call_ptr->reply, &iter);
395 current_version = graph_ptr->graph_version;
396 if (known_version > current_version)
398 lash_dbus_error(
399 call_ptr,
400 LASH_DBUS_ERROR_INVALID_ARGS,
401 "known graph version %" PRIu64 " is newer than actual version %" PRIu64,
402 known_version,
403 current_version);
404 goto exit;
407 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &current_version))
409 goto nomem;
412 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
414 goto nomem;
417 if (known_version < current_version)
419 list_for_each(client_node_ptr, &graph_ptr->clients)
421 client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
423 if (client_ptr->hidden)
425 continue;
428 if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
430 goto nomem_close_clients_array;
433 if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
435 goto nomem_close_client_struct;
438 log_info("client '%s' (%llu)", client_ptr->name, (unsigned long long)client_ptr->id);
439 if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name))
441 goto nomem_close_client_struct;
444 if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
446 goto nomem_close_client_struct;
449 list_for_each(port_node_ptr, &client_ptr->ports)
451 port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
453 if (port_ptr->hidden)
455 continue;
458 if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
460 goto nomem_close_ports_array;
463 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
465 goto nomem_close_port_struct;
468 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
470 goto nomem_close_port_struct;
473 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
475 goto nomem_close_port_struct;
478 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
480 goto nomem_close_port_struct;
483 if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
485 goto nomem_close_ports_array;
489 if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
491 goto nomem_close_client_struct;
494 if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
496 goto nomem_close_clients_array;
501 if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
503 goto nomem;
506 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
508 goto nomem;
511 if (known_version < current_version)
513 list_for_each(connection_node_ptr, &graph_ptr->connections)
515 connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
517 if (connection_ptr->hidden)
519 continue;
522 if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
524 goto nomem_close_connections_array;
527 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->client_ptr->id))
529 goto nomem_close_connection_struct;
532 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->client_ptr->name))
534 goto nomem_close_connection_struct;
537 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->id))
539 goto nomem_close_connection_struct;
542 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->name))
544 goto nomem_close_connection_struct;
547 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->client_ptr->id))
549 goto nomem_close_connection_struct;
552 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->client_ptr->name))
554 goto nomem_close_connection_struct;
557 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->id))
559 goto nomem_close_connection_struct;
562 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->name))
564 goto nomem_close_connection_struct;
567 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
569 goto nomem_close_connection_struct;
572 if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
574 goto nomem_close_connections_array;
579 if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
581 goto nomem;
584 return;
586 nomem_close_connection_struct:
587 dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
589 nomem_close_connections_array:
590 dbus_message_iter_close_container(&iter, &connections_array_iter);
591 goto nomem;
593 nomem_close_port_struct:
594 dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
596 nomem_close_ports_array:
597 dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
599 nomem_close_client_struct:
600 dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
602 nomem_close_clients_array:
603 dbus_message_iter_close_container(&iter, &clients_array_iter);
605 nomem:
606 dbus_message_unref(call_ptr->reply);
607 call_ptr->reply = NULL;
608 log_error("Ran out of memory trying to construct method return");
610 exit:
611 return;
614 static void connect_ports_by_name(struct dbus_method_call * call_ptr)
616 log_info("connect_ports_by_name() called.");
617 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect by name is not implemented yet");
620 static void connect_ports_by_id(struct dbus_method_call * call_ptr)
622 dbus_uint64_t port1_id;
623 dbus_uint64_t port2_id;
624 struct ladish_graph_port * port1_ptr;
625 struct ladish_graph_port * port2_ptr;
627 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &port1_id, DBUS_TYPE_UINT64, &port2_id, DBUS_TYPE_INVALID))
629 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
630 dbus_error_free(&g_dbus_error);
631 return;
634 log_info("connect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
636 if (graph_ptr->connect_handler == NULL)
638 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect requests on graph %s cannot be handlined", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
639 return;
642 port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
643 if (port1_ptr == NULL)
645 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port1_id);
646 return;
649 port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
650 if (port2_ptr == NULL)
652 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port2_id);
653 return;
656 log_info("connecting '%s':'%s' to '%s':'%s'", port1_ptr->client_ptr->name, port1_ptr->name, port2_ptr->client_ptr->name, port2_ptr->name);
658 if (graph_ptr->connect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, port1_ptr->port, port2_ptr->port))
660 method_return_new_void(call_ptr);
662 else
664 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect failed");
668 static void disconnect_ports(struct dbus_method_call * call_ptr, struct ladish_graph_connection * connection_ptr)
670 log_info(
671 "disconnecting '%s':'%s' from '%s':'%s'",
672 connection_ptr->port1_ptr->client_ptr->name,
673 connection_ptr->port1_ptr->name,
674 connection_ptr->port2_ptr->client_ptr->name,
675 connection_ptr->port2_ptr->name);
677 connection_ptr->changing = true;
678 if (graph_ptr->disconnect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, connection_ptr->id))
680 method_return_new_void(call_ptr);
682 else
684 connection_ptr->changing = false;
685 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect failed");
689 static void disconnect_ports_by_name(struct dbus_method_call * call_ptr)
691 log_info("disconnect_ports_by_name() called.");
692 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect by name is not implemented yet");
695 static void disconnect_ports_by_id(struct dbus_method_call * call_ptr)
697 dbus_uint64_t port1_id;
698 dbus_uint64_t port2_id;
699 struct ladish_graph_port * port1_ptr;
700 struct ladish_graph_port * port2_ptr;
701 struct ladish_graph_connection * connection_ptr;
703 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &port1_id, DBUS_TYPE_UINT64, &port2_id, DBUS_TYPE_INVALID))
705 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
706 dbus_error_free(&g_dbus_error);
707 return;
710 log_info("disconnect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
712 if (graph_ptr->disconnect_handler == NULL)
714 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect requests on graph %s cannot be handlined", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
715 return;
718 port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
719 if (port1_ptr == NULL)
721 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port1_id);
722 return;
725 port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
726 if (port2_ptr == NULL)
728 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port2_id);
729 return;
732 connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
733 if (connection_ptr == NULL)
735 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect not connected ports %"PRIu64" and %"PRIu64, port1_id, port2_id);
736 return;
739 disconnect_ports(call_ptr, connection_ptr);
742 static void disconnect_ports_by_connection_id(struct dbus_method_call * call_ptr)
744 dbus_uint64_t connection_id;
745 struct ladish_graph_connection * connection_ptr;
747 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &connection_id, DBUS_TYPE_INVALID))
749 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
750 dbus_error_free(&g_dbus_error);
751 return;
754 log_info("disconnect_ports_by_connection_id(%"PRIu64") called.", connection_id);
756 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
757 if (connection_ptr == NULL)
759 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot find connection with id %"PRIu64, connection_id);
760 return;
763 disconnect_ports(call_ptr, connection_ptr);
766 static void get_client_pid(struct dbus_method_call * call_ptr)
768 int64_t pid = 0;
769 method_return_new_single(call_ptr, DBUS_TYPE_INT64, &pid);
772 #undef graph_ptr
774 bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * opath)
776 struct ladish_graph * graph_ptr;
778 graph_ptr = malloc(sizeof(struct ladish_graph));
779 if (graph_ptr == NULL)
781 log_error("malloc() failed to allocate struct graph_implementator");
782 return false;
785 if (opath != NULL)
787 graph_ptr->opath = strdup(opath);
788 if (graph_ptr->opath == NULL)
790 log_error("strdup() failed for graph opath");
791 free(graph_ptr);
792 return false;
795 else
797 graph_ptr->opath = NULL;
800 if (!ladish_dict_create(&graph_ptr->dict))
802 log_error("ladish_dict_create() failed for graph");
803 if (graph_ptr->opath != NULL)
805 free(graph_ptr->opath);
807 free(graph_ptr);
808 return false;
811 INIT_LIST_HEAD(&graph_ptr->clients);
812 INIT_LIST_HEAD(&graph_ptr->ports);
813 INIT_LIST_HEAD(&graph_ptr->connections);
815 graph_ptr->graph_version = 1;
816 graph_ptr->next_client_id = 1;
817 graph_ptr->next_port_id = 1;
818 graph_ptr->next_connection_id = 1;
820 graph_ptr->context = NULL;
821 graph_ptr->connect_handler = NULL;
822 graph_ptr->disconnect_handler = NULL;
824 graph_ptr->persist = true;
826 *graph_handle_ptr = (ladish_graph_handle)graph_ptr;
827 return true;
830 static
831 struct ladish_graph_client *
832 ladish_graph_find_client(
833 struct ladish_graph * graph_ptr,
834 ladish_client_handle client)
836 struct list_head * node_ptr;
837 struct ladish_graph_client * client_ptr;
839 list_for_each(node_ptr, &graph_ptr->clients)
841 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
842 if (client_ptr->client == client)
844 return client_ptr;
848 return NULL;
851 static
852 struct ladish_graph_port *
853 ladish_graph_find_port(
854 struct ladish_graph * graph_ptr,
855 ladish_port_handle port)
857 struct list_head * node_ptr;
858 struct ladish_graph_port * port_ptr;
860 //log_info("searching port %p", port);
862 list_for_each(node_ptr, &graph_ptr->ports)
864 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
865 //log_info("checking port %s:%s, %p", port_ptr->client_ptr->name, port_ptr->name, port_ptr->port);
866 if (port_ptr->port == port)
868 return port_ptr;
872 return NULL;
875 #if defined(LOG_PORT_LOOKUP)
876 #undef LOG_PORT_LOOKUP
877 #endif
878 //#define LOG_PORT_LOOKUP
880 static
881 struct ladish_graph_port *
882 ladish_graph_find_port_by_jack_id_internal(
883 struct ladish_graph * graph_ptr,
884 uint64_t port_id,
885 bool room,
886 bool studio)
888 struct list_head * node_ptr;
889 struct ladish_graph_port * port_ptr;
891 ASSERT(room || studio);
893 #if defined(LOG_PORT_LOOKUP)
894 log_info(
895 "searching (in %s, %s) by jack id %"PRIu64" for port in graph %s",
896 studio ? "studio" : "",
897 room ? "room" : "",
898 port_id,
899 ladish_graph_get_description((ladish_graph_handle)graph_ptr));
900 #endif
902 list_for_each(node_ptr, &graph_ptr->ports)
904 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
905 #if defined(LOG_PORT_LOOKUP)
906 log_info(
907 "checking jack port id of port %s:%s, %p; studio id %"PRIu64", room id %"PRIu64,
908 port_ptr->client_ptr->name,
909 port_ptr->name, port_ptr->port,
910 ladish_port_get_jack_id(port_ptr->port),
911 ladish_port_get_jack_id_room(port_ptr->port));
912 #endif
913 if ((studio && ladish_port_get_jack_id(port_ptr->port) == port_id) ||
914 (room && port_ptr->link && ladish_port_get_jack_id_room(port_ptr->port) == port_id))
916 //log_info("found");
917 return port_ptr;
921 return NULL;
924 #if 0
925 static
926 struct ladish_graph_port *
927 ladish_graph_find_client_port(
928 struct ladish_graph * graph_ptr,
929 struct ladish_graph_client * client_ptr,
930 ladish_port_handle port)
932 struct list_head * node_ptr;
933 struct ladish_graph_port * port_ptr;
935 list_for_each(node_ptr, &client_ptr->ports)
937 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
938 if (port_ptr->port == port)
940 return port_ptr;
944 return NULL;
946 #endif
948 static void ladish_graph_hide_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
950 ASSERT(!connection_ptr->hidden);
951 connection_ptr->hidden = true;
952 graph_ptr->graph_version++;
954 if (graph_ptr->opath != NULL)
956 ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
960 static void ladish_graph_show_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
962 if (port_ptr->client_ptr->hidden)
964 port_ptr->client_ptr->hidden = false;
965 graph_ptr->graph_version++;
966 if (graph_ptr->opath != NULL)
968 ladish_graph_emit_client_appeared(graph_ptr, port_ptr->client_ptr);
972 ASSERT(port_ptr->hidden);
973 port_ptr->hidden = false;
974 graph_ptr->graph_version++;
975 if (graph_ptr->opath != NULL)
977 ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
978 ladish_try_connect_hidden_connections((ladish_graph_handle)graph_ptr);
982 static void ladish_graph_hide_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
984 ASSERT(!port_ptr->hidden);
985 port_ptr->hidden = true;
986 graph_ptr->graph_version++;
988 if (graph_ptr->opath != NULL)
990 ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
994 static void ladish_graph_hide_client_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
996 ASSERT(!client_ptr->hidden);
997 client_ptr->hidden = true;
998 graph_ptr->graph_version++;
1000 if (graph_ptr->opath != NULL)
1002 ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1006 static void ladish_hide_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1008 struct list_head * node_ptr;
1009 struct ladish_graph_connection * connection_ptr;
1011 log_info("hidding connections of port %"PRIu64, port_ptr->id);
1013 ASSERT(graph_ptr->opath != NULL);
1015 list_for_each(node_ptr, &graph_ptr->connections)
1017 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
1018 if (!connection_ptr->hidden && (connection_ptr->port1_ptr == port_ptr || connection_ptr->port2_ptr == port_ptr))
1020 log_info("hidding connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
1021 ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
1026 static void ladish_graph_remove_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
1028 list_del(&connection_ptr->siblings);
1029 graph_ptr->graph_version++;
1031 if (!connection_ptr->hidden && graph_ptr->opath != NULL)
1033 ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
1036 ladish_dict_destroy(connection_ptr->dict);
1037 free(connection_ptr);
1040 static void ladish_graph_remove_port_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1042 struct list_head * node_ptr;
1043 struct list_head * temp_node_ptr;
1044 struct ladish_graph_connection * connection_ptr;
1046 list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
1048 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
1049 if (connection_ptr->port1_ptr == port_ptr || connection_ptr->port2_ptr == port_ptr)
1051 log_info("removing connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
1052 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1057 static
1058 void
1059 ladish_graph_remove_port_internal(
1060 struct ladish_graph * graph_ptr,
1061 struct ladish_graph_client * client_ptr,
1062 struct ladish_graph_port * port_ptr)
1064 ladish_graph_remove_port_connections(graph_ptr, port_ptr);
1066 ladish_port_del_ref(port_ptr->port);
1068 list_del(&port_ptr->siblings_client);
1069 list_del(&port_ptr->siblings_graph);
1071 log_info("removing port '%s':'%s' (%"PRIu64":%"PRIu64") from graph %s", client_ptr->name, port_ptr->name, client_ptr->id, port_ptr->id, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1072 if (graph_ptr->opath != NULL && !port_ptr->hidden)
1074 ASSERT(port_ptr->client_ptr == client_ptr);
1075 ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
1078 free(port_ptr->name);
1079 free(port_ptr);
1082 static
1083 void
1084 ladish_graph_remove_client_internal(
1085 struct ladish_graph * graph_ptr,
1086 struct ladish_graph_client * client_ptr,
1087 bool destroy_client,
1088 ladish_graph_simple_port_callback port_callback)
1090 struct ladish_graph_port * port_ptr;
1092 while (!list_empty(&client_ptr->ports))
1094 port_ptr = list_entry(client_ptr->ports.next, struct ladish_graph_port, siblings_client);
1095 if (port_callback != NULL)
1097 port_callback(port_ptr->port);
1099 ladish_graph_remove_port_internal(graph_ptr, client_ptr, port_ptr);
1102 graph_ptr->graph_version++;
1103 list_del(&client_ptr->siblings);
1104 log_info("removing client '%s' (%"PRIu64") from graph %s", client_ptr->name, client_ptr->id, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1105 if (graph_ptr->opath != NULL && !client_ptr->hidden)
1107 ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1110 free(client_ptr->name);
1112 if (destroy_client)
1114 ladish_client_destroy(client_ptr->client);
1117 free(client_ptr);
1120 bool ladish_graph_client_looks_empty_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
1122 struct list_head * node_ptr;
1123 struct ladish_graph_port * port_ptr;
1125 list_for_each(node_ptr, &client_ptr->ports)
1127 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1128 if (!port_ptr->hidden)
1130 //log_info("port '%s' is visible, client '%s' does not look empty", port_ptr->name, client_ptr->name);
1131 return false;
1133 else
1135 //log_info("port '%s' is invisible", port_ptr->name);
1139 //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1140 return true;
1143 #define graph_ptr ((struct ladish_graph *)graph_handle)
1145 void ladish_graph_destroy(ladish_graph_handle graph_handle)
1147 ladish_graph_clear(graph_handle, NULL);
1148 ladish_dict_destroy(graph_ptr->dict);
1149 if (graph_ptr->opath != NULL)
1151 free(graph_ptr->opath);
1153 free(graph_ptr);
1156 const char * ladish_graph_get_opath(ladish_graph_handle graph_handle)
1158 return graph_ptr->opath;
1161 const char * ladish_graph_get_description(ladish_graph_handle graph_handle)
1163 return graph_ptr->opath != NULL ? graph_ptr->opath : "JACK";
1166 void
1167 ladish_graph_set_connection_handlers(
1168 ladish_graph_handle graph_handle,
1169 void * graph_context,
1170 ladish_graph_connect_request_handler connect_handler,
1171 ladish_graph_disconnect_request_handler disconnect_handler)
1173 log_info("setting connection handlers for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1174 graph_ptr->context = graph_context;
1175 graph_ptr->connect_handler = connect_handler;
1176 graph_ptr->disconnect_handler = disconnect_handler;
1179 void ladish_graph_clear(ladish_graph_handle graph_handle, ladish_graph_simple_port_callback port_callback)
1181 struct ladish_graph_client * client_ptr;
1182 struct ladish_graph_connection * connection_ptr;
1184 log_info("ladish_graph_clear() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1186 while (!list_empty(&graph_ptr->connections))
1188 connection_ptr = list_entry(graph_ptr->connections.next, struct ladish_graph_connection, siblings);
1189 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1192 while (!list_empty(&graph_ptr->clients))
1194 client_ptr = list_entry(graph_ptr->clients.next, struct ladish_graph_client, siblings);
1195 ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, port_callback);
1199 void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle)
1201 return graph_handle;
1204 ladish_dict_handle ladish_graph_get_dict(ladish_graph_handle graph_handle)
1206 return graph_ptr->dict;
1209 void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id)
1211 struct ladish_graph_connection * connection_ptr;
1213 log_info("ladish_graph_show_connection() called.");
1215 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1216 if (connection_ptr == NULL)
1218 ASSERT_NO_PASS;
1219 return;
1222 ASSERT(graph_ptr->opath != NULL);
1223 ASSERT(connection_ptr->hidden);
1224 connection_ptr->hidden = false;
1225 connection_ptr->changing = false;
1226 graph_ptr->graph_version++;
1228 ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1231 void ladish_graph_show_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1233 struct ladish_graph_port * port_ptr;
1235 //log_info("ladish_graph_show_port() called.");
1237 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1238 if (port_ptr == NULL)
1240 ASSERT_NO_PASS;
1241 return;
1244 //log_info("port '%s' is %s", port_ptr->name, port_ptr->hidden ? "invisible" : "visible");
1246 ladish_graph_show_port_internal(graph_ptr, port_ptr);
1249 void ladish_graph_hide_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1251 struct ladish_graph_port * port_ptr;
1253 log_info("ladish_graph_hide_port() called.");
1255 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1256 if (port_ptr == NULL)
1258 ASSERT_NO_PASS;
1259 return;
1262 log_info("Hidding port %"PRIu64, port_ptr->id);
1264 ASSERT(!port_ptr->hidden);
1266 if (graph_ptr->opath != NULL)
1268 ladish_hide_connections(graph_ptr, port_ptr);
1271 ladish_graph_hide_port_internal(graph_ptr, port_ptr);
1274 void ladish_graph_hide_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1276 struct ladish_graph_client * client_ptr;
1278 log_info("ladish_graph_hide_client() called.");
1280 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1281 if (client_ptr == NULL)
1283 ASSERT_NO_PASS;
1284 return;
1287 ladish_graph_hide_client_internal(graph_ptr, client_ptr);
1290 void ladish_graph_show_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1292 struct ladish_graph_client * client_ptr;
1294 log_info("ladish_graph_show_client() called.");
1296 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1297 if (client_ptr == NULL)
1299 ASSERT_NO_PASS;
1300 return;
1303 ASSERT(client_ptr->hidden);
1304 client_ptr->hidden = false;
1305 graph_ptr->graph_version++;
1307 if (graph_ptr->opath != NULL)
1309 ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1313 void ladish_graph_adjust_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle, uint32_t type, uint32_t flags)
1315 struct ladish_graph_port * port_ptr;
1317 //log_info("ladish_graph_adjust_port() called.");
1319 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1320 if (port_ptr == NULL)
1322 ASSERT_NO_PASS;
1323 return;
1326 port_ptr->type = type;
1327 port_ptr->flags = flags;
1330 bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name, bool hidden)
1332 struct ladish_graph_client * client_ptr;
1334 log_info("adding client '%s' (%p) to graph %s", name, client_handle, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1336 client_ptr = malloc(sizeof(struct ladish_graph_client));
1337 if (client_ptr == NULL)
1339 log_error("malloc() failed for struct ladish_graph_client");
1340 return false;
1343 client_ptr->name = strdup(name);
1344 if (client_ptr->name == NULL)
1346 log_error("strdup() failed for graph client name");
1347 free(client_ptr);
1348 return false;
1351 client_ptr->id = graph_ptr->next_client_id++;
1352 client_ptr->client = client_handle;
1353 client_ptr->hidden = hidden;
1354 graph_ptr->graph_version++;
1356 INIT_LIST_HEAD(&client_ptr->ports);
1358 list_add_tail(&client_ptr->siblings, &graph_ptr->clients);
1360 if (!hidden && graph_ptr->opath != NULL)
1362 ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1365 return true;
1368 void
1369 ladish_graph_remove_client(
1370 ladish_graph_handle graph_handle,
1371 ladish_client_handle client_handle)
1373 struct ladish_graph_client * client_ptr;
1375 log_info("ladish_graph_remove_client() called.");
1377 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1378 if (client_ptr != NULL)
1380 ladish_graph_remove_client_internal(graph_ptr, client_ptr, false, NULL);
1382 else
1384 ASSERT_NO_PASS;
1388 bool
1389 ladish_graph_add_port(
1390 ladish_graph_handle graph_handle,
1391 ladish_client_handle client_handle,
1392 ladish_port_handle port_handle,
1393 const char * name,
1394 uint32_t type,
1395 uint32_t flags,
1396 bool hidden)
1398 struct ladish_graph_client * client_ptr;
1399 struct ladish_graph_port * port_ptr;
1401 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1402 if (client_ptr == NULL)
1404 log_error("cannot find client to add port to. graph is %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1405 ASSERT_NO_PASS;
1406 return false;
1409 log_info("adding port '%s' (%p) to client '%s' in graph %s", name, port_handle, client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1411 port_ptr = malloc(sizeof(struct ladish_graph_port));
1412 if (port_ptr == NULL)
1414 log_error("malloc() failed for struct ladish_graph_port");
1415 return false;
1418 port_ptr->name = strdup(name);
1419 if (port_ptr->name == NULL)
1421 log_error("strdup() failed for graph port name");
1422 free(port_ptr);
1423 return false;
1426 port_ptr->type = type;
1427 port_ptr->flags = flags;
1429 port_ptr->id = graph_ptr->next_port_id++;
1430 port_ptr->port = port_handle;
1431 ladish_port_add_ref(port_ptr->port);
1432 port_ptr->hidden = true;
1434 port_ptr->link = ladish_port_is_link(port_handle);
1435 if (port_ptr->link)
1437 uuid_generate(port_ptr->link_uuid_override);
1440 port_ptr->client_ptr = client_ptr;
1441 list_add_tail(&port_ptr->siblings_client, &client_ptr->ports);
1442 list_add_tail(&port_ptr->siblings_graph, &graph_ptr->ports);
1444 if (!hidden)
1446 ladish_graph_show_port_internal(graph_ptr, port_ptr);
1449 return true;
1452 uint64_t
1453 ladish_graph_add_connection(
1454 ladish_graph_handle graph_handle,
1455 ladish_port_handle port1_handle,
1456 ladish_port_handle port2_handle,
1457 bool hidden)
1459 struct ladish_graph_port * port1_ptr;
1460 struct ladish_graph_port * port2_ptr;
1461 struct ladish_graph_connection * connection_ptr;
1463 port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1464 ASSERT(port1_ptr != NULL);
1465 port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1466 ASSERT(port2_ptr != NULL);
1468 connection_ptr = malloc(sizeof(struct ladish_graph_connection));
1469 if (connection_ptr == NULL)
1471 log_error("malloc() failed for struct ladish_graph_connection");
1472 return 0;
1475 if (!ladish_dict_create(&connection_ptr->dict))
1477 log_error("ladish_dict_create() failed for connection");
1478 free(connection_ptr);
1479 return 0;
1482 connection_ptr->id = graph_ptr->next_connection_id++;
1483 connection_ptr->port1_ptr = port1_ptr;
1484 connection_ptr->port2_ptr = port2_ptr;
1485 connection_ptr->hidden = hidden;
1486 connection_ptr->changing = false;
1487 graph_ptr->graph_version++;
1489 list_add_tail(&connection_ptr->siblings, &graph_ptr->connections);
1491 /* log_info( */
1492 /* "new connection %"PRIu64" between '%s':'%s' and '%s':'%s'", */
1493 /* connection_ptr->id, */
1494 /* port1_ptr->client_ptr->name, */
1495 /* port1_ptr->name, */
1496 /* port2_ptr->client_ptr->name, */
1497 /* port2_ptr->name); */
1499 if (!hidden && graph_ptr->opath != NULL)
1501 ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1504 return connection_ptr->id;
1507 void
1508 ladish_graph_remove_connection(
1509 ladish_graph_handle graph_handle,
1510 uint64_t connection_id,
1511 bool force)
1513 struct ladish_graph_connection * connection_ptr;
1515 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1516 if (connection_ptr == NULL)
1518 ASSERT_NO_PASS;
1519 return;
1522 if (force || connection_ptr->changing || !graph_ptr->persist)
1524 /* log_info( */
1525 /* "removing connection '%s':'%s' - '%s':'%s'", */
1526 /* connection_ptr->port1_ptr->client_ptr->name, */
1527 /* connection_ptr->port1_ptr->name, */
1528 /* connection_ptr->port2_ptr->client_ptr->name, */
1529 /* connection_ptr->port2_ptr->name); */
1531 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1533 else
1535 /* log_info( */
1536 /* "hiding connection '%s':'%s' - '%s':'%s'", */
1537 /* connection_ptr->port1_ptr->client_ptr->name, */
1538 /* connection_ptr->port1_ptr->name, */
1539 /* connection_ptr->port2_ptr->client_ptr->name, */
1540 /* connection_ptr->port2_ptr->name); */
1542 ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
1546 bool
1547 ladish_graph_get_connection_ports(
1548 ladish_graph_handle graph_handle,
1549 uint64_t connection_id,
1550 ladish_port_handle * port1_handle_ptr,
1551 ladish_port_handle * port2_handle_ptr)
1553 struct ladish_graph_connection * connection_ptr;
1555 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1556 if (connection_ptr == NULL)
1558 return false;
1561 *port1_handle_ptr = connection_ptr->port1_ptr->port;
1562 *port2_handle_ptr = connection_ptr->port2_ptr->port;
1564 return true;
1567 ladish_dict_handle ladish_graph_get_connection_dict(ladish_graph_handle graph_handle, uint64_t connection_id)
1569 struct ladish_graph_connection * connection_ptr;
1571 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1572 if (connection_ptr == NULL)
1574 return NULL;
1577 return connection_ptr->dict;
1580 bool
1581 ladish_graph_find_connection(
1582 ladish_graph_handle graph_handle,
1583 ladish_port_handle port1_handle,
1584 ladish_port_handle port2_handle,
1585 uint64_t * connection_id_ptr)
1587 struct ladish_graph_port * port1_ptr;
1588 struct ladish_graph_port * port2_ptr;
1589 struct ladish_graph_connection * connection_ptr;
1591 port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1592 if (port1_ptr == NULL)
1594 return false;
1597 port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1598 if (port1_ptr == NULL)
1600 return false;
1603 connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
1604 if (connection_ptr == NULL)
1606 return false;
1609 *connection_id_ptr = connection_ptr->id;
1611 return true;
1614 ladish_client_handle ladish_graph_find_client_by_name(ladish_graph_handle graph_handle, const char * name, bool appless)
1616 struct list_head * node_ptr;
1617 struct ladish_graph_client * client_ptr;
1619 list_for_each(node_ptr, &graph_ptr->clients)
1621 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1622 if (strcmp(client_ptr->name, name) == 0 &&
1623 (!appless || !ladish_client_has_app(client_ptr->client))) /* if appless is true, then an appless client is being searched */
1625 return client_ptr->client;
1629 return NULL;
1632 ladish_client_handle ladish_graph_find_client_by_app(ladish_graph_handle graph_handle, const uuid_t app_uuid)
1634 struct list_head * node_ptr;
1635 struct ladish_graph_client * client_ptr;
1636 uuid_t current_uuid;
1638 list_for_each(node_ptr, &graph_ptr->clients)
1640 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1641 if(! ladish_client_get_app(client_ptr->client, current_uuid))
1642 continue;
1644 if (uuid_compare(current_uuid, app_uuid) == 0)
1646 return client_ptr->client;
1650 return NULL;
1653 ladish_port_handle
1654 ladish_graph_find_port_by_name(
1655 ladish_graph_handle graph_handle,
1656 ladish_client_handle client_handle,
1657 const char * name,
1658 void * vgraph_filter)
1660 struct ladish_graph_client * client_ptr;
1661 struct list_head * node_ptr;
1662 struct ladish_graph_port * port_ptr;
1664 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1665 if (client_ptr != NULL)
1667 list_for_each(node_ptr, &client_ptr->ports)
1669 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1671 if (vgraph_filter != NULL && ladish_port_get_vgraph(port_ptr->port) != vgraph_filter)
1673 continue;
1676 if (strcmp(port_ptr->name, name) == 0)
1678 return port_ptr->port;
1682 else
1684 ASSERT_NO_PASS;
1687 return NULL;
1690 ladish_client_handle ladish_graph_find_client_by_uuid(ladish_graph_handle graph_handle, const uuid_t uuid)
1692 struct list_head * node_ptr;
1693 struct ladish_graph_client * client_ptr;
1694 uuid_t current_uuid;
1696 list_for_each(node_ptr, &graph_ptr->clients)
1698 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1699 ladish_client_get_uuid(client_ptr->client, current_uuid);
1700 if (uuid_compare(current_uuid, uuid) == 0)
1702 return client_ptr->client;
1706 return NULL;
1709 ladish_port_handle ladish_graph_find_port_by_uuid(ladish_graph_handle graph_handle, const uuid_t uuid, bool use_link_override_uuids, void * vgraph_filter)
1711 struct ladish_graph_port * port_ptr;
1713 port_ptr = ladish_graph_find_port_by_uuid_internal(graph_ptr, NULL, uuid, use_link_override_uuids, vgraph_filter);
1714 if (port_ptr != NULL)
1716 return port_ptr->port;
1719 return NULL;
1722 ladish_client_handle ladish_graph_get_port_client(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1724 struct ladish_graph_port * port_ptr;
1726 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1727 if (port_ptr == NULL)
1729 return NULL;
1732 return port_ptr->client_ptr->client;
1735 bool ladish_graph_is_port_present(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1737 return ladish_graph_find_port(graph_ptr, port_handle) != NULL;
1740 ladish_client_handle ladish_graph_find_client_by_id(ladish_graph_handle graph_handle, uint64_t client_id)
1742 struct list_head * node_ptr;
1743 struct ladish_graph_client * client_ptr;
1745 list_for_each(node_ptr, &graph_ptr->clients)
1747 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1748 if (client_ptr->id == client_id)
1750 return client_ptr->client;
1754 return NULL;
1757 ladish_port_handle ladish_graph_find_port_by_id(ladish_graph_handle graph_handle, uint64_t port_id)
1759 struct ladish_graph_port * port_ptr;
1761 port_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port_id);
1762 if (port_ptr == NULL)
1764 return NULL;
1767 return port_ptr->port;
1770 ladish_client_handle ladish_graph_find_client_by_jack_id(ladish_graph_handle graph_handle, uint64_t client_id)
1772 struct list_head * node_ptr;
1773 struct ladish_graph_client * client_ptr;
1775 list_for_each(node_ptr, &graph_ptr->clients)
1777 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1778 if (ladish_client_get_jack_id(client_ptr->client) == client_id)
1780 return client_ptr->client;
1784 return NULL;
1787 ladish_port_handle ladish_graph_find_port_by_jack_id(ladish_graph_handle graph_handle, uint64_t port_id, bool room, bool studio)
1789 struct ladish_graph_port * port_ptr;
1791 port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, port_id, room, studio);
1792 if (port_ptr == NULL)
1794 return NULL;
1797 return port_ptr->port;
1800 bool ladish_graph_client_has_visible_app_port(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const uuid_t app_uuid)
1802 struct ladish_graph_client * client_ptr;
1803 struct list_head * node_ptr;
1804 struct ladish_graph_port * port_ptr;
1806 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1807 if (client_ptr == NULL)
1809 ASSERT_NO_PASS;
1810 return false;
1813 list_for_each(node_ptr, &client_ptr->ports)
1815 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1816 if (port_ptr->hidden)
1818 continue;
1821 if (ladish_port_belongs_to_app(port_ptr->port, app_uuid))
1823 ASSERT(!client_ptr->hidden);
1824 return true;
1828 return false;
1831 ladish_client_handle
1832 ladish_graph_remove_port(
1833 ladish_graph_handle graph_handle,
1834 ladish_port_handle port)
1836 struct ladish_graph_port * port_ptr;
1837 ladish_client_handle client;
1839 port_ptr = ladish_graph_find_port(graph_ptr, port);
1840 if (port_ptr == NULL)
1842 return NULL;
1845 client = port_ptr->client_ptr->client;
1846 ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
1847 return client;
1850 ladish_client_handle
1851 ladish_graph_remove_port_by_jack_id(
1852 ladish_graph_handle graph_handle,
1853 uint64_t jack_port_id,
1854 bool room,
1855 bool studio)
1857 struct ladish_graph_port * port_ptr;
1858 ladish_client_handle client;
1860 port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, jack_port_id, room, studio);
1861 if (port_ptr == NULL)
1863 return NULL;
1866 client = port_ptr->client_ptr->client;
1867 ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
1868 return client;
1871 bool
1872 ladish_graph_rename_client(
1873 ladish_graph_handle graph_handle,
1874 ladish_client_handle client_handle,
1875 const char * new_client_name)
1877 char * name;
1878 struct ladish_graph_client * client_ptr;
1879 char * old_name;
1881 name = strdup(new_client_name);
1882 if (name == NULL)
1884 log_error("strdup('%s') failed.", new_client_name);
1885 return false;
1888 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1889 if (client_ptr == NULL)
1891 free(name);
1892 ASSERT_NO_PASS;
1893 return false;
1896 old_name = client_ptr->name;
1897 client_ptr->name = name;
1899 graph_ptr->graph_version++;
1901 if (!client_ptr->hidden && graph_ptr->opath != NULL)
1903 dbus_signal_emit(
1904 g_dbus_connection,
1905 graph_ptr->opath,
1906 JACKDBUS_IFACE_PATCHBAY,
1907 "ClientRenamed",
1908 "ttss",
1909 &graph_ptr->graph_version,
1910 &client_ptr->id,
1911 &old_name,
1912 &client_ptr->name);
1915 free(old_name);
1917 return true;
1920 bool
1921 ladish_graph_rename_port(
1922 ladish_graph_handle graph_handle,
1923 ladish_port_handle port_handle,
1924 const char * new_port_name)
1926 char * name;
1927 struct ladish_graph_port * port_ptr;
1928 char * old_name;
1930 name = strdup(new_port_name);
1931 if (name == NULL)
1933 log_error("strdup('%s') failed.", new_port_name);
1934 return false;
1937 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1938 if (port_ptr == NULL)
1940 ASSERT_NO_PASS;
1941 free(name);
1942 return false;
1945 old_name = port_ptr->name;
1946 port_ptr->name = name;
1948 graph_ptr->graph_version++;
1950 if (!port_ptr->hidden && graph_ptr->opath != NULL)
1952 dbus_signal_emit(
1953 g_dbus_connection,
1954 graph_ptr->opath,
1955 JACKDBUS_IFACE_PATCHBAY,
1956 "PortRenamed",
1957 "ttstss",
1958 &graph_ptr->graph_version,
1959 &port_ptr->client_ptr->id,
1960 &port_ptr->client_ptr->name,
1961 &port_ptr->id,
1962 &old_name,
1963 &port_ptr->name);
1966 free(old_name);
1968 return true;
1971 const char * ladish_graph_get_client_name(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1973 struct ladish_graph_client * client_ptr;
1975 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1976 if (client_ptr != NULL)
1978 return client_ptr->name;
1981 ASSERT_NO_PASS;
1982 return NULL;
1985 bool ladish_graph_client_is_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1987 struct ladish_graph_client * client_ptr;
1989 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1990 if (client_ptr != NULL)
1992 return list_empty(&client_ptr->ports);
1995 ASSERT_NO_PASS;
1996 return true;
1999 bool ladish_graph_client_looks_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2001 struct ladish_graph_client * client_ptr;
2003 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2004 if (client_ptr == NULL)
2006 ASSERT_NO_PASS;
2007 return true;
2010 if (ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2012 //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2013 return true;
2016 return false;
2019 bool ladish_graph_client_is_hidden(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2021 struct ladish_graph_client * client_ptr;
2023 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2024 if (client_ptr != NULL)
2026 return client_ptr->hidden;
2029 ASSERT_NO_PASS;
2030 return true;
2033 void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle)
2035 struct list_head * node_ptr;
2036 struct ladish_graph_connection * connection_ptr;
2038 if (!list_empty(&graph_ptr->connections) && graph_ptr->connect_handler == NULL)
2040 ASSERT_NO_PASS;
2041 return;
2044 ASSERT(graph_ptr->opath != NULL);
2046 list_for_each(node_ptr, &graph_ptr->connections)
2048 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2049 log_debug(
2050 "checking connection (%s, %s) '%s':'%s' (%s) to '%s':'%s' (%s)",
2051 connection_ptr->hidden ? "hidden" : "visible",
2052 connection_ptr->changing ? "changing" : "not changing",
2053 connection_ptr->port1_ptr->client_ptr->name,
2054 connection_ptr->port1_ptr->name,
2055 connection_ptr->port1_ptr->hidden ? "hidden" : "visible",
2056 connection_ptr->port2_ptr->client_ptr->name,
2057 connection_ptr->port2_ptr->name,
2058 connection_ptr->port2_ptr->hidden ? "hidden" : "visible");
2059 if (connection_ptr->hidden &&
2060 !connection_ptr->changing &&
2061 !connection_ptr->port1_ptr->hidden &&
2062 !connection_ptr->port2_ptr->hidden)
2064 log_info(
2065 "auto connecting '%s':'%s' to '%s':'%s'",
2066 connection_ptr->port1_ptr->client_ptr->name,
2067 connection_ptr->port1_ptr->name,
2068 connection_ptr->port2_ptr->client_ptr->name,
2069 connection_ptr->port2_ptr->name);
2071 connection_ptr->changing = true;
2072 if (!graph_ptr->connect_handler(graph_ptr->context, graph_handle, connection_ptr->port1_ptr->port, connection_ptr->port2_ptr->port))
2074 connection_ptr->changing = false;
2075 log_error("auto connect failed.");
2081 bool ladish_disconnect_visible_connections(ladish_graph_handle graph_handle)
2083 struct list_head * node_ptr;
2084 struct ladish_graph_connection * connection_ptr;
2086 if (graph_ptr->disconnect_handler == NULL)
2088 ASSERT_NO_PASS;
2089 return false;
2092 ASSERT(graph_ptr->opath != NULL);
2094 list_for_each(node_ptr, &graph_ptr->connections)
2096 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2097 log_debug(
2098 "checking connection (%s, %s) '%s':'%s' (%s) to '%s':'%s' (%s)",
2099 connection_ptr->hidden ? "hidden" : "visible",
2100 connection_ptr->changing ? "changing" : "not changing",
2101 connection_ptr->port1_ptr->client_ptr->name,
2102 connection_ptr->port1_ptr->name,
2103 connection_ptr->port1_ptr->hidden ? "hidden" : "visible",
2104 connection_ptr->port2_ptr->client_ptr->name,
2105 connection_ptr->port2_ptr->name,
2106 connection_ptr->port2_ptr->hidden ? "hidden" : "visible");
2107 if (!connection_ptr->hidden &&
2108 !connection_ptr->changing &&
2109 !connection_ptr->port1_ptr->hidden &&
2110 !connection_ptr->port2_ptr->hidden)
2112 log_info(
2113 "disconnecting '%s':'%s' from '%s':'%s'",
2114 connection_ptr->port1_ptr->client_ptr->name,
2115 connection_ptr->port1_ptr->name,
2116 connection_ptr->port2_ptr->client_ptr->name,
2117 connection_ptr->port2_ptr->name);
2119 connection_ptr->changing = true;
2120 if (!graph_ptr->disconnect_handler(graph_ptr->context, graph_handle, connection_ptr->id))
2122 connection_ptr->changing = false;
2123 log_error("disconnect failed.");
2124 return false;
2129 return true;
2132 void ladish_graph_hide_non_virtual(ladish_graph_handle graph_handle)
2134 struct list_head * node_ptr;
2135 struct ladish_graph_connection * connection_ptr;
2136 struct ladish_graph_port * port_ptr;
2137 struct ladish_graph_client * client_ptr;
2139 log_info("hiding everything in graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2141 list_for_each(node_ptr, &graph_ptr->connections)
2143 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2144 if (!connection_ptr->hidden &&
2145 (ladish_client_get_jack_id(connection_ptr->port1_ptr->client_ptr->client) != 0 ||
2146 ladish_client_get_jack_id(connection_ptr->port2_ptr->client_ptr->client) != 0))
2148 log_debug("hidding connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
2149 ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
2153 list_for_each(node_ptr, &graph_ptr->ports)
2155 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2156 if (!port_ptr->hidden && ladish_client_get_jack_id(port_ptr->client_ptr->client) != 0)
2158 ladish_port_set_jack_id(port_ptr->port, 0);
2159 ladish_graph_hide_port_internal(graph_ptr, port_ptr);
2163 list_for_each(node_ptr, &graph_ptr->clients)
2165 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2166 if (!client_ptr->hidden && ladish_client_get_jack_id(client_ptr->client) != 0)
2168 ladish_client_set_jack_id(client_ptr->client, 0);
2169 ladish_graph_hide_client_internal(graph_ptr, client_ptr);
2174 void ladish_graph_get_port_uuid(ladish_graph_handle graph_handle, ladish_port_handle port, uuid_t uuid_ptr)
2176 struct ladish_graph_port * port_ptr;
2178 port_ptr = ladish_graph_find_port(graph_ptr, port);
2179 ASSERT(port_ptr != NULL);
2180 ASSERT(port_ptr->link);
2182 uuid_copy(uuid_ptr, port_ptr->link_uuid_override);
2185 const char * ladish_graph_get_port_name(ladish_graph_handle graph_handle, ladish_port_handle port)
2187 struct ladish_graph_port * port_ptr;
2189 port_ptr = ladish_graph_find_port(graph_ptr, port);
2190 ASSERT(port_ptr != NULL);
2192 return port_ptr->name;
2195 ladish_port_handle
2196 ladish_graph_find_client_port_by_uuid(
2197 ladish_graph_handle graph_handle,
2198 ladish_client_handle client,
2199 const uuid_t uuid,
2200 bool use_link_override_uuids)
2202 struct ladish_graph_client * client_ptr;
2203 struct ladish_graph_port * port_ptr;
2205 client_ptr = ladish_graph_find_client(graph_ptr, client);
2206 ASSERT(client_ptr != NULL);
2208 port_ptr = ladish_graph_find_port_by_uuid_internal(graph_ptr, client_ptr, uuid, use_link_override_uuids, NULL);
2209 if (port_ptr != NULL)
2211 return port_ptr->port;
2214 return NULL;
2217 void
2218 ladish_graph_set_link_port_override_uuid(
2219 ladish_graph_handle graph_handle,
2220 ladish_port_handle port,
2221 const uuid_t override_uuid)
2223 struct ladish_graph_port * port_ptr;
2225 port_ptr = ladish_graph_find_port(graph_ptr, port);
2226 ASSERT(ladish_port_is_link(port_ptr->port));
2228 uuid_copy(port_ptr->link_uuid_override, override_uuid);
2231 bool
2232 ladish_graph_iterate_nodes(
2233 ladish_graph_handle graph_handle,
2234 bool skip_hidden,
2235 void * callback_context,
2236 bool
2237 (* client_begin_callback)(
2238 void * context,
2239 ladish_graph_handle graph_handle,
2240 ladish_client_handle client_handle,
2241 const char * client_name,
2242 void ** client_iteration_context_ptr_ptr),
2243 bool
2244 (* port_callback)(
2245 void * context,
2246 ladish_graph_handle graph_handle,
2247 void * client_iteration_context_ptr,
2248 ladish_client_handle client_handle,
2249 const char * client_name,
2250 ladish_port_handle port_handle,
2251 const char * port_name,
2252 uint32_t port_type,
2253 uint32_t port_flags),
2254 bool
2255 (* client_end_callback)(
2256 void * context,
2257 ladish_graph_handle graph_handle,
2258 ladish_client_handle client_handle,
2259 const char * client_name,
2260 void * client_iteration_context_ptr))
2262 struct list_head * client_node_ptr;
2263 struct ladish_graph_client * client_ptr;
2264 void * client_context;
2265 struct list_head * port_node_ptr;
2266 struct list_head * port_temp_node_ptr;
2267 struct ladish_graph_port * port_ptr;
2269 list_for_each(client_node_ptr, &graph_ptr->clients)
2271 client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2273 if (skip_hidden && client_ptr->hidden && !ladish_client_has_app(client_ptr->client))
2275 continue;
2278 if (client_begin_callback != NULL)
2280 if (!client_begin_callback(callback_context, graph_handle, client_ptr->client, client_ptr->name, &client_context))
2282 return false;
2285 else
2287 client_context = NULL;
2290 if (port_callback == NULL)
2292 continue;
2295 list_for_each_safe(port_node_ptr, port_temp_node_ptr, &client_ptr->ports)
2297 port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2299 if (skip_hidden && port_ptr->hidden && !ladish_client_has_app(port_ptr->client_ptr->client))
2301 continue;
2304 if (!port_callback(
2305 callback_context,
2306 graph_handle,
2307 client_context,
2308 client_ptr->client,
2309 client_ptr->name,
2310 port_ptr->port,
2311 port_ptr->name,
2312 port_ptr->type,
2313 port_ptr->flags))
2315 return false;
2319 if (client_end_callback != NULL)
2321 if (!client_end_callback(callback_context, graph_handle, client_ptr->client, client_ptr->name, &client_context))
2323 return false;
2328 return true;
2331 static bool is_system_client(ladish_client_handle client)
2333 uuid_t uuid;
2334 ladish_client_get_uuid(client, uuid);
2335 return ladish_virtualizer_is_system_client(uuid);
2338 #define is_port_interesting(port_ptr) ( \
2339 ladish_client_has_app(port_ptr->client_ptr->client) || \
2340 ladish_port_is_link(port_ptr->port) || \
2341 is_system_client(port_ptr->client_ptr->client) \
2344 bool
2345 ladish_graph_iterate_connections(
2346 ladish_graph_handle graph_handle,
2347 bool skip_hidden,
2348 void * callback_context,
2349 bool (* callback)(
2350 void * context,
2351 ladish_graph_handle graph_handle,
2352 ladish_port_handle port1_handle,
2353 ladish_port_handle port2_handle,
2354 ladish_dict_handle dict))
2356 struct list_head * node_ptr;
2357 struct ladish_graph_connection * connection_ptr;
2359 list_for_each(node_ptr, &graph_ptr->connections)
2361 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2363 if (skip_hidden &&
2364 connection_ptr->hidden &&
2365 (!is_port_interesting(connection_ptr->port1_ptr) ||
2366 !is_port_interesting(connection_ptr->port2_ptr)))
2368 continue;
2371 if (!callback(callback_context, graph_handle, connection_ptr->port1_ptr->port, connection_ptr->port2_ptr->port, connection_ptr->dict))
2373 return false;
2377 return true;
2380 static
2381 bool
2382 dump_dict_entry(
2383 void * context,
2384 const char * key,
2385 const char * value)
2387 log_info("%s key '%s' with value '%s'", (const char *)context, key, value);
2388 return true;
2391 static
2392 void
2393 dump_dict(
2394 const char * indent,
2395 ladish_dict_handle dict)
2397 if (ladish_dict_is_empty(dict))
2399 return;
2402 log_info("%sdict:", indent);
2403 ladish_dict_iterate(dict, (void *)indent, dump_dict_entry);
2406 void ladish_graph_dump(ladish_graph_handle graph_handle)
2408 struct list_head * client_node_ptr;
2409 struct ladish_graph_client * client_ptr;
2410 struct list_head * port_node_ptr;
2411 struct ladish_graph_port * port_ptr;
2412 struct list_head * connection_node_ptr;
2413 struct ladish_graph_connection * connection_ptr;
2414 uuid_t uuid;
2415 char uuid_str[37];
2417 log_info("graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2418 log_info(" version %"PRIu64, graph_ptr->graph_version);
2419 log_info(" persist: %s", graph_ptr->persist ? "yes" : "no");
2420 dump_dict(" ", graph_ptr->dict);
2421 log_info(" clients:");
2422 list_for_each(client_node_ptr, &graph_ptr->clients)
2424 client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2425 log_info(" %s client '%s', id=%"PRIu64", ptr=%p%", client_ptr->hidden ? "invisible" : "visible", client_ptr->name, client_ptr->id, client_ptr->client);
2426 ladish_client_get_uuid(client_ptr->client, uuid);
2427 uuid_unparse(uuid, uuid_str);
2428 log_info(" uuid=%s", uuid_str);
2429 if (ladish_client_get_interlink(client_ptr->client, uuid))
2431 uuid_unparse(uuid, uuid_str);
2432 log_info(" interlink=%s", uuid_str);
2434 else
2436 log_info(" no interlink");
2438 dump_dict(" ", ladish_client_get_dict(client_ptr->client));
2439 log_info(" ports:");
2440 list_for_each(port_node_ptr, &client_ptr->ports)
2442 port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2444 ladish_port_get_uuid(port_ptr->port, uuid);
2445 uuid_unparse(uuid, uuid_str);
2447 log_info(" %s port '%s', uuid=%s, id=%"PRIu64", type=0x%"PRIX32", flags=0x%"PRIX32", ptr=%p", port_ptr->hidden ? "invisible" : "visible", port_ptr->name, uuid_str, port_ptr->id, port_ptr->type, port_ptr->flags, port_ptr->port);
2448 dump_dict(" ", ladish_port_get_dict(port_ptr->port));
2451 log_info(" connections:");
2452 list_for_each(connection_node_ptr, &graph_ptr->connections)
2454 connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
2456 log_info(
2457 " %s connection '%s':'%s' - '%s':'%s'%s",
2458 connection_ptr->hidden ? "invisible" : "visible",
2459 connection_ptr->port1_ptr->client_ptr->name,
2460 connection_ptr->port1_ptr->name,
2461 connection_ptr->port2_ptr->client_ptr->name,
2462 connection_ptr->port2_ptr->name,
2463 connection_ptr->changing ? " [changing]" : "");
2464 dump_dict(" ", connection_ptr->dict);
2468 void ladish_graph_clear_persist(ladish_graph_handle graph_handle)
2470 log_info("Clearing persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2471 graph_ptr->persist = false;
2474 void ladish_graph_set_persist(ladish_graph_handle graph_handle)
2476 log_info("Setting persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2477 graph_ptr->persist = true;
2480 bool ladish_graph_is_persist(ladish_graph_handle graph_handle)
2482 return graph_ptr->persist;
2485 bool ladish_graph_has_visible_connections(ladish_graph_handle graph_handle)
2487 struct list_head * node_ptr;
2488 struct ladish_graph_connection * connection_ptr;
2490 list_for_each(node_ptr, &graph_ptr->connections)
2492 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2494 if (!connection_ptr->hidden)
2496 return true;
2500 return false;
2503 bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
2505 struct list_head * node_ptr;
2506 struct ladish_graph_client * client_ptr;
2508 if (ladish_graph_has_visible_connections(graph_handle))
2510 return false;
2513 list_for_each(node_ptr, &graph_ptr->clients)
2515 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2516 if (!ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2518 return false;
2522 return true;
2525 void ladish_graph_remove_hidden_objects(ladish_graph_handle graph_handle)
2527 struct list_head * node_ptr;
2528 struct list_head * temp_node_ptr;
2529 struct ladish_graph_client * client_ptr;
2530 struct ladish_graph_connection * connection_ptr;
2532 log_info("ladish_graph_remove_hidden_objects() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2534 list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
2536 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2537 if (connection_ptr->hidden)
2539 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
2543 list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->clients)
2545 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2546 if (client_ptr->hidden)
2548 ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, NULL);
2553 /* Trick the world that graph objects disappear and the reapper so the new dict values are fetched */
2554 /* This is a nasty hack and should be removed once dict object can emit signals */
2555 void ladish_graph_trick_dicts(ladish_graph_handle graph_handle)
2557 struct list_head * node_ptr;
2558 struct ladish_graph_connection * connection_ptr;
2559 struct ladish_graph_client * client_ptr;
2560 struct ladish_graph_port * port_ptr;
2562 list_for_each(node_ptr, &graph_ptr->connections)
2564 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2565 if (!connection_ptr->hidden)
2567 graph_ptr->graph_version++;
2568 ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
2572 list_for_each(node_ptr, &graph_ptr->ports)
2574 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2576 if (!port_ptr->hidden)
2578 graph_ptr->graph_version++;
2579 ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
2583 list_for_each(node_ptr, &graph_ptr->clients)
2585 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2587 if (!client_ptr->hidden)
2589 graph_ptr->graph_version++;
2590 ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
2591 graph_ptr->graph_version++;
2592 ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
2596 list_for_each(node_ptr, &graph_ptr->ports)
2598 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2600 if (!port_ptr->hidden)
2602 graph_ptr->graph_version++;
2603 ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
2607 list_for_each(node_ptr, &graph_ptr->connections)
2609 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2610 if (!connection_ptr->hidden)
2612 graph_ptr->graph_version++;
2613 ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
2618 #undef graph_ptr
2619 #define graph_ptr ((struct ladish_graph *)context)
2621 static
2622 bool
2623 ladish_graph_copy_client_begin_callback(
2624 void * context,
2625 ladish_graph_handle graph_handle,
2626 ladish_client_handle client_handle,
2627 const char * client_name,
2628 void ** client_iteration_context_ptr_ptr)
2630 ladish_client_handle copy;
2632 if (!ladish_client_create_copy(client_handle, &copy))
2634 return false;
2637 if (!ladish_graph_add_client(context, copy, client_name, false))
2639 ladish_client_destroy(copy);
2640 return false;
2643 *client_iteration_context_ptr_ptr = copy;
2645 return true;
2648 static
2649 bool
2650 ladish_graph_copy_port_callback(
2651 void * context,
2652 ladish_graph_handle graph_handle,
2653 void * client_iteration_context_ptr,
2654 ladish_client_handle client_handle,
2655 const char * client_name,
2656 ladish_port_handle port_handle,
2657 const char * port_name,
2658 uint32_t port_type,
2659 uint32_t port_flags)
2661 ladish_port_handle copy;
2663 if (!ladish_port_create_copy(port_handle, &copy))
2665 return false;
2668 if (!ladish_graph_add_port(context, client_iteration_context_ptr, copy, port_name, port_type, port_flags, true))
2670 ladish_port_destroy(copy);
2671 return false;
2674 return true;
2677 #undef graph_ptr
2679 bool ladish_graph_copy(ladish_graph_handle src, ladish_graph_handle dest, bool skip_hidden)
2681 return ladish_graph_iterate_nodes(
2682 src,
2683 skip_hidden,
2684 dest,
2685 ladish_graph_copy_client_begin_callback,
2686 ladish_graph_copy_port_callback,
2687 NULL);
2690 METHOD_ARGS_BEGIN(GetAllPorts, "Get all ports")
2691 METHOD_ARG_DESCRIBE_IN("ports_list", "as", "List of all ports")
2692 METHOD_ARGS_END
2694 METHOD_ARGS_BEGIN(GetGraph, "Get whole graph")
2695 METHOD_ARG_DESCRIBE_IN("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Known graph version")
2696 METHOD_ARG_DESCRIBE_OUT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Current graph version")
2697 METHOD_ARG_DESCRIBE_OUT("clients_and_ports", "a(tsa(tsuu))", "Clients and their ports")
2698 METHOD_ARG_DESCRIBE_OUT("connections", "a(tstststst)", "Connections array")
2699 METHOD_ARGS_END
2701 METHOD_ARGS_BEGIN(ConnectPortsByName, "Connect ports")
2702 METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2703 METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2704 METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2705 METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2706 METHOD_ARGS_END
2708 METHOD_ARGS_BEGIN(ConnectPortsByID, "Connect ports")
2709 METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2710 METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2711 METHOD_ARGS_END
2713 METHOD_ARGS_BEGIN(DisconnectPortsByName, "Disconnect ports")
2714 METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2715 METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2716 METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2717 METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2718 METHOD_ARGS_END
2720 METHOD_ARGS_BEGIN(DisconnectPortsByID, "Disconnect ports")
2721 METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2722 METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2723 METHOD_ARGS_END
2725 METHOD_ARGS_BEGIN(DisconnectPortsByConnectionID, "Disconnect ports")
2726 METHOD_ARG_DESCRIBE_IN("connection_id", DBUS_TYPE_UINT64_AS_STRING, "id of connection to disconnect")
2727 METHOD_ARGS_END
2729 METHOD_ARGS_BEGIN(GetClientPID, "get process id of client")
2730 METHOD_ARG_DESCRIBE_IN("client_id", DBUS_TYPE_UINT64_AS_STRING, "id of client")
2731 METHOD_ARG_DESCRIBE_OUT("process_id", DBUS_TYPE_INT64_AS_STRING, "pid of client")
2732 METHOD_ARGS_END
2734 METHODS_BEGIN
2735 METHOD_DESCRIBE(GetAllPorts, get_all_ports)
2736 METHOD_DESCRIBE(GetGraph, get_graph)
2737 METHOD_DESCRIBE(ConnectPortsByName, connect_ports_by_name)
2738 METHOD_DESCRIBE(ConnectPortsByID, connect_ports_by_id)
2739 METHOD_DESCRIBE(DisconnectPortsByName, disconnect_ports_by_name)
2740 METHOD_DESCRIBE(DisconnectPortsByID, disconnect_ports_by_id)
2741 METHOD_DESCRIBE(DisconnectPortsByConnectionID, disconnect_ports_by_connection_id)
2742 METHOD_DESCRIBE(GetClientPID, get_client_pid)
2743 METHODS_END
2745 SIGNAL_ARGS_BEGIN(GraphChanged, "")
2746 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2747 SIGNAL_ARGS_END
2749 SIGNAL_ARGS_BEGIN(ClientAppeared, "")
2750 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2751 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2752 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2753 SIGNAL_ARGS_END
2755 SIGNAL_ARGS_BEGIN(ClientDisappeared, "")
2756 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2757 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2758 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2759 SIGNAL_ARGS_END
2761 SIGNAL_ARGS_BEGIN(PortAppeared, "")
2762 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2763 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2764 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2765 SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
2766 SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
2767 SIGNAL_ARG_DESCRIBE("port_flags", DBUS_TYPE_UINT32_AS_STRING, "")
2768 SIGNAL_ARG_DESCRIBE("port_type", DBUS_TYPE_UINT32_AS_STRING, "")
2769 SIGNAL_ARGS_END
2771 SIGNAL_ARGS_BEGIN(PortDisappeared, "")
2772 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2773 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2774 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2775 SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
2776 SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
2777 SIGNAL_ARGS_END
2779 SIGNAL_ARGS_BEGIN(PortsConnected, "")
2780 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2781 SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2782 SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
2783 SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2784 SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
2785 SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2786 SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
2787 SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2788 SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
2789 SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
2790 SIGNAL_ARGS_END
2792 SIGNAL_ARGS_BEGIN(PortsDisconnected, "")
2793 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2794 SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2795 SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
2796 SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2797 SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
2798 SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2799 SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
2800 SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2801 SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
2802 SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
2803 SIGNAL_ARGS_END
2805 SIGNALS_BEGIN
2806 SIGNAL_DESCRIBE(GraphChanged)
2807 SIGNAL_DESCRIBE(ClientAppeared)
2808 SIGNAL_DESCRIBE(ClientDisappeared)
2809 SIGNAL_DESCRIBE(PortAppeared)
2810 SIGNAL_DESCRIBE(PortDisappeared)
2811 SIGNAL_DESCRIBE(PortsConnected)
2812 SIGNAL_DESCRIBE(PortsDisconnected)
2813 SIGNALS_END
2815 INTERFACE_BEGIN(g_interface_patchbay, JACKDBUS_IFACE_PATCHBAY)
2816 INTERFACE_DEFAULT_HANDLER
2817 INTERFACE_EXPOSE_METHODS
2818 INTERFACE_EXPOSE_SIGNALS
2819 INTERFACE_END