on project load adjust canvas positions of capture/playback clients
[ladish.git] / daemon / graph.c
blob899667437f4e4594a29a92b353123d2a2ab8e3df
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)
224 struct list_head * node_ptr;
225 struct ladish_graph_port * port_ptr;
226 uuid_t current_uuid;
227 #if defined(LOG_PORT_LOOKUP)
228 char uuid1_str[37];
229 char uuid2_str[37];
231 log_info("searching by uuid for port in graph %s", ladish_graph_get_description((ladish_graph_handle)graph_ptr));
232 uuid_unparse(uuid, uuid1_str);
233 #endif
235 list_for_each(node_ptr, &graph_ptr->ports)
237 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
239 if (client_ptr != NULL && port_ptr->client_ptr != client_ptr)
241 continue;
244 #if defined(LOG_PORT_LOOKUP)
245 if (port_ptr->link)
247 uuid_unparse(port_ptr->link_uuid_override, uuid2_str);
248 log_info("comparing link uuid %s with %s", uuid2_str, uuid1_str);
250 #endif
252 if (use_link_override_uuids && port_ptr->link && uuid_compare(port_ptr->link_uuid_override, uuid) == 0)
254 #if defined(LOG_PORT_LOOKUP)
255 log_info("found link port %p of client '%s'", port_ptr->port, port_ptr->client_ptr->name);
256 #endif
257 return port_ptr;
260 ladish_port_get_uuid(port_ptr->port, current_uuid);
261 #if defined(LOG_PORT_LOOKUP)
262 uuid_unparse(current_uuid, uuid2_str);
263 log_info("comparing port uuid %s with %s", uuid2_str, uuid1_str);
264 #endif
265 if (uuid_compare(current_uuid, uuid) == 0)
267 #if defined(LOG_PORT_LOOKUP)
268 log_info("found port %p of client '%s'", port_ptr->port, port_ptr->client_ptr->name);
269 #endif
270 return port_ptr;
274 return NULL;
277 static struct ladish_graph_connection * ladish_graph_find_connection_by_id(struct ladish_graph * graph_ptr, uint64_t connection_id)
279 struct list_head * node_ptr;
280 struct ladish_graph_connection * connection_ptr;
282 list_for_each(node_ptr, &graph_ptr->connections)
284 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
285 if (connection_ptr->id == connection_id)
287 return connection_ptr;
291 return NULL;
294 static
295 struct ladish_graph_connection *
296 ladish_graph_find_connection_by_ports(
297 struct ladish_graph * graph_ptr,
298 struct ladish_graph_port * port1_ptr,
299 struct ladish_graph_port * port2_ptr)
301 struct list_head * node_ptr;
302 struct ladish_graph_connection * connection_ptr;
304 list_for_each(node_ptr, &graph_ptr->connections)
306 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
307 if ((connection_ptr->port1_ptr == port1_ptr && connection_ptr->port2_ptr == port2_ptr) ||
308 (connection_ptr->port1_ptr == port2_ptr && connection_ptr->port2_ptr == port1_ptr))
310 return connection_ptr;
314 return NULL;
317 #define graph_ptr ((struct ladish_graph *)call_ptr->iface_context)
319 static void get_all_ports(struct dbus_method_call * call_ptr)
321 DBusMessageIter iter, sub_iter;
323 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
324 if (call_ptr->reply == NULL)
326 goto fail;
329 dbus_message_iter_init_append(call_ptr->reply, &iter);
331 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
333 goto fail_unref;
336 if (!dbus_message_iter_close_container(&iter, &sub_iter))
338 goto fail_unref;
341 return;
343 fail_unref:
344 dbus_message_unref(call_ptr->reply);
345 call_ptr->reply = NULL;
347 fail:
348 log_error("Ran out of memory trying to construct method return");
351 static void get_graph(struct dbus_method_call * call_ptr)
353 dbus_uint64_t known_version;
354 dbus_uint64_t current_version;
355 DBusMessageIter iter;
356 DBusMessageIter clients_array_iter;
357 DBusMessageIter connections_array_iter;
358 DBusMessageIter client_struct_iter;
359 struct list_head * client_node_ptr;
360 struct ladish_graph_client * client_ptr;
361 DBusMessageIter ports_array_iter;
362 struct list_head * port_node_ptr;
363 struct ladish_graph_port * port_ptr;
364 DBusMessageIter port_struct_iter;
365 struct list_head * connection_node_ptr;
366 struct ladish_graph_connection * connection_ptr;
367 DBusMessageIter connection_struct_iter;
369 //log_info("get_graph() called");
371 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &known_version, DBUS_TYPE_INVALID))
373 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
374 dbus_error_free(&g_dbus_error);
375 return;
378 //log_info("Getting graph, known version is %" PRIu64, known_version);
380 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
381 if (call_ptr->reply == NULL)
383 log_error("Ran out of memory trying to construct method return");
384 goto exit;
387 dbus_message_iter_init_append(call_ptr->reply, &iter);
389 current_version = graph_ptr->graph_version;
390 if (known_version > current_version)
392 lash_dbus_error(
393 call_ptr,
394 LASH_DBUS_ERROR_INVALID_ARGS,
395 "known graph version %" PRIu64 " is newer than actual version %" PRIu64,
396 known_version,
397 current_version);
398 goto exit;
401 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &current_version))
403 goto nomem;
406 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
408 goto nomem;
411 if (known_version < current_version)
413 list_for_each(client_node_ptr, &graph_ptr->clients)
415 client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
417 if (client_ptr->hidden)
419 continue;
422 if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
424 goto nomem_close_clients_array;
427 if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
429 goto nomem_close_client_struct;
432 log_info("client '%s' (%llu)", client_ptr->name, (unsigned long long)client_ptr->id);
433 if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name))
435 goto nomem_close_client_struct;
438 if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
440 goto nomem_close_client_struct;
443 list_for_each(port_node_ptr, &client_ptr->ports)
445 port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
447 if (port_ptr->hidden)
449 continue;
452 if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
454 goto nomem_close_ports_array;
457 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
459 goto nomem_close_port_struct;
462 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
464 goto nomem_close_port_struct;
467 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
469 goto nomem_close_port_struct;
472 if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
474 goto nomem_close_port_struct;
477 if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
479 goto nomem_close_ports_array;
483 if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
485 goto nomem_close_client_struct;
488 if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
490 goto nomem_close_clients_array;
495 if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
497 goto nomem;
500 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
502 goto nomem;
505 if (known_version < current_version)
507 list_for_each(connection_node_ptr, &graph_ptr->connections)
509 connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
511 if (connection_ptr->hidden)
513 continue;
516 if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
518 goto nomem_close_connections_array;
521 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->client_ptr->id))
523 goto nomem_close_connection_struct;
526 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->client_ptr->name))
528 goto nomem_close_connection_struct;
531 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->id))
533 goto nomem_close_connection_struct;
536 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->name))
538 goto nomem_close_connection_struct;
541 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->client_ptr->id))
543 goto nomem_close_connection_struct;
546 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->client_ptr->name))
548 goto nomem_close_connection_struct;
551 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->id))
553 goto nomem_close_connection_struct;
556 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->name))
558 goto nomem_close_connection_struct;
561 if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
563 goto nomem_close_connection_struct;
566 if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
568 goto nomem_close_connections_array;
573 if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
575 goto nomem;
578 return;
580 nomem_close_connection_struct:
581 dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
583 nomem_close_connections_array:
584 dbus_message_iter_close_container(&iter, &connections_array_iter);
585 goto nomem;
587 nomem_close_port_struct:
588 dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
590 nomem_close_ports_array:
591 dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
593 nomem_close_client_struct:
594 dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
596 nomem_close_clients_array:
597 dbus_message_iter_close_container(&iter, &clients_array_iter);
599 nomem:
600 dbus_message_unref(call_ptr->reply);
601 call_ptr->reply = NULL;
602 log_error("Ran out of memory trying to construct method return");
604 exit:
605 return;
608 static void connect_ports_by_name(struct dbus_method_call * call_ptr)
610 log_info("connect_ports_by_name() called.");
611 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect by name is not implemented yet");
614 static void connect_ports_by_id(struct dbus_method_call * call_ptr)
616 dbus_uint64_t port1_id;
617 dbus_uint64_t port2_id;
618 struct ladish_graph_port * port1_ptr;
619 struct ladish_graph_port * port2_ptr;
621 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &port1_id, DBUS_TYPE_UINT64, &port2_id, DBUS_TYPE_INVALID))
623 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
624 dbus_error_free(&g_dbus_error);
625 return;
628 log_info("connect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
630 if (graph_ptr->connect_handler == NULL)
632 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");
633 return;
636 port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
637 if (port1_ptr == NULL)
639 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port1_id);
640 return;
643 port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
644 if (port2_ptr == NULL)
646 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port2_id);
647 return;
650 log_info("connecting '%s':'%s' to '%s':'%s'", port1_ptr->client_ptr->name, port1_ptr->name, port2_ptr->client_ptr->name, port2_ptr->name);
652 if (graph_ptr->connect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, port1_ptr->port, port2_ptr->port))
654 method_return_new_void(call_ptr);
656 else
658 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect failed");
662 static void disconnect_ports(struct dbus_method_call * call_ptr, struct ladish_graph_connection * connection_ptr)
664 log_info(
665 "disconnecting '%s':'%s' from '%s':'%s'",
666 connection_ptr->port1_ptr->client_ptr->name,
667 connection_ptr->port1_ptr->name,
668 connection_ptr->port2_ptr->client_ptr->name,
669 connection_ptr->port2_ptr->name);
671 connection_ptr->changing = true;
672 if (graph_ptr->disconnect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, connection_ptr->id))
674 method_return_new_void(call_ptr);
676 else
678 connection_ptr->changing = false;
679 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect failed");
683 static void disconnect_ports_by_name(struct dbus_method_call * call_ptr)
685 log_info("disconnect_ports_by_name() called.");
686 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect by name is not implemented yet");
689 static void disconnect_ports_by_id(struct dbus_method_call * call_ptr)
691 dbus_uint64_t port1_id;
692 dbus_uint64_t port2_id;
693 struct ladish_graph_port * port1_ptr;
694 struct ladish_graph_port * port2_ptr;
695 struct ladish_graph_connection * connection_ptr;
697 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &port1_id, DBUS_TYPE_UINT64, &port2_id, DBUS_TYPE_INVALID))
699 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
700 dbus_error_free(&g_dbus_error);
701 return;
704 log_info("disconnect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
706 if (graph_ptr->disconnect_handler == NULL)
708 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");
709 return;
712 port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
713 if (port1_ptr == NULL)
715 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port1_id);
716 return;
719 port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
720 if (port2_ptr == NULL)
722 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port2_id);
723 return;
726 connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
727 if (connection_ptr == NULL)
729 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect not connected ports %"PRIu64" and %"PRIu64, port1_id, port2_id);
730 return;
733 disconnect_ports(call_ptr, connection_ptr);
736 static void disconnect_ports_by_connection_id(struct dbus_method_call * call_ptr)
738 dbus_uint64_t connection_id;
739 struct ladish_graph_connection * connection_ptr;
741 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &connection_id, DBUS_TYPE_INVALID))
743 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
744 dbus_error_free(&g_dbus_error);
745 return;
748 log_info("disconnect_ports_by_connection_id(%"PRIu64") called.", connection_id);
750 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
751 if (connection_ptr == NULL)
753 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot find connection with id %"PRIu64, connection_id);
754 return;
757 disconnect_ports(call_ptr, connection_ptr);
760 static void get_client_pid(struct dbus_method_call * call_ptr)
762 int64_t pid = 0;
763 method_return_new_single(call_ptr, DBUS_TYPE_INT64, &pid);
766 #undef graph_ptr
768 bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * opath)
770 struct ladish_graph * graph_ptr;
772 graph_ptr = malloc(sizeof(struct ladish_graph));
773 if (graph_ptr == NULL)
775 log_error("malloc() failed to allocate struct graph_implementator");
776 return false;
779 if (opath != NULL)
781 graph_ptr->opath = strdup(opath);
782 if (graph_ptr->opath == NULL)
784 log_error("strdup() failed for graph opath");
785 free(graph_ptr);
786 return false;
789 else
791 graph_ptr->opath = NULL;
794 if (!ladish_dict_create(&graph_ptr->dict))
796 log_error("ladish_dict_create() failed for graph");
797 if (graph_ptr->opath != NULL)
799 free(graph_ptr->opath);
801 free(graph_ptr);
802 return false;
805 INIT_LIST_HEAD(&graph_ptr->clients);
806 INIT_LIST_HEAD(&graph_ptr->ports);
807 INIT_LIST_HEAD(&graph_ptr->connections);
809 graph_ptr->graph_version = 1;
810 graph_ptr->next_client_id = 1;
811 graph_ptr->next_port_id = 1;
812 graph_ptr->next_connection_id = 1;
814 graph_ptr->context = NULL;
815 graph_ptr->connect_handler = NULL;
816 graph_ptr->disconnect_handler = NULL;
818 graph_ptr->persist = true;
820 *graph_handle_ptr = (ladish_graph_handle)graph_ptr;
821 return true;
824 static
825 struct ladish_graph_client *
826 ladish_graph_find_client(
827 struct ladish_graph * graph_ptr,
828 ladish_client_handle client)
830 struct list_head * node_ptr;
831 struct ladish_graph_client * client_ptr;
833 list_for_each(node_ptr, &graph_ptr->clients)
835 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
836 if (client_ptr->client == client)
838 return client_ptr;
842 return NULL;
845 static
846 struct ladish_graph_port *
847 ladish_graph_find_port(
848 struct ladish_graph * graph_ptr,
849 ladish_port_handle port)
851 struct list_head * node_ptr;
852 struct ladish_graph_port * port_ptr;
854 //log_info("searching port %p", port);
856 list_for_each(node_ptr, &graph_ptr->ports)
858 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
859 //log_info("checking port %s:%s, %p", port_ptr->client_ptr->name, port_ptr->name, port_ptr->port);
860 if (port_ptr->port == port)
862 return port_ptr;
866 return NULL;
869 static
870 struct ladish_graph_port *
871 ladish_graph_find_port_by_jack_id_internal(
872 struct ladish_graph * graph_ptr,
873 uint64_t port_id,
874 bool room,
875 bool studio)
877 struct list_head * node_ptr;
878 struct ladish_graph_port * port_ptr;
880 ASSERT(room || studio);
882 list_for_each(node_ptr, &graph_ptr->ports)
884 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
885 //log_info("checking jack port id of port %s:%s, %p", port_ptr->client_ptr->name, port_ptr->name, port_ptr->port);
886 if ((studio && ladish_port_get_jack_id(port_ptr->port) == port_id) ||
887 (room && port_ptr->link && ladish_port_get_jack_id_room(port_ptr->port) == port_id))
889 //log_info("found");
890 return port_ptr;
894 return NULL;
897 #if 0
898 static
899 struct ladish_graph_port *
900 ladish_graph_find_client_port(
901 struct ladish_graph * graph_ptr,
902 struct ladish_graph_client * client_ptr,
903 ladish_port_handle port)
905 struct list_head * node_ptr;
906 struct ladish_graph_port * port_ptr;
908 list_for_each(node_ptr, &client_ptr->ports)
910 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
911 if (port_ptr->port == port)
913 return port_ptr;
917 return NULL;
919 #endif
921 static void ladish_graph_hide_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
923 ASSERT(!connection_ptr->hidden);
924 connection_ptr->hidden = true;
925 graph_ptr->graph_version++;
927 if (graph_ptr->opath != NULL)
929 ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
933 static void ladish_graph_show_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
935 if (port_ptr->client_ptr->hidden)
937 port_ptr->client_ptr->hidden = false;
938 graph_ptr->graph_version++;
939 if (graph_ptr->opath != NULL)
941 ladish_graph_emit_client_appeared(graph_ptr, port_ptr->client_ptr);
945 ASSERT(port_ptr->hidden);
946 port_ptr->hidden = false;
947 graph_ptr->graph_version++;
948 if (graph_ptr->opath != NULL)
950 ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
951 ladish_try_connect_hidden_connections((ladish_graph_handle)graph_ptr);
955 static void ladish_graph_hide_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
957 ASSERT(!port_ptr->hidden);
958 port_ptr->hidden = true;
959 graph_ptr->graph_version++;
961 if (graph_ptr->opath != NULL)
963 ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
967 static void ladish_graph_hide_client_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
969 ASSERT(!client_ptr->hidden);
970 client_ptr->hidden = true;
971 graph_ptr->graph_version++;
973 if (graph_ptr->opath != NULL)
975 ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
979 static void ladish_hide_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
981 struct list_head * node_ptr;
982 struct ladish_graph_connection * connection_ptr;
984 log_info("hidding connections of port %"PRIu64, port_ptr->id);
986 ASSERT(graph_ptr->opath != NULL);
988 list_for_each(node_ptr, &graph_ptr->connections)
990 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
991 if (!connection_ptr->hidden && (connection_ptr->port1_ptr == port_ptr || connection_ptr->port2_ptr == port_ptr))
993 log_info("hidding connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
994 ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
999 static void ladish_graph_remove_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
1001 list_del(&connection_ptr->siblings);
1002 graph_ptr->graph_version++;
1004 if (!connection_ptr->hidden && graph_ptr->opath != NULL)
1006 ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
1009 ladish_dict_destroy(connection_ptr->dict);
1010 free(connection_ptr);
1013 static void ladish_graph_remove_port_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1015 struct list_head * node_ptr;
1016 struct list_head * temp_node_ptr;
1017 struct ladish_graph_connection * connection_ptr;
1019 list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
1021 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
1022 if (connection_ptr->port1_ptr == port_ptr || connection_ptr->port2_ptr == port_ptr)
1024 log_info("removing connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
1025 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1030 static
1031 void
1032 ladish_graph_remove_port_internal(
1033 struct ladish_graph * graph_ptr,
1034 struct ladish_graph_client * client_ptr,
1035 struct ladish_graph_port * port_ptr)
1037 ladish_graph_remove_port_connections(graph_ptr, port_ptr);
1039 ladish_port_del_ref(port_ptr->port);
1041 list_del(&port_ptr->siblings_client);
1042 list_del(&port_ptr->siblings_graph);
1044 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");
1045 if (graph_ptr->opath != NULL && !port_ptr->hidden)
1047 ASSERT(port_ptr->client_ptr == client_ptr);
1048 ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
1051 free(port_ptr->name);
1052 free(port_ptr);
1055 static
1056 void
1057 ladish_graph_remove_client_internal(
1058 struct ladish_graph * graph_ptr,
1059 struct ladish_graph_client * client_ptr,
1060 bool destroy_client,
1061 ladish_graph_simple_port_callback port_callback)
1063 struct ladish_graph_port * port_ptr;
1065 while (!list_empty(&client_ptr->ports))
1067 port_ptr = list_entry(client_ptr->ports.next, struct ladish_graph_port, siblings_client);
1068 if (port_callback != NULL)
1070 port_callback(port_ptr->port);
1072 ladish_graph_remove_port_internal(graph_ptr, client_ptr, port_ptr);
1075 graph_ptr->graph_version++;
1076 list_del(&client_ptr->siblings);
1077 log_info("removing client '%s' (%"PRIu64") from graph %s", client_ptr->name, client_ptr->id, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1078 if (graph_ptr->opath != NULL && !client_ptr->hidden)
1080 ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1083 free(client_ptr->name);
1085 if (destroy_client)
1087 ladish_client_destroy(client_ptr->client);
1090 free(client_ptr);
1093 bool ladish_graph_client_looks_empty_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
1095 struct list_head * node_ptr;
1096 struct ladish_graph_port * port_ptr;
1098 list_for_each(node_ptr, &client_ptr->ports)
1100 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1101 if (!port_ptr->hidden)
1103 //log_info("port '%s' is visible, client '%s' does not look empty", port_ptr->name, client_ptr->name);
1104 return false;
1106 else
1108 //log_info("port '%s' is invisible", port_ptr->name);
1112 //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1113 return true;
1116 #define graph_ptr ((struct ladish_graph *)graph_handle)
1118 void ladish_graph_destroy(ladish_graph_handle graph_handle)
1120 ladish_graph_clear(graph_handle, NULL);
1121 ladish_dict_destroy(graph_ptr->dict);
1122 if (graph_ptr->opath != NULL)
1124 free(graph_ptr->opath);
1126 free(graph_ptr);
1129 const char * ladish_graph_get_opath(ladish_graph_handle graph_handle)
1131 return graph_ptr->opath;
1134 const char * ladish_graph_get_description(ladish_graph_handle graph_handle)
1136 return graph_ptr->opath != NULL ? graph_ptr->opath : "JACK";
1139 void
1140 ladish_graph_set_connection_handlers(
1141 ladish_graph_handle graph_handle,
1142 void * graph_context,
1143 ladish_graph_connect_request_handler connect_handler,
1144 ladish_graph_disconnect_request_handler disconnect_handler)
1146 log_info("setting connection handlers for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1147 graph_ptr->context = graph_context;
1148 graph_ptr->connect_handler = connect_handler;
1149 graph_ptr->disconnect_handler = disconnect_handler;
1152 void ladish_graph_clear(ladish_graph_handle graph_handle, ladish_graph_simple_port_callback port_callback)
1154 struct ladish_graph_client * client_ptr;
1155 struct ladish_graph_connection * connection_ptr;
1157 log_info("ladish_graph_clear() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1159 while (!list_empty(&graph_ptr->connections))
1161 connection_ptr = list_entry(graph_ptr->connections.next, struct ladish_graph_connection, siblings);
1162 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1165 while (!list_empty(&graph_ptr->clients))
1167 client_ptr = list_entry(graph_ptr->clients.next, struct ladish_graph_client, siblings);
1168 ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, port_callback);
1172 void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle)
1174 return graph_handle;
1177 ladish_dict_handle ladish_graph_get_dict(ladish_graph_handle graph_handle)
1179 return graph_ptr->dict;
1182 void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id)
1184 struct ladish_graph_connection * connection_ptr;
1186 log_info("ladish_graph_show_connection() called.");
1188 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1189 if (connection_ptr == NULL)
1191 ASSERT_NO_PASS;
1192 return;
1195 ASSERT(graph_ptr->opath != NULL);
1196 ASSERT(connection_ptr->hidden);
1197 connection_ptr->hidden = false;
1198 connection_ptr->changing = false;
1199 graph_ptr->graph_version++;
1201 ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1204 void ladish_graph_show_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1206 struct ladish_graph_port * port_ptr;
1208 //log_info("ladish_graph_show_port() called.");
1210 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1211 if (port_ptr == NULL)
1213 ASSERT_NO_PASS;
1214 return;
1217 //log_info("port '%s' is %s", port_ptr->name, port_ptr->hidden ? "invisible" : "visible");
1219 ladish_graph_show_port_internal(graph_ptr, port_ptr);
1222 void ladish_graph_hide_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1224 struct ladish_graph_port * port_ptr;
1226 log_info("ladish_graph_hide_port() called.");
1228 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1229 if (port_ptr == NULL)
1231 ASSERT_NO_PASS;
1232 return;
1235 log_info("Hidding port %"PRIu64, port_ptr->id);
1237 ASSERT(!port_ptr->hidden);
1239 if (graph_ptr->opath != NULL)
1241 ladish_hide_connections(graph_ptr, port_ptr);
1244 ladish_graph_hide_port_internal(graph_ptr, port_ptr);
1247 void ladish_graph_hide_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1249 struct ladish_graph_client * client_ptr;
1251 log_info("ladish_graph_hide_client() called.");
1253 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1254 if (client_ptr == NULL)
1256 ASSERT_NO_PASS;
1257 return;
1260 ladish_graph_hide_client_internal(graph_ptr, client_ptr);
1263 void ladish_graph_show_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1265 struct ladish_graph_client * client_ptr;
1267 log_info("ladish_graph_show_client() called.");
1269 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1270 if (client_ptr == NULL)
1272 ASSERT_NO_PASS;
1273 return;
1276 ASSERT(client_ptr->hidden);
1277 client_ptr->hidden = false;
1278 graph_ptr->graph_version++;
1280 if (graph_ptr->opath != NULL)
1282 ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1286 void ladish_graph_adjust_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle, uint32_t type, uint32_t flags)
1288 struct ladish_graph_port * port_ptr;
1290 //log_info("ladish_graph_adjust_port() called.");
1292 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1293 if (port_ptr == NULL)
1295 ASSERT_NO_PASS;
1296 return;
1299 port_ptr->type = type;
1300 port_ptr->flags = flags;
1303 bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name, bool hidden)
1305 struct ladish_graph_client * client_ptr;
1307 log_info("adding client '%s' (%p) to graph %s", name, client_handle, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1309 client_ptr = malloc(sizeof(struct ladish_graph_client));
1310 if (client_ptr == NULL)
1312 log_error("malloc() failed for struct ladish_graph_client");
1313 return false;
1316 client_ptr->name = strdup(name);
1317 if (client_ptr->name == NULL)
1319 log_error("strdup() failed for graph client name");
1320 free(client_ptr);
1321 return false;
1324 client_ptr->id = graph_ptr->next_client_id++;
1325 client_ptr->client = client_handle;
1326 client_ptr->hidden = hidden;
1327 graph_ptr->graph_version++;
1329 INIT_LIST_HEAD(&client_ptr->ports);
1331 list_add_tail(&client_ptr->siblings, &graph_ptr->clients);
1333 if (!hidden && graph_ptr->opath != NULL)
1335 ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1338 return true;
1341 void
1342 ladish_graph_remove_client(
1343 ladish_graph_handle graph_handle,
1344 ladish_client_handle client_handle)
1346 struct ladish_graph_client * client_ptr;
1348 log_info("ladish_graph_remove_client() called.");
1350 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1351 if (client_ptr != NULL)
1353 ladish_graph_remove_client_internal(graph_ptr, client_ptr, false, NULL);
1355 else
1357 ASSERT_NO_PASS;
1361 bool
1362 ladish_graph_add_port(
1363 ladish_graph_handle graph_handle,
1364 ladish_client_handle client_handle,
1365 ladish_port_handle port_handle,
1366 const char * name,
1367 uint32_t type,
1368 uint32_t flags,
1369 bool hidden)
1371 struct ladish_graph_client * client_ptr;
1372 struct ladish_graph_port * port_ptr;
1374 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1375 if (client_ptr == NULL)
1377 log_error("cannot find client to add port to. graph is %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1378 ASSERT_NO_PASS;
1379 return false;
1382 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");
1384 port_ptr = malloc(sizeof(struct ladish_graph_port));
1385 if (port_ptr == NULL)
1387 log_error("malloc() failed for struct ladish_graph_port");
1388 return false;
1391 port_ptr->name = strdup(name);
1392 if (port_ptr->name == NULL)
1394 log_error("strdup() failed for graph port name");
1395 free(port_ptr);
1396 return false;
1399 port_ptr->type = type;
1400 port_ptr->flags = flags;
1402 port_ptr->id = graph_ptr->next_port_id++;
1403 port_ptr->port = port_handle;
1404 ladish_port_add_ref(port_ptr->port);
1405 port_ptr->hidden = true;
1407 port_ptr->link = ladish_port_is_link(port_handle);
1408 if (port_ptr->link)
1410 uuid_generate(port_ptr->link_uuid_override);
1413 port_ptr->client_ptr = client_ptr;
1414 list_add_tail(&port_ptr->siblings_client, &client_ptr->ports);
1415 list_add_tail(&port_ptr->siblings_graph, &graph_ptr->ports);
1417 if (!hidden)
1419 ladish_graph_show_port_internal(graph_ptr, port_ptr);
1422 return true;
1425 uint64_t
1426 ladish_graph_add_connection(
1427 ladish_graph_handle graph_handle,
1428 ladish_port_handle port1_handle,
1429 ladish_port_handle port2_handle,
1430 bool hidden)
1432 struct ladish_graph_port * port1_ptr;
1433 struct ladish_graph_port * port2_ptr;
1434 struct ladish_graph_connection * connection_ptr;
1436 port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1437 ASSERT(port1_ptr != NULL);
1438 port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1439 ASSERT(port2_ptr != NULL);
1441 connection_ptr = malloc(sizeof(struct ladish_graph_connection));
1442 if (connection_ptr == NULL)
1444 log_error("malloc() failed for struct ladish_graph_connection");
1445 return 0;
1448 if (!ladish_dict_create(&connection_ptr->dict))
1450 log_error("ladish_dict_create() failed for connection");
1451 free(connection_ptr);
1452 return 0;
1455 connection_ptr->id = graph_ptr->next_connection_id++;
1456 connection_ptr->port1_ptr = port1_ptr;
1457 connection_ptr->port2_ptr = port2_ptr;
1458 connection_ptr->hidden = hidden;
1459 connection_ptr->changing = false;
1460 graph_ptr->graph_version++;
1462 list_add_tail(&connection_ptr->siblings, &graph_ptr->connections);
1464 /* log_info( */
1465 /* "new connection %"PRIu64" between '%s':'%s' and '%s':'%s'", */
1466 /* connection_ptr->id, */
1467 /* port1_ptr->client_ptr->name, */
1468 /* port1_ptr->name, */
1469 /* port2_ptr->client_ptr->name, */
1470 /* port2_ptr->name); */
1472 if (!hidden && graph_ptr->opath != NULL)
1474 ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1477 return connection_ptr->id;
1480 void
1481 ladish_graph_remove_connection(
1482 ladish_graph_handle graph_handle,
1483 uint64_t connection_id,
1484 bool force)
1486 struct ladish_graph_connection * connection_ptr;
1488 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1489 if (connection_ptr == NULL)
1491 ASSERT_NO_PASS;
1492 return;
1495 if (force || connection_ptr->changing || !graph_ptr->persist)
1497 /* log_info( */
1498 /* "removing connection '%s':'%s' - '%s':'%s'", */
1499 /* connection_ptr->port1_ptr->client_ptr->name, */
1500 /* connection_ptr->port1_ptr->name, */
1501 /* connection_ptr->port2_ptr->client_ptr->name, */
1502 /* connection_ptr->port2_ptr->name); */
1504 ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1506 else
1508 /* log_info( */
1509 /* "hiding connection '%s':'%s' - '%s':'%s'", */
1510 /* connection_ptr->port1_ptr->client_ptr->name, */
1511 /* connection_ptr->port1_ptr->name, */
1512 /* connection_ptr->port2_ptr->client_ptr->name, */
1513 /* connection_ptr->port2_ptr->name); */
1515 ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
1519 bool
1520 ladish_graph_get_connection_ports(
1521 ladish_graph_handle graph_handle,
1522 uint64_t connection_id,
1523 ladish_port_handle * port1_handle_ptr,
1524 ladish_port_handle * port2_handle_ptr)
1526 struct ladish_graph_connection * connection_ptr;
1528 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1529 if (connection_ptr == NULL)
1531 return false;
1534 *port1_handle_ptr = connection_ptr->port1_ptr->port;
1535 *port2_handle_ptr = connection_ptr->port2_ptr->port;
1537 return true;
1540 ladish_dict_handle ladish_graph_get_connection_dict(ladish_graph_handle graph_handle, uint64_t connection_id)
1542 struct ladish_graph_connection * connection_ptr;
1544 connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1545 if (connection_ptr == NULL)
1547 return NULL;
1550 return connection_ptr->dict;
1553 bool
1554 ladish_graph_find_connection(
1555 ladish_graph_handle graph_handle,
1556 ladish_port_handle port1_handle,
1557 ladish_port_handle port2_handle,
1558 uint64_t * connection_id_ptr)
1560 struct ladish_graph_port * port1_ptr;
1561 struct ladish_graph_port * port2_ptr;
1562 struct ladish_graph_connection * connection_ptr;
1564 port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1565 if (port1_ptr == NULL)
1567 return false;
1570 port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1571 if (port1_ptr == NULL)
1573 return false;
1576 connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
1577 if (connection_ptr == NULL)
1579 return false;
1582 *connection_id_ptr = connection_ptr->id;
1584 return true;
1587 ladish_client_handle ladish_graph_find_client_by_name(ladish_graph_handle graph_handle, const char * name, bool appless)
1589 struct list_head * node_ptr;
1590 struct ladish_graph_client * client_ptr;
1592 list_for_each(node_ptr, &graph_ptr->clients)
1594 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1595 if (strcmp(client_ptr->name, name) == 0 &&
1596 (!appless || !ladish_client_has_app(client_ptr->client))) /* if appless is true, then an appless client is being searched */
1598 return client_ptr->client;
1602 return NULL;
1605 ladish_client_handle ladish_graph_find_client_by_app(ladish_graph_handle graph_handle, const uuid_t app_uuid)
1607 struct list_head * node_ptr;
1608 struct ladish_graph_client * client_ptr;
1609 uuid_t current_uuid;
1611 list_for_each(node_ptr, &graph_ptr->clients)
1613 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1614 ladish_client_get_app(client_ptr->client, current_uuid);
1615 if (uuid_compare(current_uuid, app_uuid) == 0)
1617 return client_ptr->client;
1621 return NULL;
1624 ladish_port_handle ladish_graph_find_port_by_name(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name)
1626 struct ladish_graph_client * client_ptr;
1627 struct list_head * node_ptr;
1628 struct ladish_graph_port * port_ptr;
1630 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1631 if (client_ptr != NULL)
1633 list_for_each(node_ptr, &client_ptr->ports)
1635 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1636 if (strcmp(port_ptr->name, name) == 0)
1638 return port_ptr->port;
1642 else
1644 ASSERT_NO_PASS;
1647 return NULL;
1650 ladish_client_handle ladish_graph_find_client_by_uuid(ladish_graph_handle graph_handle, const uuid_t uuid)
1652 struct list_head * node_ptr;
1653 struct ladish_graph_client * client_ptr;
1654 uuid_t current_uuid;
1656 list_for_each(node_ptr, &graph_ptr->clients)
1658 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1659 ladish_client_get_uuid(client_ptr->client, current_uuid);
1660 if (uuid_compare(current_uuid, uuid) == 0)
1662 return client_ptr->client;
1666 return NULL;
1669 ladish_port_handle ladish_graph_find_port_by_uuid(ladish_graph_handle graph_handle, const uuid_t uuid, bool use_link_override_uuids)
1671 struct ladish_graph_port * port_ptr;
1673 port_ptr = ladish_graph_find_port_by_uuid_internal(graph_ptr, NULL, uuid, use_link_override_uuids);
1674 if (port_ptr != NULL)
1676 return port_ptr->port;
1679 return NULL;
1682 ladish_client_handle ladish_graph_get_port_client(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1684 struct ladish_graph_port * port_ptr;
1686 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1687 if (port_ptr == NULL)
1689 return NULL;
1692 return port_ptr->client_ptr->client;
1695 bool ladish_graph_is_port_present(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1697 return ladish_graph_find_port(graph_ptr, port_handle) != NULL;
1700 ladish_client_handle ladish_graph_find_client_by_id(ladish_graph_handle graph_handle, uint64_t client_id)
1702 struct list_head * node_ptr;
1703 struct ladish_graph_client * client_ptr;
1705 list_for_each(node_ptr, &graph_ptr->clients)
1707 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1708 if (client_ptr->id == client_id)
1710 return client_ptr->client;
1714 return NULL;
1717 ladish_port_handle ladish_graph_find_port_by_id(ladish_graph_handle graph_handle, uint64_t port_id)
1719 struct ladish_graph_port * port_ptr;
1721 port_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port_id);
1722 if (port_ptr == NULL)
1724 return NULL;
1727 return port_ptr->port;
1730 ladish_client_handle ladish_graph_find_client_by_jack_id(ladish_graph_handle graph_handle, uint64_t client_id)
1732 struct list_head * node_ptr;
1733 struct ladish_graph_client * client_ptr;
1735 list_for_each(node_ptr, &graph_ptr->clients)
1737 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1738 if (ladish_client_get_jack_id(client_ptr->client) == client_id)
1740 return client_ptr->client;
1744 return NULL;
1747 ladish_port_handle ladish_graph_find_port_by_jack_id(ladish_graph_handle graph_handle, uint64_t port_id, bool room, bool studio)
1749 struct ladish_graph_port * port_ptr;
1751 port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, port_id, room, studio);
1752 if (port_ptr == NULL)
1754 return NULL;
1757 return port_ptr->port;
1760 ladish_client_handle
1761 ladish_graph_remove_port(
1762 ladish_graph_handle graph_handle,
1763 ladish_port_handle port)
1765 struct ladish_graph_port * port_ptr;
1766 ladish_client_handle client;
1768 port_ptr = ladish_graph_find_port(graph_ptr, port);
1769 if (port_ptr == NULL)
1771 return NULL;
1774 client = port_ptr->client_ptr->client;
1775 ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
1776 return client;
1779 ladish_client_handle
1780 ladish_graph_remove_port_by_jack_id(
1781 ladish_graph_handle graph_handle,
1782 uint64_t jack_port_id,
1783 bool room,
1784 bool studio)
1786 struct ladish_graph_port * port_ptr;
1787 ladish_client_handle client;
1789 port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, jack_port_id, room, studio);
1790 if (port_ptr == NULL)
1792 return NULL;
1795 client = port_ptr->client_ptr->client;
1796 ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
1797 return client;
1800 bool
1801 ladish_graph_rename_client(
1802 ladish_graph_handle graph_handle,
1803 ladish_client_handle client_handle,
1804 const char * new_client_name)
1806 char * name;
1807 struct ladish_graph_client * client_ptr;
1808 char * old_name;
1810 name = strdup(new_client_name);
1811 if (name == NULL)
1813 log_error("strdup('%s') failed.", new_client_name);
1814 return false;
1817 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1818 if (client_ptr == NULL)
1820 free(name);
1821 ASSERT_NO_PASS;
1822 return false;
1825 old_name = client_ptr->name;
1826 client_ptr->name = name;
1828 graph_ptr->graph_version++;
1830 if (!client_ptr->hidden && graph_ptr->opath != NULL)
1832 dbus_signal_emit(
1833 g_dbus_connection,
1834 graph_ptr->opath,
1835 JACKDBUS_IFACE_PATCHBAY,
1836 "ClientRenamed",
1837 "ttss",
1838 &graph_ptr->graph_version,
1839 &client_ptr->id,
1840 &old_name,
1841 &client_ptr->name);
1844 free(old_name);
1846 return true;
1849 bool
1850 ladish_graph_rename_port(
1851 ladish_graph_handle graph_handle,
1852 ladish_port_handle port_handle,
1853 const char * new_port_name)
1855 char * name;
1856 struct ladish_graph_port * port_ptr;
1857 char * old_name;
1859 name = strdup(new_port_name);
1860 if (name == NULL)
1862 log_error("strdup('%s') failed.", new_port_name);
1863 return false;
1866 port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1867 if (port_ptr == NULL)
1869 ASSERT_NO_PASS;
1870 free(name);
1871 return false;
1874 old_name = port_ptr->name;
1875 port_ptr->name = name;
1877 graph_ptr->graph_version++;
1879 if (!port_ptr->hidden && graph_ptr->opath != NULL)
1881 dbus_signal_emit(
1882 g_dbus_connection,
1883 graph_ptr->opath,
1884 JACKDBUS_IFACE_PATCHBAY,
1885 "PortRenamed",
1886 "ttstss",
1887 &graph_ptr->graph_version,
1888 &port_ptr->client_ptr->id,
1889 &port_ptr->client_ptr->name,
1890 &port_ptr->id,
1891 &old_name,
1892 &port_ptr->name);
1895 free(old_name);
1897 return true;
1900 const char * ladish_graph_get_client_name(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1902 struct ladish_graph_client * client_ptr;
1904 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1905 if (client_ptr != NULL)
1907 return client_ptr->name;
1910 ASSERT_NO_PASS;
1911 return NULL;
1914 bool ladish_graph_client_is_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1916 struct ladish_graph_client * client_ptr;
1918 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1919 if (client_ptr != NULL)
1921 return list_empty(&client_ptr->ports);
1924 ASSERT_NO_PASS;
1925 return true;
1928 bool ladish_graph_client_looks_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1930 struct ladish_graph_client * client_ptr;
1932 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1933 if (client_ptr == NULL)
1935 ASSERT_NO_PASS;
1936 return true;
1939 if (ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
1941 //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1942 return true;
1945 return false;
1948 bool ladish_graph_client_is_hidden(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1950 struct ladish_graph_client * client_ptr;
1952 client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1953 if (client_ptr != NULL)
1955 return client_ptr->hidden;
1958 ASSERT_NO_PASS;
1959 return true;
1962 void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle)
1964 struct list_head * node_ptr;
1965 struct ladish_graph_connection * connection_ptr;
1967 if (!list_empty(&graph_ptr->connections) && graph_ptr->connect_handler == NULL)
1969 ASSERT_NO_PASS;
1970 return;
1973 ASSERT(graph_ptr->opath != NULL);
1975 list_for_each(node_ptr, &graph_ptr->connections)
1977 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
1978 log_debug(
1979 "checking connection (%s, %s) '%s':'%s' (%s) to '%s':'%s' (%s)",
1980 connection_ptr->hidden ? "hidden" : "visible",
1981 connection_ptr->changing ? "changing" : "not changing",
1982 connection_ptr->port1_ptr->client_ptr->name,
1983 connection_ptr->port1_ptr->name,
1984 connection_ptr->port1_ptr->hidden ? "hidden" : "visible",
1985 connection_ptr->port2_ptr->client_ptr->name,
1986 connection_ptr->port2_ptr->name,
1987 connection_ptr->port2_ptr->hidden ? "hidden" : "visible");
1988 if (connection_ptr->hidden &&
1989 !connection_ptr->changing &&
1990 !connection_ptr->port1_ptr->hidden &&
1991 !connection_ptr->port2_ptr->hidden)
1993 log_info(
1994 "auto connecting '%s':'%s' to '%s':'%s'",
1995 connection_ptr->port1_ptr->client_ptr->name,
1996 connection_ptr->port1_ptr->name,
1997 connection_ptr->port2_ptr->client_ptr->name,
1998 connection_ptr->port2_ptr->name);
2000 connection_ptr->changing = true;
2001 if (!graph_ptr->connect_handler(graph_ptr->context, graph_handle, connection_ptr->port1_ptr->port, connection_ptr->port2_ptr->port))
2003 connection_ptr->changing = false;
2004 log_error("auto connect failed.");
2010 void ladish_graph_hide_non_virtual(ladish_graph_handle graph_handle)
2012 struct list_head * node_ptr;
2013 struct ladish_graph_connection * connection_ptr;
2014 struct ladish_graph_port * port_ptr;
2015 struct ladish_graph_client * client_ptr;
2017 log_info("hiding everything in graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2019 list_for_each(node_ptr, &graph_ptr->connections)
2021 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2022 if (!connection_ptr->hidden &&
2023 (ladish_client_get_jack_id(connection_ptr->port1_ptr->client_ptr->client) != 0 ||
2024 ladish_client_get_jack_id(connection_ptr->port2_ptr->client_ptr->client) != 0))
2026 log_debug("hidding connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
2027 ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
2031 list_for_each(node_ptr, &graph_ptr->ports)
2033 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2034 if (!port_ptr->hidden && ladish_client_get_jack_id(port_ptr->client_ptr->client) != 0)
2036 ladish_port_set_jack_id(port_ptr->port, 0);
2037 ladish_graph_hide_port_internal(graph_ptr, port_ptr);
2041 list_for_each(node_ptr, &graph_ptr->clients)
2043 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2044 if (!client_ptr->hidden && ladish_client_get_jack_id(client_ptr->client) != 0)
2046 ladish_client_set_jack_id(client_ptr->client, 0);
2047 ladish_graph_hide_client_internal(graph_ptr, client_ptr);
2052 void ladish_graph_get_port_uuid(ladish_graph_handle graph_handle, ladish_port_handle port, uuid_t uuid_ptr)
2054 struct ladish_graph_port * port_ptr;
2056 port_ptr = ladish_graph_find_port(graph_ptr, port);
2057 ASSERT(port_ptr != NULL);
2058 ASSERT(port_ptr->link);
2060 uuid_copy(uuid_ptr, port_ptr->link_uuid_override);
2063 const char * ladish_graph_get_port_name(ladish_graph_handle graph_handle, ladish_port_handle port)
2065 struct ladish_graph_port * port_ptr;
2067 port_ptr = ladish_graph_find_port(graph_ptr, port);
2068 ASSERT(port_ptr != NULL);
2070 return port_ptr->name;
2073 ladish_port_handle
2074 ladish_graph_find_client_port_by_uuid(
2075 ladish_graph_handle graph_handle,
2076 ladish_client_handle client,
2077 const uuid_t uuid,
2078 bool use_link_override_uuids)
2080 struct ladish_graph_client * client_ptr;
2081 struct ladish_graph_port * port_ptr;
2083 client_ptr = ladish_graph_find_client(graph_ptr, client);
2084 ASSERT(client_ptr != NULL);
2086 port_ptr = ladish_graph_find_port_by_uuid_internal(graph_ptr, client_ptr, uuid, use_link_override_uuids);
2087 if (port_ptr != NULL)
2089 return port_ptr->port;
2092 return NULL;
2095 void
2096 ladish_graph_set_link_port_override_uuid(
2097 ladish_graph_handle graph_handle,
2098 ladish_port_handle port,
2099 const uuid_t override_uuid)
2101 struct ladish_graph_port * port_ptr;
2103 port_ptr = ladish_graph_find_port(graph_ptr, port);
2104 ASSERT(ladish_port_is_link(port_ptr->port));
2106 uuid_copy(port_ptr->link_uuid_override, override_uuid);
2109 bool
2110 ladish_graph_iterate_nodes(
2111 ladish_graph_handle graph_handle,
2112 bool skip_hidden,
2113 void * vgraph_filter,
2114 void * callback_context,
2115 bool
2116 (* client_begin_callback)(
2117 void * context,
2118 ladish_graph_handle graph_handle,
2119 ladish_client_handle client_handle,
2120 const char * client_name,
2121 void ** client_iteration_context_ptr_ptr),
2122 bool
2123 (* port_callback)(
2124 void * context,
2125 ladish_graph_handle graph_handle,
2126 void * client_iteration_context_ptr,
2127 ladish_client_handle client_handle,
2128 const char * client_name,
2129 ladish_port_handle port_handle,
2130 const char * port_name,
2131 uint32_t port_type,
2132 uint32_t port_flags),
2133 bool
2134 (* client_end_callback)(
2135 void * context,
2136 ladish_graph_handle graph_handle,
2137 ladish_client_handle client_handle,
2138 const char * client_name,
2139 void * client_iteration_context_ptr))
2141 struct list_head * client_node_ptr;
2142 struct ladish_graph_client * client_ptr;
2143 void * client_context;
2144 struct list_head * port_node_ptr;
2145 struct ladish_graph_port * port_ptr;
2146 void * vgraph;
2148 list_for_each(client_node_ptr, &graph_ptr->clients)
2150 client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2152 if (skip_hidden && client_ptr->hidden && !ladish_client_has_app(client_ptr->client))
2154 continue;
2157 if (vgraph_filter != NULL)
2159 vgraph = ladish_client_get_vgraph(client_ptr->client);
2160 if (vgraph != vgraph_filter)
2162 continue;
2166 if (client_begin_callback != NULL)
2168 if (!client_begin_callback(callback_context, graph_handle, client_ptr->client, client_ptr->name, &client_context))
2170 return false;
2173 else
2175 client_context = NULL;
2178 if (port_callback == NULL)
2180 continue;
2183 list_for_each(port_node_ptr, &client_ptr->ports)
2185 port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2187 if (skip_hidden && port_ptr->hidden && !ladish_client_has_app(port_ptr->client_ptr->client))
2189 continue;
2192 if (!port_callback(
2193 callback_context,
2194 graph_handle,
2195 client_context,
2196 client_ptr->client,
2197 client_ptr->name,
2198 port_ptr->port,
2199 port_ptr->name,
2200 port_ptr->type,
2201 port_ptr->flags))
2203 return false;
2207 if (client_end_callback != NULL)
2209 if (!client_end_callback(callback_context, graph_handle, client_ptr->client, client_ptr->name, &client_context))
2211 return false;
2216 return true;
2219 static bool is_system_client(ladish_client_handle client)
2221 uuid_t uuid;
2222 ladish_client_get_uuid(client, uuid);
2223 return ladish_virtualizer_is_system_client(uuid);
2226 #define is_port_interesting(port_ptr) ( \
2227 ladish_client_has_app(port_ptr->client_ptr->client) || \
2228 ladish_port_is_link(port_ptr->port) || \
2229 is_system_client(port_ptr->client_ptr->client) \
2232 bool
2233 ladish_graph_iterate_connections(
2234 ladish_graph_handle graph_handle,
2235 bool skip_hidden,
2236 void * callback_context,
2237 bool (* callback)(
2238 void * context,
2239 ladish_graph_handle graph_handle,
2240 ladish_port_handle port1_handle,
2241 ladish_port_handle port2_handle,
2242 ladish_dict_handle dict))
2244 struct list_head * node_ptr;
2245 struct ladish_graph_connection * connection_ptr;
2247 list_for_each(node_ptr, &graph_ptr->connections)
2249 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2251 if (skip_hidden &&
2252 connection_ptr->hidden &&
2253 (!is_port_interesting(connection_ptr->port1_ptr) ||
2254 !is_port_interesting(connection_ptr->port2_ptr)))
2256 continue;
2259 if (!callback(callback_context, graph_handle, connection_ptr->port1_ptr->port, connection_ptr->port2_ptr->port, connection_ptr->dict))
2261 return false;
2265 return true;
2268 static
2269 bool
2270 dump_dict_entry(
2271 void * context,
2272 const char * key,
2273 const char * value)
2275 log_info("%s key '%s' with value '%s'", (const char *)context, key, value);
2276 return true;
2279 static
2280 void
2281 dump_dict(
2282 const char * indent,
2283 ladish_dict_handle dict)
2285 if (ladish_dict_is_empty(dict))
2287 return;
2290 log_info("%sdict:", indent);
2291 ladish_dict_iterate(dict, (void *)indent, dump_dict_entry);
2294 void ladish_graph_dump(ladish_graph_handle graph_handle)
2296 struct list_head * client_node_ptr;
2297 struct ladish_graph_client * client_ptr;
2298 struct list_head * port_node_ptr;
2299 struct ladish_graph_port * port_ptr;
2300 struct list_head * connection_node_ptr;
2301 struct ladish_graph_connection * connection_ptr;
2302 uuid_t uuid;
2303 char uuid_str[37];
2305 log_info("graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2306 log_info(" version %"PRIu64, graph_ptr->graph_version);
2307 log_info(" persist: %s", graph_ptr->persist ? "yes" : "no");
2308 dump_dict(" ", graph_ptr->dict);
2309 log_info(" clients:");
2310 list_for_each(client_node_ptr, &graph_ptr->clients)
2312 client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2313 log_info(" %s client '%s', id=%"PRIu64", ptr=%p%", client_ptr->hidden ? "invisible" : "visible", client_ptr->name, client_ptr->id, client_ptr->client);
2314 ladish_client_get_uuid(client_ptr->client, uuid);
2315 uuid_unparse(uuid, uuid_str);
2316 log_info(" uuid=%s", uuid_str);
2317 if (ladish_client_get_interlink(client_ptr->client, uuid))
2319 uuid_unparse(uuid, uuid_str);
2320 log_info(" interlink=%s", uuid_str);
2322 else
2324 log_info(" no interlink");
2326 dump_dict(" ", ladish_client_get_dict(client_ptr->client));
2327 log_info(" ports:");
2328 list_for_each(port_node_ptr, &client_ptr->ports)
2330 port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2332 ladish_port_get_uuid(port_ptr->port, uuid);
2333 uuid_unparse(uuid, uuid_str);
2335 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);
2336 dump_dict(" ", ladish_port_get_dict(port_ptr->port));
2339 log_info(" connections:");
2340 list_for_each(connection_node_ptr, &graph_ptr->connections)
2342 connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
2344 log_info(
2345 " %s connection '%s':'%s' - '%s':'%s'%s",
2346 connection_ptr->hidden ? "invisible" : "visible",
2347 connection_ptr->port1_ptr->client_ptr->name,
2348 connection_ptr->port1_ptr->name,
2349 connection_ptr->port2_ptr->client_ptr->name,
2350 connection_ptr->port2_ptr->name,
2351 connection_ptr->changing ? " [changing]" : "");
2352 dump_dict(" ", connection_ptr->dict);
2356 void ladish_graph_clear_persist(ladish_graph_handle graph_handle)
2358 log_info("Clearing persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2359 graph_ptr->persist = false;
2362 void ladish_graph_set_persist(ladish_graph_handle graph_handle)
2364 log_info("Setting persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2365 graph_ptr->persist = true;
2368 bool ladish_graph_is_persist(ladish_graph_handle graph_handle)
2370 return graph_ptr->persist;
2373 bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
2375 struct list_head * node_ptr;
2376 struct ladish_graph_connection * connection_ptr;
2377 struct ladish_graph_client * client_ptr;
2379 list_for_each(node_ptr, &graph_ptr->connections)
2381 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2383 if (!connection_ptr->hidden)
2385 return false;
2389 list_for_each(node_ptr, &graph_ptr->clients)
2391 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2392 if (!ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2394 return false;
2398 return true;
2401 /* Trick the world that graph objects disappear and the reapper so the new dict values are fetched */
2402 /* This is a nasty hack and should be removed once dict object can emit signals */
2403 void ladish_graph_trick_dicts(ladish_graph_handle graph_handle)
2405 struct list_head * node_ptr;
2406 struct ladish_graph_connection * connection_ptr;
2407 struct ladish_graph_client * client_ptr;
2408 struct ladish_graph_port * port_ptr;
2410 list_for_each(node_ptr, &graph_ptr->connections)
2412 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2413 if (!connection_ptr->hidden)
2415 graph_ptr->graph_version++;
2416 ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
2420 list_for_each(node_ptr, &graph_ptr->ports)
2422 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2424 if (!port_ptr->hidden)
2426 graph_ptr->graph_version++;
2427 ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
2431 list_for_each(node_ptr, &graph_ptr->clients)
2433 client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2435 if (!client_ptr->hidden)
2437 graph_ptr->graph_version++;
2438 ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
2439 graph_ptr->graph_version++;
2440 ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
2444 list_for_each(node_ptr, &graph_ptr->ports)
2446 port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2448 if (!port_ptr->hidden)
2450 graph_ptr->graph_version++;
2451 ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
2455 list_for_each(node_ptr, &graph_ptr->connections)
2457 connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2458 if (!connection_ptr->hidden)
2460 graph_ptr->graph_version++;
2461 ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
2466 #undef graph_ptr
2467 #define graph_ptr ((struct ladish_graph *)context)
2469 static
2470 bool
2471 ladish_graph_copy_client_begin_callback(
2472 void * context,
2473 ladish_graph_handle graph_handle,
2474 ladish_client_handle client_handle,
2475 const char * client_name,
2476 void ** client_iteration_context_ptr_ptr)
2478 ladish_client_handle copy;
2480 if (!ladish_client_create_copy(client_handle, &copy))
2482 return false;
2485 if (!ladish_graph_add_client(context, copy, client_name, false))
2487 ladish_client_destroy(copy);
2488 return false;
2491 *client_iteration_context_ptr_ptr = copy;
2493 return true;
2496 static
2497 bool
2498 ladish_graph_copy_port_callback(
2499 void * context,
2500 ladish_graph_handle graph_handle,
2501 void * client_iteration_context_ptr,
2502 ladish_client_handle client_handle,
2503 const char * client_name,
2504 ladish_port_handle port_handle,
2505 const char * port_name,
2506 uint32_t port_type,
2507 uint32_t port_flags)
2509 ladish_port_handle copy;
2511 if (!ladish_port_create_copy(port_handle, &copy))
2513 return false;
2516 if (!ladish_graph_add_port(context, client_iteration_context_ptr, copy, port_name, port_type, port_flags, true))
2518 ladish_port_destroy(copy);
2519 return false;
2522 return true;
2525 #undef graph_ptr
2527 bool ladish_graph_copy(ladish_graph_handle src, ladish_graph_handle dest, bool skip_hidden)
2529 return ladish_graph_iterate_nodes(
2530 src,
2531 skip_hidden,
2532 NULL,
2533 dest,
2534 ladish_graph_copy_client_begin_callback,
2535 ladish_graph_copy_port_callback,
2536 NULL);
2539 METHOD_ARGS_BEGIN(GetAllPorts, "Get all ports")
2540 METHOD_ARG_DESCRIBE_IN("ports_list", "as", "List of all ports")
2541 METHOD_ARGS_END
2543 METHOD_ARGS_BEGIN(GetGraph, "Get whole graph")
2544 METHOD_ARG_DESCRIBE_IN("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Known graph version")
2545 METHOD_ARG_DESCRIBE_OUT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Current graph version")
2546 METHOD_ARG_DESCRIBE_OUT("clients_and_ports", "a(tsa(tsuu))", "Clients and their ports")
2547 METHOD_ARG_DESCRIBE_OUT("connections", "a(tstststst)", "Connections array")
2548 METHOD_ARGS_END
2550 METHOD_ARGS_BEGIN(ConnectPortsByName, "Connect ports")
2551 METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2552 METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2553 METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2554 METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2555 METHOD_ARGS_END
2557 METHOD_ARGS_BEGIN(ConnectPortsByID, "Connect ports")
2558 METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2559 METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2560 METHOD_ARGS_END
2562 METHOD_ARGS_BEGIN(DisconnectPortsByName, "Disconnect ports")
2563 METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2564 METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2565 METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2566 METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2567 METHOD_ARGS_END
2569 METHOD_ARGS_BEGIN(DisconnectPortsByID, "Disconnect ports")
2570 METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2571 METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2572 METHOD_ARGS_END
2574 METHOD_ARGS_BEGIN(DisconnectPortsByConnectionID, "Disconnect ports")
2575 METHOD_ARG_DESCRIBE_IN("connection_id", DBUS_TYPE_UINT64_AS_STRING, "id of connection to disconnect")
2576 METHOD_ARGS_END
2578 METHOD_ARGS_BEGIN(GetClientPID, "get process id of client")
2579 METHOD_ARG_DESCRIBE_IN("client_id", DBUS_TYPE_UINT64_AS_STRING, "id of client")
2580 METHOD_ARG_DESCRIBE_OUT("process_id", DBUS_TYPE_INT64_AS_STRING, "pid of client")
2581 METHOD_ARGS_END
2583 METHODS_BEGIN
2584 METHOD_DESCRIBE(GetAllPorts, get_all_ports)
2585 METHOD_DESCRIBE(GetGraph, get_graph)
2586 METHOD_DESCRIBE(ConnectPortsByName, connect_ports_by_name)
2587 METHOD_DESCRIBE(ConnectPortsByID, connect_ports_by_id)
2588 METHOD_DESCRIBE(DisconnectPortsByName, disconnect_ports_by_name)
2589 METHOD_DESCRIBE(DisconnectPortsByID, disconnect_ports_by_id)
2590 METHOD_DESCRIBE(DisconnectPortsByConnectionID, disconnect_ports_by_connection_id)
2591 METHOD_DESCRIBE(GetClientPID, get_client_pid)
2592 METHODS_END
2594 SIGNAL_ARGS_BEGIN(GraphChanged, "")
2595 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2596 SIGNAL_ARGS_END
2598 SIGNAL_ARGS_BEGIN(ClientAppeared, "")
2599 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2600 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2601 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2602 SIGNAL_ARGS_END
2604 SIGNAL_ARGS_BEGIN(ClientDisappeared, "")
2605 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2606 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2607 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2608 SIGNAL_ARGS_END
2610 SIGNAL_ARGS_BEGIN(PortAppeared, "")
2611 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2612 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2613 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2614 SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
2615 SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
2616 SIGNAL_ARG_DESCRIBE("port_flags", DBUS_TYPE_UINT32_AS_STRING, "")
2617 SIGNAL_ARG_DESCRIBE("port_type", DBUS_TYPE_UINT32_AS_STRING, "")
2618 SIGNAL_ARGS_END
2620 SIGNAL_ARGS_BEGIN(PortDisappeared, "")
2621 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2622 SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2623 SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2624 SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
2625 SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
2626 SIGNAL_ARGS_END
2628 SIGNAL_ARGS_BEGIN(PortsConnected, "")
2629 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2630 SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2631 SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
2632 SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2633 SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
2634 SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2635 SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
2636 SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2637 SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
2638 SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
2639 SIGNAL_ARGS_END
2641 SIGNAL_ARGS_BEGIN(PortsDisconnected, "")
2642 SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2643 SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2644 SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
2645 SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2646 SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
2647 SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2648 SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
2649 SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2650 SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
2651 SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
2652 SIGNAL_ARGS_END
2654 SIGNALS_BEGIN
2655 SIGNAL_DESCRIBE(GraphChanged)
2656 SIGNAL_DESCRIBE(ClientAppeared)
2657 SIGNAL_DESCRIBE(ClientDisappeared)
2658 SIGNAL_DESCRIBE(PortAppeared)
2659 SIGNAL_DESCRIBE(PortDisappeared)
2660 SIGNAL_DESCRIBE(PortsConnected)
2661 SIGNAL_DESCRIBE(PortsDisconnected)
2662 SIGNALS_END
2664 INTERFACE_BEGIN(g_interface_patchbay, JACKDBUS_IFACE_PATCHBAY)
2665 INTERFACE_DEFAULT_HANDLER
2666 INTERFACE_EXPOSE_METHODS
2667 INTERFACE_EXPOSE_SIGNALS
2668 INTERFACE_END