root/daemon/graph.c @ 1d029ffd763c038622c7610e180a0170988ffcd7

Revision 1d029ffd763c038622c7610e180a0170988ffcd7, 78.2 KB (checked in by Nedko Arnaudov <nedko@…>, 2 years ago)

Move graph iteration filtering to callbacks

  • Property mode set to 100644
Line 
1/* -*- Mode: C ; c-basic-offset: 2 -*- */
2/*
3 * LADI Session Handler (ladish)
4 *
5 * Copyright (C) 2008, 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2008 Juuso Alasuutari
7 *
8 **************************************************************************
9 * This file contains implementation of the D-Bus patchbay interface helpers
10 **************************************************************************
11 *
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.
16 *
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.
21 *
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.
26 */
27
28#include "common.h"
29#include "graph.h"
30#include "../dbus/error.h"
31#include "../dbus_constants.h"
32#include "virtualizer.h"
33
34struct ladish_graph_port
35{
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;
47};
48
49struct ladish_graph_client
50{
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;
57};
58
59struct ladish_graph_connection
60{
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;
68};
69
70struct ladish_graph
71{
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;
82
83  void * context;
84  ladish_graph_connect_request_handler connect_handler;
85  ladish_graph_disconnect_request_handler disconnect_handler;
86};
87
88static void ladish_graph_emit_ports_disconnected(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
89{
90  ASSERT(graph_ptr->opath != NULL);
91
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);
108}
109
110static void ladish_graph_emit_ports_connected(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
111{
112  ASSERT(graph_ptr->opath != NULL);
113
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);
130}
131
132static void ladish_graph_emit_client_appeared(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
133{
134  ASSERT(graph_ptr->opath != NULL);
135
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);
145}
146
147static void ladish_graph_emit_client_disappeared(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
148{
149  ASSERT(graph_ptr->opath != NULL);
150
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);
160}
161
162static void ladish_graph_emit_port_appeared(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
163{
164  ASSERT(graph_ptr->opath != NULL);
165
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);
179}
180
181static void ladish_graph_emit_port_disappeared(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
182{
183  ASSERT(graph_ptr->opath != NULL);
184
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);
196}
197
198static struct ladish_graph_port * ladish_graph_find_port_by_id_internal(struct ladish_graph * graph_ptr, uint64_t port_id)
199{
200  struct list_head * node_ptr;
201  struct ladish_graph_port * port_ptr;
202
203  list_for_each(node_ptr, &graph_ptr->ports)
204  {
205    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
206    if (port_ptr->id == port_id)
207    {
208      return port_ptr;
209    }
210  }
211
212  return NULL;
213}
214
215//#define LOG_PORT_LOOKUP
216
217static struct ladish_graph_port *
218ladish_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)
224{
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];
231
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
235
236  list_for_each(node_ptr, &graph_ptr->ports)
237  {
238    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
239
240    if (client_ptr != NULL && port_ptr->client_ptr != client_ptr)
241    {
242      continue;
243    }
244
245    if (vgraph_filter != NULL && ladish_port_get_vgraph(port_ptr->port) != vgraph_filter)
246    {
247      continue;
248    }
249
250#if defined(LOG_PORT_LOOKUP)
251    if (port_ptr->link)
252    {
253      uuid_unparse(port_ptr->link_uuid_override, uuid2_str);
254      log_info("comparing link uuid %s with %s", uuid2_str, uuid1_str);
255    }
256#endif
257
258    if (use_link_override_uuids && port_ptr->link && uuid_compare(port_ptr->link_uuid_override, uuid) == 0)
259    {
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;
264    }
265
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)
272    {
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;
277    }
278  }
279
280  return NULL;
281}
282
283static struct ladish_graph_connection * ladish_graph_find_connection_by_id(struct ladish_graph * graph_ptr, uint64_t connection_id)
284{
285  struct list_head * node_ptr;
286  struct ladish_graph_connection * connection_ptr;
287
288  list_for_each(node_ptr, &graph_ptr->connections)
289  {
290    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
291    if (connection_ptr->id == connection_id)
292    {
293      return connection_ptr;
294    }
295  }
296
297  return NULL;
298}
299
300static
301struct ladish_graph_connection *
302ladish_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)
306{
307  struct list_head * node_ptr;
308  struct ladish_graph_connection * connection_ptr;
309
310  list_for_each(node_ptr, &graph_ptr->connections)
311  {
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))
315    {
316      return connection_ptr;
317    }
318  }
319
320  return NULL;
321}
322
323#define graph_ptr ((struct ladish_graph *)call_ptr->iface_context)
324
325static void get_all_ports(struct dbus_method_call * call_ptr)
326{
327  DBusMessageIter iter, sub_iter;
328
329  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
330  if (call_ptr->reply == NULL)
331  {
332    goto fail;
333  }
334
335  dbus_message_iter_init_append(call_ptr->reply, &iter);
336
337  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
338  {
339    goto fail_unref;
340  }
341
342  if (!dbus_message_iter_close_container(&iter, &sub_iter))
343  {
344    goto fail_unref;
345  }
346
347  return;
348
349fail_unref:
350  dbus_message_unref(call_ptr->reply);
351  call_ptr->reply = NULL;
352
353fail:
354  log_error("Ran out of memory trying to construct method return");
355}
356
357static void get_graph(struct dbus_method_call * call_ptr)
358{
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;
374
375  //log_info("get_graph() called");
376
377  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &known_version, DBUS_TYPE_INVALID))
378  {
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;
382  }
383
384  //log_info("Getting graph, known version is %" PRIu64, known_version);
385
386  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
387  if (call_ptr->reply == NULL)
388  {
389    log_error("Ran out of memory trying to construct method return");
390    goto exit;
391  }
392
393  dbus_message_iter_init_append(call_ptr->reply, &iter);
394
395  current_version = graph_ptr->graph_version;
396  if (known_version > current_version)
397  {
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;
405  }
406
407  if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &current_version))
408  {
409    goto nomem;
410  }
411
412  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
413  {
414    goto nomem;
415  }
416
417  if (known_version < current_version)
418  {
419    list_for_each(client_node_ptr, &graph_ptr->clients)
420    {
421      client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
422
423      if (client_ptr->hidden)
424      {
425        continue;
426      }
427
428      if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
429      {
430        goto nomem_close_clients_array;
431      }
432
433      if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
434      {
435        goto nomem_close_client_struct;
436      }
437
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))
440      {
441        goto nomem_close_client_struct;
442      }
443
444      if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
445      {
446        goto nomem_close_client_struct;
447      }
448
449      list_for_each(port_node_ptr, &client_ptr->ports)
450      {
451        port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
452
453        if (port_ptr->hidden)
454        {
455          continue;
456        }
457
458        if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
459        {
460          goto nomem_close_ports_array;
461        }
462
463        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
464        {
465          goto nomem_close_port_struct;
466        }
467
468        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
469        {
470          goto nomem_close_port_struct;
471        }
472
473        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
474        {
475          goto nomem_close_port_struct;
476        }
477
478        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
479        {
480          goto nomem_close_port_struct;
481        }
482
483        if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
484        {
485          goto nomem_close_ports_array;
486        }
487      }
488
489      if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
490      {
491        goto nomem_close_client_struct;
492      }
493
494      if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
495      {
496        goto nomem_close_clients_array;
497      }
498    }
499  }
500
501  if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
502  {
503    goto nomem;
504  }
505
506  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
507  {
508    goto nomem;
509  }
510
511  if (known_version < current_version)
512  {
513    list_for_each(connection_node_ptr, &graph_ptr->connections)
514    {
515      connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
516
517      if (connection_ptr->hidden)
518      {
519        continue;
520      }
521
522      if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
523      {
524        goto nomem_close_connections_array;
525      }
526
527      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->client_ptr->id))
528      {
529        goto nomem_close_connection_struct;
530      }
531
532      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->client_ptr->name))
533      {
534        goto nomem_close_connection_struct;
535      }
536
537      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->id))
538      {
539        goto nomem_close_connection_struct;
540      }
541
542      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->name))
543      {
544        goto nomem_close_connection_struct;
545      }
546
547      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->client_ptr->id))
548      {
549        goto nomem_close_connection_struct;
550      }
551
552      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->client_ptr->name))
553      {
554        goto nomem_close_connection_struct;
555      }
556
557      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->id))
558      {
559        goto nomem_close_connection_struct;
560      }
561
562      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->name))
563      {
564        goto nomem_close_connection_struct;
565      }
566
567      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
568      {
569        goto nomem_close_connection_struct;
570      }
571
572      if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
573      {
574        goto nomem_close_connections_array;
575      }
576    }
577  }
578
579  if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
580  {
581    goto nomem;
582  }
583
584  return;
585
586nomem_close_connection_struct:
587  dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
588
589nomem_close_connections_array:
590  dbus_message_iter_close_container(&iter, &connections_array_iter);
591  goto nomem;
592
593nomem_close_port_struct:
594  dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
595
596nomem_close_ports_array:
597  dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
598
599nomem_close_client_struct:
600  dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
601
602nomem_close_clients_array:
603  dbus_message_iter_close_container(&iter, &clients_array_iter);
604
605nomem:
606  dbus_message_unref(call_ptr->reply);
607  call_ptr->reply = NULL;
608  log_error("Ran out of memory trying to construct method return");
609
610exit:
611  return;
612}
613
614static void connect_ports_by_name(struct dbus_method_call * call_ptr)
615{
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");
618}
619
620static void connect_ports_by_id(struct dbus_method_call * call_ptr)
621{
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;
626
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))
628  {
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;
632  }
633
634  log_info("connect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
635
636  if (graph_ptr->connect_handler == NULL)
637  {
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;
640  }
641
642  port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
643  if (port1_ptr == NULL)
644  {
645    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port1_id);
646    return;
647  }
648
649  port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
650  if (port2_ptr == NULL)
651  {
652    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port2_id);
653    return;
654  }
655
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);
657
658  if (graph_ptr->connect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, port1_ptr->port, port2_ptr->port))
659  {
660    method_return_new_void(call_ptr);
661  }
662  else
663  {
664    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect failed");
665  }
666}
667
668static void disconnect_ports(struct dbus_method_call * call_ptr, struct ladish_graph_connection * connection_ptr)
669{
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);
676
677  connection_ptr->changing = true;
678  if (graph_ptr->disconnect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, connection_ptr->id))
679  {
680    method_return_new_void(call_ptr);
681  }
682  else
683  {
684    connection_ptr->changing = false;
685    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect failed");
686  }
687}
688
689static void disconnect_ports_by_name(struct dbus_method_call * call_ptr)
690{
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");
693}
694
695static void disconnect_ports_by_id(struct dbus_method_call * call_ptr)
696{
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;
702
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))
704  {
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;
708  }
709
710  log_info("disconnect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
711
712  if (graph_ptr->disconnect_handler == NULL)
713  {
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;
716  }
717
718  port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
719  if (port1_ptr == NULL)
720  {
721    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port1_id);
722    return;
723  }
724
725  port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
726  if (port2_ptr == NULL)
727  {
728    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port2_id);
729    return;
730  }
731
732  connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
733  if (connection_ptr == NULL)
734  {
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;
737  }
738
739  disconnect_ports(call_ptr, connection_ptr);
740}
741
742static void disconnect_ports_by_connection_id(struct dbus_method_call * call_ptr)
743{
744  dbus_uint64_t connection_id;
745  struct ladish_graph_connection * connection_ptr;
746
747  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &connection_id, DBUS_TYPE_INVALID))
748  {
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;
752  }
753
754  log_info("disconnect_ports_by_connection_id(%"PRIu64") called.", connection_id);
755
756  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
757  if (connection_ptr == NULL)
758  {
759    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot find connection with id %"PRIu64, connection_id);
760    return;
761  }
762
763  disconnect_ports(call_ptr, connection_ptr);
764}
765
766static void get_client_pid(struct dbus_method_call * call_ptr)
767{
768  int64_t pid = 0;
769  method_return_new_single(call_ptr, DBUS_TYPE_INT64, &pid);
770}
771
772#undef graph_ptr
773
774bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * opath)
775{
776  struct ladish_graph * graph_ptr;
777
778  graph_ptr = malloc(sizeof(struct ladish_graph));
779  if (graph_ptr == NULL)
780  {
781    log_error("malloc() failed to allocate struct graph_implementator");
782    return false;
783  }
784
785  if (opath != NULL)
786  {
787    graph_ptr->opath = strdup(opath);
788    if (graph_ptr->opath == NULL)
789    {
790      log_error("strdup() failed for graph opath");
791      free(graph_ptr);
792      return false;
793    }
794  }
795  else
796  {
797    graph_ptr->opath = NULL;
798  }
799
800  if (!ladish_dict_create(&graph_ptr->dict))
801  {
802    log_error("ladish_dict_create() failed for graph");
803    if (graph_ptr->opath != NULL)
804    {
805      free(graph_ptr->opath);
806    }
807    free(graph_ptr);
808    return false;
809  }
810
811  INIT_LIST_HEAD(&graph_ptr->clients);
812  INIT_LIST_HEAD(&graph_ptr->ports);
813  INIT_LIST_HEAD(&graph_ptr->connections);
814
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;
819
820  graph_ptr->context = NULL;
821  graph_ptr->connect_handler = NULL;
822  graph_ptr->disconnect_handler = NULL;
823
824  graph_ptr->persist = true;
825
826  *graph_handle_ptr = (ladish_graph_handle)graph_ptr;
827  return true;
828}
829
830static
831struct ladish_graph_client *
832ladish_graph_find_client(
833  struct ladish_graph * graph_ptr,
834  ladish_client_handle client)
835{
836  struct list_head * node_ptr;
837  struct ladish_graph_client * client_ptr;
838
839  list_for_each(node_ptr, &graph_ptr->clients)
840  {
841    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
842    if (client_ptr->client == client)
843    {
844      return client_ptr;
845    }
846  }
847
848  return NULL;
849}
850
851static
852struct ladish_graph_port *
853ladish_graph_find_port(
854  struct ladish_graph * graph_ptr,
855  ladish_port_handle port)
856{
857  struct list_head * node_ptr;
858  struct ladish_graph_port * port_ptr;
859
860  //log_info("searching port %p", port);
861
862  list_for_each(node_ptr, &graph_ptr->ports)
863  {
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)
867    {
868      return port_ptr;
869    }
870  }
871
872  return NULL;
873}
874
875#if defined(LOG_PORT_LOOKUP)
876#undef LOG_PORT_LOOKUP
877#endif
878//#define LOG_PORT_LOOKUP
879
880static
881struct ladish_graph_port *
882ladish_graph_find_port_by_jack_id_internal(
883  struct ladish_graph * graph_ptr,
884  uint64_t port_id,
885  bool room,
886  bool studio)
887{
888  struct list_head * node_ptr;
889  struct ladish_graph_port * port_ptr;
890
891  ASSERT(room || studio);
892
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
901
902  list_for_each(node_ptr, &graph_ptr->ports)
903  {
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))
915    {
916      //log_info("found");
917      return port_ptr;
918    }
919  }
920
921  return NULL;
922}
923
924#if 0
925static
926struct ladish_graph_port *
927ladish_graph_find_client_port(
928  struct ladish_graph * graph_ptr,
929  struct ladish_graph_client * client_ptr,
930  ladish_port_handle port)
931{
932  struct list_head * node_ptr;
933  struct ladish_graph_port * port_ptr;
934
935  list_for_each(node_ptr, &client_ptr->ports)
936  {
937    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
938    if (port_ptr->port == port)
939    {
940      return port_ptr;
941    }
942  }
943
944  return NULL;
945}
946#endif
947
948static void ladish_graph_hide_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
949{
950  ASSERT(!connection_ptr->hidden);
951  connection_ptr->hidden = true;
952  graph_ptr->graph_version++;
953
954  if (graph_ptr->opath != NULL)
955  {
956    ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
957  }
958}
959
960static void ladish_graph_show_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
961{
962  if (port_ptr->client_ptr->hidden)
963  {
964    port_ptr->client_ptr->hidden = false;
965    graph_ptr->graph_version++;
966    if (graph_ptr->opath != NULL)
967    {
968      ladish_graph_emit_client_appeared(graph_ptr, port_ptr->client_ptr);
969    }
970  }
971
972  ASSERT(port_ptr->hidden);
973  port_ptr->hidden = false;
974  graph_ptr->graph_version++;
975  if (graph_ptr->opath != NULL)
976  {
977    ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
978    ladish_try_connect_hidden_connections((ladish_graph_handle)graph_ptr);
979  }
980}
981
982static void ladish_graph_hide_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
983{
984  ASSERT(!port_ptr->hidden);
985  port_ptr->hidden = true;
986  graph_ptr->graph_version++;
987
988  if (graph_ptr->opath != NULL)
989  {
990    ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
991  }
992}
993
994static void ladish_graph_hide_client_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
995{
996  ASSERT(!client_ptr->hidden);
997  client_ptr->hidden = true;
998  graph_ptr->graph_version++;
999
1000  if (graph_ptr->opath != NULL)
1001  {
1002    ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1003  }
1004}
1005
1006static void ladish_hide_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1007{
1008  struct list_head * node_ptr;
1009  struct ladish_graph_connection * connection_ptr;
1010
1011  log_info("hidding connections of port %"PRIu64, port_ptr->id);
1012
1013  ASSERT(graph_ptr->opath != NULL);
1014
1015  list_for_each(node_ptr, &graph_ptr->connections)
1016  {
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))
1019    {
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);
1022    }
1023  }
1024}
1025
1026static void ladish_graph_remove_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
1027{
1028  list_del(&connection_ptr->siblings);
1029  graph_ptr->graph_version++;
1030
1031  if (!connection_ptr->hidden && graph_ptr->opath != NULL)
1032  {
1033    ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
1034  }
1035
1036  ladish_dict_destroy(connection_ptr->dict);
1037  free(connection_ptr);
1038}
1039
1040static void ladish_graph_remove_port_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1041{
1042  struct list_head * node_ptr;
1043  struct list_head * temp_node_ptr;
1044  struct ladish_graph_connection * connection_ptr;
1045
1046  list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
1047  {
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)
1050    {
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);
1053    }
1054  }
1055}
1056
1057static
1058void
1059ladish_graph_remove_port_internal(
1060  struct ladish_graph * graph_ptr,
1061  struct ladish_graph_client * client_ptr,
1062  struct ladish_graph_port * port_ptr)
1063{
1064  ladish_graph_remove_port_connections(graph_ptr, port_ptr);
1065
1066  ladish_port_del_ref(port_ptr->port);
1067
1068  list_del(&port_ptr->siblings_client);
1069  list_del(&port_ptr->siblings_graph);
1070
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)
1073  {
1074    ASSERT(port_ptr->client_ptr == client_ptr);
1075    ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
1076  }
1077
1078  free(port_ptr->name);
1079  free(port_ptr);
1080}
1081
1082static
1083void
1084ladish_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)
1089{
1090  struct ladish_graph_port * port_ptr;
1091
1092  while (!list_empty(&client_ptr->ports))
1093  {
1094    port_ptr = list_entry(client_ptr->ports.next, struct ladish_graph_port, siblings_client);
1095    if (port_callback != NULL)
1096    {
1097      port_callback(port_ptr->port);
1098    }
1099    ladish_graph_remove_port_internal(graph_ptr, client_ptr, port_ptr);
1100  }
1101
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)
1106  {
1107    ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1108  }
1109
1110  free(client_ptr->name);
1111
1112  if (destroy_client)
1113  {
1114    ladish_client_destroy(client_ptr->client);
1115  }
1116
1117  free(client_ptr);
1118}
1119
1120bool ladish_graph_client_looks_empty_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
1121{
1122  struct list_head * node_ptr;
1123  struct ladish_graph_port * port_ptr;
1124
1125  list_for_each(node_ptr, &client_ptr->ports)
1126  {
1127    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1128    if (!port_ptr->hidden)
1129    {
1130      //log_info("port '%s' is visible, client '%s' does not look empty", port_ptr->name, client_ptr->name);
1131      return false;
1132    }
1133    else
1134    {
1135      //log_info("port '%s' is invisible", port_ptr->name);
1136    }
1137  }
1138
1139  //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1140  return true;
1141}
1142
1143#define graph_ptr ((struct ladish_graph *)graph_handle)
1144
1145void ladish_graph_destroy(ladish_graph_handle graph_handle)
1146{
1147  ladish_graph_clear(graph_handle, NULL);
1148  ladish_dict_destroy(graph_ptr->dict);
1149  if (graph_ptr->opath != NULL)
1150  {
1151    free(graph_ptr->opath);
1152  }
1153  free(graph_ptr);
1154}
1155
1156const char * ladish_graph_get_opath(ladish_graph_handle graph_handle)
1157{
1158  return graph_ptr->opath;
1159}
1160
1161const char * ladish_graph_get_description(ladish_graph_handle graph_handle)
1162{
1163  return graph_ptr->opath != NULL ? graph_ptr->opath : "JACK";
1164}
1165
1166void
1167ladish_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)
1172{
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;
1177}
1178
1179void ladish_graph_clear(ladish_graph_handle graph_handle, ladish_graph_simple_port_callback port_callback)
1180{
1181  struct ladish_graph_client * client_ptr;
1182  struct ladish_graph_connection * connection_ptr;
1183
1184  log_info("ladish_graph_clear() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1185
1186  while (!list_empty(&graph_ptr->connections))
1187  {
1188    connection_ptr = list_entry(graph_ptr->connections.next, struct ladish_graph_connection, siblings);
1189    ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1190  }
1191
1192  while (!list_empty(&graph_ptr->clients))
1193  {
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);
1196  }
1197}
1198
1199void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle)
1200{
1201  return graph_handle;
1202}
1203
1204ladish_dict_handle ladish_graph_get_dict(ladish_graph_handle graph_handle)
1205{
1206  return graph_ptr->dict;
1207}
1208
1209void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id)
1210{
1211  struct ladish_graph_connection * connection_ptr;
1212
1213  log_info("ladish_graph_show_connection() called.");
1214
1215  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1216  if (connection_ptr == NULL)
1217  {
1218    ASSERT_NO_PASS;
1219    return;
1220  }
1221
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++;
1227
1228  ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1229}
1230
1231void ladish_graph_show_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1232{
1233  struct ladish_graph_port * port_ptr;
1234
1235  //log_info("ladish_graph_show_port() called.");
1236
1237  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1238  if (port_ptr == NULL)
1239  {
1240    ASSERT_NO_PASS;
1241    return;
1242  }
1243
1244  //log_info("port '%s' is %s", port_ptr->name, port_ptr->hidden ? "invisible" : "visible");
1245
1246  ladish_graph_show_port_internal(graph_ptr, port_ptr);
1247}
1248
1249void ladish_graph_hide_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1250{
1251  struct ladish_graph_port * port_ptr;
1252
1253  log_info("ladish_graph_hide_port() called.");
1254
1255  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1256  if (port_ptr == NULL)
1257  {
1258    ASSERT_NO_PASS;
1259    return;
1260  }
1261
1262  log_info("Hidding port %"PRIu64, port_ptr->id);
1263
1264  ASSERT(!port_ptr->hidden);
1265
1266  if (graph_ptr->opath != NULL)
1267  {
1268    ladish_hide_connections(graph_ptr, port_ptr);
1269  }
1270
1271  ladish_graph_hide_port_internal(graph_ptr, port_ptr);
1272}
1273
1274void ladish_graph_hide_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1275{
1276  struct ladish_graph_client * client_ptr;
1277
1278  log_info("ladish_graph_hide_client() called.");
1279
1280  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1281  if (client_ptr == NULL)
1282  {
1283    ASSERT_NO_PASS;
1284    return;
1285  }
1286
1287  ladish_graph_hide_client_internal(graph_ptr, client_ptr);
1288}
1289
1290void ladish_graph_show_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1291{
1292  struct ladish_graph_client * client_ptr;
1293
1294  log_info("ladish_graph_show_client() called.");
1295
1296  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1297  if (client_ptr == NULL)
1298  {
1299    ASSERT_NO_PASS;
1300    return;
1301  }
1302
1303  ASSERT(client_ptr->hidden);
1304  client_ptr->hidden = false;
1305  graph_ptr->graph_version++;
1306
1307  if (graph_ptr->opath != NULL)
1308  {
1309    ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1310  }
1311}
1312
1313void ladish_graph_adjust_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle, uint32_t type, uint32_t flags)
1314{
1315  struct ladish_graph_port * port_ptr;
1316
1317  //log_info("ladish_graph_adjust_port() called.");
1318
1319  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1320  if (port_ptr == NULL)
1321  {
1322    ASSERT_NO_PASS;
1323    return;
1324  }
1325
1326  port_ptr->type = type;
1327  port_ptr->flags = flags;
1328}
1329
1330bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name, bool hidden)
1331{
1332  struct ladish_graph_client * client_ptr;
1333
1334  log_info("adding client '%s' (%p) to graph %s", name, client_handle, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1335
1336  client_ptr = malloc(sizeof(struct ladish_graph_client));
1337  if (client_ptr == NULL)
1338  {
1339    log_error("malloc() failed for struct ladish_graph_client");
1340    return false;
1341  }
1342
1343  client_ptr->name = strdup(name);
1344  if (client_ptr->name == NULL)
1345  {
1346    log_error("strdup() failed for graph client name");
1347    free(client_ptr);
1348    return false;
1349  }
1350
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++;
1355
1356  INIT_LIST_HEAD(&client_ptr->ports);
1357
1358  list_add_tail(&client_ptr->siblings, &graph_ptr->clients);
1359
1360  if (!hidden && graph_ptr->opath != NULL)
1361  {
1362    ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1363  }
1364
1365  return true;
1366}
1367
1368void
1369ladish_graph_remove_client(
1370  ladish_graph_handle graph_handle,
1371  ladish_client_handle client_handle)
1372{
1373  struct ladish_graph_client * client_ptr;
1374
1375  log_info("ladish_graph_remove_client() called.");
1376
1377  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1378  if (client_ptr != NULL)
1379  {
1380    ladish_graph_remove_client_internal(graph_ptr, client_ptr, false, NULL);
1381  }
1382  else
1383  {
1384    ASSERT_NO_PASS;
1385  }
1386}
1387
1388bool
1389ladish_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)
1397{
1398  struct ladish_graph_client * client_ptr;
1399  struct ladish_graph_port * port_ptr;
1400
1401  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1402  if (client_ptr == NULL)
1403  {
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;
1407  }
1408
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");
1410
1411  port_ptr = malloc(sizeof(struct ladish_graph_port));
1412  if (port_ptr == NULL)
1413  {
1414    log_error("malloc() failed for struct ladish_graph_port");
1415    return false;
1416  }
1417
1418  port_ptr->name = strdup(name);
1419  if (port_ptr->name == NULL)
1420  {
1421    log_error("strdup() failed for graph port name");
1422    free(port_ptr);
1423    return false;
1424  }
1425
1426  port_ptr->type = type;
1427  port_ptr->flags = flags;
1428
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;
1433
1434  port_ptr->link = ladish_port_is_link(port_handle);
1435  if (port_ptr->link)
1436  {
1437    uuid_generate(port_ptr->link_uuid_override);
1438  }
1439
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);
1443
1444  if (!hidden)
1445  {
1446    ladish_graph_show_port_internal(graph_ptr, port_ptr);
1447  }
1448
1449  return true;
1450}
1451
1452uint64_t
1453ladish_graph_add_connection(
1454  ladish_graph_handle graph_handle,
1455  ladish_port_handle port1_handle,
1456  ladish_port_handle port2_handle,
1457  bool hidden)
1458{
1459  struct ladish_graph_port * port1_ptr;
1460  struct ladish_graph_port * port2_ptr;
1461  struct ladish_graph_connection * connection_ptr;
1462
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);
1467
1468  connection_ptr = malloc(sizeof(struct ladish_graph_connection));
1469  if (connection_ptr == NULL)
1470  {
1471    log_error("malloc() failed for struct ladish_graph_connection");
1472    return 0;
1473  }
1474
1475  if (!ladish_dict_create(&connection_ptr->dict))
1476  {
1477    log_error("ladish_dict_create() failed for connection");
1478    free(connection_ptr);
1479    return 0;
1480  }
1481
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++;
1488
1489  list_add_tail(&connection_ptr->siblings, &graph_ptr->connections);
1490
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); */
1498
1499  if (!hidden && graph_ptr->opath != NULL)
1500  {
1501    ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1502  }
1503
1504  return connection_ptr->id;
1505}
1506
1507void
1508ladish_graph_remove_connection(
1509  ladish_graph_handle graph_handle,
1510  uint64_t connection_id,
1511  bool force)
1512{
1513  struct ladish_graph_connection * connection_ptr;
1514
1515  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1516  if (connection_ptr == NULL)
1517  {
1518    ASSERT_NO_PASS;
1519    return;
1520  }
1521
1522  if (force || connection_ptr->changing || !graph_ptr->persist)
1523  {
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); */
1530
1531    ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1532  }
1533  else
1534  {
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); */
1541
1542    ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
1543  }
1544}
1545
1546bool
1547ladish_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)
1552{
1553  struct ladish_graph_connection * connection_ptr;
1554
1555  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1556  if (connection_ptr == NULL)
1557  {
1558    return false;
1559  }
1560
1561  *port1_handle_ptr = connection_ptr->port1_ptr->port;
1562  *port2_handle_ptr = connection_ptr->port2_ptr->port;
1563
1564  return true;
1565}
1566
1567ladish_dict_handle ladish_graph_get_connection_dict(ladish_graph_handle graph_handle, uint64_t connection_id)
1568{
1569  struct ladish_graph_connection * connection_ptr;
1570
1571  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1572  if (connection_ptr == NULL)
1573  {
1574    return NULL;
1575  }
1576
1577  return connection_ptr->dict;
1578}
1579
1580bool
1581ladish_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)
1586{
1587  struct ladish_graph_port * port1_ptr;
1588  struct ladish_graph_port * port2_ptr;
1589  struct ladish_graph_connection * connection_ptr;
1590
1591  port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1592  if (port1_ptr == NULL)
1593  {
1594    return false;
1595  }
1596     
1597  port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1598  if (port1_ptr == NULL)
1599  {
1600    return false;
1601  }
1602
1603  connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
1604  if (connection_ptr == NULL)
1605  {
1606    return false;
1607  }
1608
1609  *connection_id_ptr = connection_ptr->id;
1610
1611  return true;
1612}
1613
1614ladish_client_handle ladish_graph_find_client_by_name(ladish_graph_handle graph_handle, const char * name, bool appless)
1615{
1616  struct list_head * node_ptr;
1617  struct ladish_graph_client * client_ptr;
1618
1619  list_for_each(node_ptr, &graph_ptr->clients)
1620  {
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 */
1624    {
1625      return client_ptr->client;
1626    }
1627  }
1628
1629  return NULL;
1630}
1631
1632ladish_client_handle ladish_graph_find_client_by_app(ladish_graph_handle graph_handle, const uuid_t app_uuid)
1633{
1634  struct list_head * node_ptr;
1635  struct ladish_graph_client * client_ptr;
1636  uuid_t current_uuid;
1637
1638  list_for_each(node_ptr, &graph_ptr->clients)
1639  {
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;
1643
1644    if (uuid_compare(current_uuid, app_uuid) == 0)
1645    {
1646      return client_ptr->client;
1647    }
1648  }
1649
1650  return NULL;
1651}
1652
1653ladish_port_handle
1654ladish_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)
1659{
1660  struct ladish_graph_client * client_ptr;
1661  struct list_head * node_ptr;
1662  struct ladish_graph_port * port_ptr;
1663
1664  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1665  if (client_ptr != NULL)
1666  {
1667    list_for_each(node_ptr, &client_ptr->ports)
1668    {
1669      port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1670
1671      if (vgraph_filter != NULL && ladish_port_get_vgraph(port_ptr->port) != vgraph_filter)
1672      {
1673        continue;
1674      }
1675
1676      if (strcmp(port_ptr->name, name) == 0)
1677      {
1678        return port_ptr->port;
1679      }
1680    }
1681  }
1682  else
1683  {
1684    ASSERT_NO_PASS;
1685  }
1686
1687  return NULL;
1688}
1689
1690ladish_client_handle ladish_graph_find_client_by_uuid(ladish_graph_handle graph_handle, const uuid_t uuid)
1691{
1692  struct list_head * node_ptr;
1693  struct ladish_graph_client * client_ptr;
1694  uuid_t current_uuid;
1695
1696  list_for_each(node_ptr, &graph_ptr->clients)
1697  {
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)
1701    {
1702      return client_ptr->client;
1703    }
1704  }
1705
1706  return NULL;
1707}
1708
1709ladish_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)
1710{
1711  struct ladish_graph_port * port_ptr;
1712
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)
1715  {
1716    return port_ptr->port;
1717  }
1718
1719  return NULL;
1720}
1721
1722ladish_client_handle ladish_graph_get_port_client(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1723{
1724  struct ladish_graph_port * port_ptr;
1725
1726  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1727  if (port_ptr == NULL)
1728  {
1729    return NULL;
1730  }
1731
1732  return port_ptr->client_ptr->client;
1733}
1734
1735bool ladish_graph_is_port_present(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1736{
1737  return ladish_graph_find_port(graph_ptr, port_handle) != NULL;
1738}
1739
1740ladish_client_handle ladish_graph_find_client_by_id(ladish_graph_handle graph_handle, uint64_t client_id)
1741{
1742  struct list_head * node_ptr;
1743  struct ladish_graph_client * client_ptr;
1744
1745  list_for_each(node_ptr, &graph_ptr->clients)
1746  {
1747    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1748    if (client_ptr->id == client_id)
1749    {
1750      return client_ptr->client;
1751    }
1752  }
1753
1754  return NULL;
1755}
1756
1757ladish_port_handle ladish_graph_find_port_by_id(ladish_graph_handle graph_handle, uint64_t port_id)
1758{
1759  struct ladish_graph_port * port_ptr;
1760
1761  port_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port_id);
1762  if (port_ptr == NULL)
1763  {
1764    return NULL;
1765  }
1766
1767  return port_ptr->port;
1768}
1769
1770ladish_client_handle ladish_graph_find_client_by_jack_id(ladish_graph_handle graph_handle, uint64_t client_id)
1771{
1772  struct list_head * node_ptr;
1773  struct ladish_graph_client * client_ptr;
1774
1775  list_for_each(node_ptr, &graph_ptr->clients)
1776  {
1777    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1778    if (ladish_client_get_jack_id(client_ptr->client) == client_id)
1779    {
1780      return client_ptr->client;
1781    }
1782  }
1783
1784  return NULL;
1785}
1786
1787ladish_port_handle ladish_graph_find_port_by_jack_id(ladish_graph_handle graph_handle, uint64_t port_id, bool room, bool studio)
1788{
1789  struct ladish_graph_port * port_ptr;
1790
1791  port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, port_id, room, studio);
1792  if (port_ptr == NULL)
1793  {
1794    return NULL;
1795  }
1796
1797  return port_ptr->port;
1798}
1799
1800bool ladish_graph_client_has_visible_app_port(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const uuid_t app_uuid)
1801{
1802  struct ladish_graph_client * client_ptr;
1803  struct list_head * node_ptr;
1804  struct ladish_graph_port * port_ptr;
1805
1806  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1807  if (client_ptr == NULL)
1808  {
1809    ASSERT_NO_PASS;
1810    return false;
1811  }
1812
1813  list_for_each(node_ptr, &client_ptr->ports)
1814  {
1815    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1816    if (port_ptr->hidden)
1817    {
1818      continue;
1819    }
1820
1821    if (ladish_port_belongs_to_app(port_ptr->port, app_uuid))
1822    {
1823      ASSERT(!client_ptr->hidden);
1824      return true;
1825    }
1826  }
1827
1828  return false;
1829}
1830
1831ladish_client_handle
1832ladish_graph_remove_port(
1833  ladish_graph_handle graph_handle,
1834  ladish_port_handle port)
1835{
1836  struct ladish_graph_port * port_ptr;
1837  ladish_client_handle client;
1838
1839  port_ptr = ladish_graph_find_port(graph_ptr, port);
1840  if (port_ptr == NULL)
1841  {
1842    return NULL;
1843  }
1844
1845  client = port_ptr->client_ptr->client;
1846  ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
1847  return client;
1848}
1849
1850ladish_client_handle
1851ladish_graph_remove_port_by_jack_id(
1852  ladish_graph_handle graph_handle,
1853  uint64_t jack_port_id,
1854  bool room,
1855  bool studio)
1856{
1857  struct ladish_graph_port * port_ptr;
1858  ladish_client_handle client;
1859
1860  port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, jack_port_id, room, studio);
1861  if (port_ptr == NULL)
1862  {
1863    return NULL;
1864  }
1865
1866  client = port_ptr->client_ptr->client;
1867  ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
1868  return client;
1869}
1870
1871bool
1872ladish_graph_rename_client(
1873  ladish_graph_handle graph_handle,
1874  ladish_client_handle client_handle,
1875  const char * new_client_name)
1876{
1877  char * name;
1878  struct ladish_graph_client * client_ptr;
1879  char * old_name;
1880
1881  name = strdup(new_client_name);
1882  if (name == NULL)
1883  {
1884    log_error("strdup('%s') failed.", new_client_name);
1885    return false;
1886  }
1887
1888  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1889  if (client_ptr == NULL)
1890  {
1891    free(name);
1892    ASSERT_NO_PASS;
1893    return false;
1894  }
1895
1896  old_name = client_ptr->name;
1897  client_ptr->name = name;
1898
1899  graph_ptr->graph_version++;
1900
1901  if (!client_ptr->hidden && graph_ptr->opath != NULL)
1902  {
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);
1913  }
1914
1915  free(old_name);
1916
1917  return true;
1918}
1919
1920bool
1921ladish_graph_rename_port(
1922  ladish_graph_handle graph_handle,
1923  ladish_port_handle port_handle,
1924  const char * new_port_name)
1925{
1926  char * name;
1927  struct ladish_graph_port * port_ptr;
1928  char * old_name;
1929
1930  name = strdup(new_port_name);
1931  if (name == NULL)
1932  {
1933    log_error("strdup('%s') failed.", new_port_name);
1934    return false;
1935  }
1936
1937  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1938  if (port_ptr == NULL)
1939  {
1940    ASSERT_NO_PASS;
1941    free(name);
1942    return false;
1943  }
1944
1945  old_name = port_ptr->name;
1946  port_ptr->name = name;
1947
1948  graph_ptr->graph_version++;
1949
1950  if (!port_ptr->hidden && graph_ptr->opath != NULL)
1951  {
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);
1964  }
1965
1966  free(old_name);
1967
1968  return true;
1969}
1970
1971const char * ladish_graph_get_client_name(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1972{
1973  struct ladish_graph_client * client_ptr;
1974
1975  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1976  if (client_ptr != NULL)
1977  {
1978      return client_ptr->name;
1979  }
1980
1981  ASSERT_NO_PASS;
1982  return NULL;
1983}
1984
1985bool ladish_graph_client_is_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1986{
1987  struct ladish_graph_client * client_ptr;
1988
1989  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1990  if (client_ptr != NULL)
1991  {
1992    return list_empty(&client_ptr->ports);
1993  }
1994
1995  ASSERT_NO_PASS;
1996  return true;
1997}
1998
1999bool ladish_graph_client_looks_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2000{
2001  struct ladish_graph_client * client_ptr;
2002
2003  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2004  if (client_ptr == NULL)
2005  {
2006    ASSERT_NO_PASS;
2007    return true;
2008  }
2009
2010  if (ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2011  {
2012    //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2013    return true;
2014  }
2015
2016  return false;
2017}
2018
2019bool ladish_graph_client_is_hidden(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2020{
2021  struct ladish_graph_client * client_ptr;
2022
2023  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2024  if (client_ptr != NULL)
2025  {
2026    return client_ptr->hidden;
2027  }
2028
2029  ASSERT_NO_PASS;
2030  return true;
2031}
2032
2033void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle)
2034{
2035  struct list_head * node_ptr;
2036  struct ladish_graph_connection * connection_ptr;
2037
2038  if (!list_empty(&graph_ptr->connections) && graph_ptr->connect_handler == NULL)
2039  {
2040    ASSERT_NO_PASS;
2041    return;
2042  }
2043
2044  ASSERT(graph_ptr->opath != NULL);
2045
2046  list_for_each(node_ptr, &graph_ptr->connections)
2047  {
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)
2063    {
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);
2070
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))
2073      {
2074        connection_ptr->changing = false;
2075        log_error("auto connect failed.");
2076      }
2077    }
2078  }
2079}
2080
2081bool ladish_disconnect_visible_connections(ladish_graph_handle graph_handle)
2082{
2083  struct list_head * node_ptr;
2084  struct ladish_graph_connection * connection_ptr;
2085
2086  if (graph_ptr->disconnect_handler == NULL)
2087  {
2088    ASSERT_NO_PASS;
2089    return false;
2090  }
2091
2092  ASSERT(graph_ptr->opath != NULL);
2093
2094  list_for_each(node_ptr, &graph_ptr->connections)
2095  {
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)
2111    {
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);
2118
2119      connection_ptr->changing = true;
2120      if (!graph_ptr->disconnect_handler(graph_ptr->context, graph_handle, connection_ptr->id))
2121      {
2122        connection_ptr->changing = false;
2123        log_error("disconnect failed.");
2124        return false;
2125      }
2126    }
2127  }
2128
2129  return true;
2130}
2131
2132void ladish_graph_hide_non_virtual(ladish_graph_handle graph_handle)
2133{
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;
2138
2139  log_info("hiding everything in graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2140
2141  list_for_each(node_ptr, &graph_ptr->connections)
2142  {
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))
2147    {
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);
2150    }
2151  }
2152
2153  list_for_each(node_ptr, &graph_ptr->ports)
2154  {
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)
2157    {
2158      ladish_port_set_jack_id(port_ptr->port, 0);
2159      ladish_graph_hide_port_internal(graph_ptr, port_ptr);
2160    }
2161  }
2162
2163  list_for_each(node_ptr, &graph_ptr->clients)
2164  {
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)
2167    {
2168      ladish_client_set_jack_id(client_ptr->client, 0);
2169      ladish_graph_hide_client_internal(graph_ptr, client_ptr);
2170    }
2171  }
2172}
2173
2174void ladish_graph_get_port_uuid(ladish_graph_handle graph_handle, ladish_port_handle port, uuid_t uuid_ptr)
2175{
2176  struct ladish_graph_port * port_ptr;
2177
2178  port_ptr = ladish_graph_find_port(graph_ptr, port);
2179  ASSERT(port_ptr != NULL);
2180  ASSERT(port_ptr->link);
2181
2182  uuid_copy(uuid_ptr, port_ptr->link_uuid_override);
2183}
2184
2185const char * ladish_graph_get_port_name(ladish_graph_handle graph_handle, ladish_port_handle port)
2186{
2187  struct ladish_graph_port * port_ptr;
2188
2189  port_ptr = ladish_graph_find_port(graph_ptr, port);
2190  ASSERT(port_ptr != NULL);
2191
2192  return port_ptr->name;
2193}
2194
2195ladish_port_handle
2196ladish_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)
2201{
2202  struct ladish_graph_client * client_ptr;
2203  struct ladish_graph_port * port_ptr;
2204
2205  client_ptr = ladish_graph_find_client(graph_ptr, client);
2206  ASSERT(client_ptr != NULL);
2207
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)
2210  {
2211    return port_ptr->port;
2212  }
2213
2214  return NULL;
2215}
2216
2217void
2218ladish_graph_set_link_port_override_uuid(
2219  ladish_graph_handle graph_handle,
2220  ladish_port_handle port,
2221  const uuid_t override_uuid)
2222{
2223  struct ladish_graph_port * port_ptr;
2224
2225  port_ptr = ladish_graph_find_port(graph_ptr, port);
2226  ASSERT(ladish_port_is_link(port_ptr->port));
2227
2228  uuid_copy(port_ptr->link_uuid_override, override_uuid);
2229}
2230
2231bool
2232ladish_graph_iterate_nodes(
2233  ladish_graph_handle graph_handle,
2234  void * callback_context,
2235  bool
2236  (* client_begin_callback)(
2237    void * context,
2238    ladish_graph_handle graph_handle,
2239    bool hidden,
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    bool hidden,
2248    void * client_iteration_context_ptr,
2249    ladish_client_handle client_handle,
2250    const char * client_name,
2251    ladish_port_handle port_handle,
2252    const char * port_name,
2253    uint32_t port_type,
2254    uint32_t port_flags),
2255  bool
2256  (* client_end_callback)(
2257    void * context,
2258    ladish_graph_handle graph_handle,
2259    bool hidden,
2260    ladish_client_handle client_handle,
2261    const char * client_name,
2262    void * client_iteration_context_ptr))
2263{
2264  struct list_head * client_node_ptr;
2265  struct ladish_graph_client * client_ptr;
2266  void * client_context;
2267  struct list_head * port_node_ptr;
2268  struct list_head * port_temp_node_ptr;
2269  struct ladish_graph_port * port_ptr;
2270
2271  list_for_each(client_node_ptr, &graph_ptr->clients)
2272  {
2273    client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2274
2275    if (client_begin_callback != NULL)
2276    {
2277      if (!client_begin_callback(callback_context, graph_handle, client_ptr->hidden, client_ptr->client, client_ptr->name, &client_context))
2278      {
2279        return false;
2280      }
2281    }
2282    else
2283    {
2284      client_context = NULL;
2285    }
2286
2287    if (port_callback == NULL)
2288    {
2289      continue;
2290    }
2291
2292    list_for_each_safe(port_node_ptr, port_temp_node_ptr, &client_ptr->ports)
2293    {
2294      port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2295
2296      if (!port_callback(
2297            callback_context,
2298            graph_handle,
2299            port_ptr->hidden,
2300            client_context,
2301            client_ptr->client,
2302            client_ptr->name,
2303            port_ptr->port,
2304            port_ptr->name,
2305            port_ptr->type,
2306            port_ptr->flags))
2307      {
2308        return false;
2309      }
2310    }
2311
2312    if (client_end_callback != NULL)
2313    {
2314      if (!client_end_callback(callback_context, graph_handle, client_ptr->hidden, client_ptr->client, client_ptr->name, &client_context))
2315      {
2316        return false;
2317      }
2318    }
2319  }
2320
2321  return true;
2322}
2323
2324bool
2325ladish_graph_iterate_connections(
2326  ladish_graph_handle graph_handle,
2327  void * callback_context,
2328  bool (* callback)(
2329    void * context,
2330    ladish_graph_handle graph_handle,
2331    bool hidden,
2332    ladish_client_handle client1_handle,
2333    ladish_port_handle port1_handle,
2334    ladish_client_handle client2_handle,
2335    ladish_port_handle port2_handle,
2336    ladish_dict_handle dict))
2337{
2338  struct list_head * node_ptr;
2339  struct ladish_graph_connection * connection_ptr;
2340
2341  list_for_each(node_ptr, &graph_ptr->connections)
2342  {
2343    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2344
2345    if (!callback(
2346          callback_context,
2347          graph_handle,
2348          connection_ptr->hidden,
2349          connection_ptr->port1_ptr->client_ptr->client,
2350          connection_ptr->port1_ptr->port,
2351          connection_ptr->port2_ptr->client_ptr->client,
2352          connection_ptr->port2_ptr->port,
2353          connection_ptr->dict))
2354    {
2355      return false;
2356    }
2357  }
2358
2359  return true;
2360}
2361
2362static
2363bool
2364dump_dict_entry(
2365  void * context,
2366  const char * key,
2367  const char * value)
2368{
2369  log_info("%s  key '%s' with value '%s'", (const char *)context, key, value);
2370  return true;
2371}
2372
2373static
2374void
2375dump_dict(
2376  const char * indent,
2377  ladish_dict_handle dict)
2378{
2379  if (ladish_dict_is_empty(dict))
2380  {
2381    return;
2382  }
2383
2384  log_info("%sdict:", indent);
2385  ladish_dict_iterate(dict, (void *)indent, dump_dict_entry);
2386}
2387
2388void ladish_graph_dump(ladish_graph_handle graph_handle)
2389{
2390  struct list_head * client_node_ptr;
2391  struct ladish_graph_client * client_ptr;
2392  struct list_head * port_node_ptr;
2393  struct ladish_graph_port * port_ptr;
2394  struct list_head * connection_node_ptr;
2395  struct ladish_graph_connection * connection_ptr;
2396  uuid_t uuid;
2397  char uuid_str[37];
2398  ladish_graph_handle vgraph;
2399
2400  log_info("graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2401  log_info("  version %"PRIu64, graph_ptr->graph_version);
2402  log_info("  persist: %s", graph_ptr->persist ? "yes" : "no");
2403  dump_dict("  ", graph_ptr->dict);
2404  log_info("  clients:");
2405  list_for_each(client_node_ptr, &graph_ptr->clients)
2406  {
2407    client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2408    log_info("    %s client '%s', id=%"PRIu64", ptr=%p%", client_ptr->hidden ? "invisible" : "visible", client_ptr->name, client_ptr->id, client_ptr->client);
2409    ladish_client_get_uuid(client_ptr->client, uuid);
2410    uuid_unparse(uuid, uuid_str);
2411    log_info("    uuid=%s", uuid_str);
2412    if (ladish_client_get_interlink(client_ptr->client, uuid))
2413    {
2414      uuid_unparse(uuid, uuid_str);
2415      log_info("    interlink=%s", uuid_str);
2416    }
2417    else
2418    {
2419      log_info("    no interlink");
2420    }
2421    dump_dict("      ", ladish_client_get_dict(client_ptr->client));
2422    log_info("      ports:");
2423    list_for_each(port_node_ptr, &client_ptr->ports)
2424    {
2425      port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2426
2427      ladish_port_get_uuid(port_ptr->port, uuid);
2428      uuid_unparse(uuid, uuid_str);
2429
2430      vgraph = ladish_port_get_vgraph(port_ptr->port);
2431
2432      log_info("        %s port '%s', uuid=%s, id=%"PRIu64", type=0x%"PRIX32", flags=0x%"PRIX32", ptr=%p, vgraph=%s", port_ptr->hidden ? "invisible" : "visible", port_ptr->name, uuid_str, port_ptr->id, port_ptr->type, port_ptr->flags, port_ptr->port, vgraph != NULL ? ladish_graph_get_description(vgraph) : "NULL");
2433      dump_dict("        ", ladish_port_get_dict(port_ptr->port));
2434    }
2435  }
2436  log_info("  connections:");
2437  list_for_each(connection_node_ptr, &graph_ptr->connections)
2438  {
2439    connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
2440
2441    log_info(
2442      "    %s connection '%s':'%s' - '%s':'%s'%s",
2443      connection_ptr->hidden ? "invisible" : "visible",
2444      connection_ptr->port1_ptr->client_ptr->name,
2445      connection_ptr->port1_ptr->name,
2446      connection_ptr->port2_ptr->client_ptr->name,
2447      connection_ptr->port2_ptr->name,
2448      connection_ptr->changing ? " [changing]" : "");
2449    dump_dict("      ", connection_ptr->dict);
2450  }
2451}
2452
2453void ladish_graph_clear_persist(ladish_graph_handle graph_handle)
2454{
2455  log_info("Clearing persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2456  graph_ptr->persist = false;
2457}
2458
2459void ladish_graph_set_persist(ladish_graph_handle graph_handle)
2460{
2461  log_info("Setting persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2462  graph_ptr->persist = true;
2463}
2464
2465bool ladish_graph_is_persist(ladish_graph_handle graph_handle)
2466{
2467  return graph_ptr->persist;
2468}
2469
2470bool ladish_graph_has_visible_connections(ladish_graph_handle graph_handle)
2471{
2472  struct list_head * node_ptr;
2473  struct ladish_graph_connection * connection_ptr;
2474
2475  list_for_each(node_ptr, &graph_ptr->connections)
2476  {
2477    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2478
2479    if (!connection_ptr->hidden)
2480    {
2481      return true;
2482    }
2483  }
2484
2485  return false;
2486}
2487
2488bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
2489{
2490  struct list_head * node_ptr;
2491  struct ladish_graph_client * client_ptr;
2492
2493  if (ladish_graph_has_visible_connections(graph_handle))
2494  {
2495    return false;
2496  }
2497
2498  list_for_each(node_ptr, &graph_ptr->clients)
2499  {
2500    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2501    if (!ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2502    {
2503      return false;
2504    }
2505  }
2506
2507  return true;
2508}
2509
2510void ladish_graph_remove_hidden_objects(ladish_graph_handle graph_handle)
2511{
2512  struct list_head * node_ptr;
2513  struct list_head * temp_node_ptr;
2514  struct ladish_graph_client * client_ptr;
2515  struct ladish_graph_connection * connection_ptr;
2516
2517  log_info("ladish_graph_remove_hidden_objects() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2518
2519  list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
2520  {
2521    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2522    if (connection_ptr->hidden)
2523    {
2524      ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
2525    }
2526  }
2527
2528  list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->clients)
2529  {
2530    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2531    if (client_ptr->hidden)
2532    {
2533      ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, NULL);
2534    }
2535  }
2536}
2537
2538/* Trick the world that graph objects disappear and the reapper so the new dict values are fetched */
2539/* This is a nasty hack and should be removed once dict object can emit signals */
2540void ladish_graph_trick_dicts(ladish_graph_handle graph_handle)
2541{
2542  struct list_head * node_ptr;
2543  struct ladish_graph_connection * connection_ptr;
2544  struct ladish_graph_client * client_ptr;
2545  struct ladish_graph_port * port_ptr;
2546
2547  list_for_each(node_ptr, &graph_ptr->connections)
2548  {
2549    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2550    if (!connection_ptr->hidden)
2551    {
2552      graph_ptr->graph_version++;
2553      ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
2554    }
2555  }
2556
2557  list_for_each(node_ptr, &graph_ptr->ports)
2558  {
2559    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2560
2561    if (!port_ptr->hidden)
2562    {
2563      graph_ptr->graph_version++;
2564      ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
2565    }
2566  }
2567
2568  list_for_each(node_ptr, &graph_ptr->clients)
2569  {
2570    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2571
2572    if (!client_ptr->hidden)
2573    {
2574      graph_ptr->graph_version++;
2575      ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
2576      graph_ptr->graph_version++;
2577      ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
2578    }
2579  }
2580
2581  list_for_each(node_ptr, &graph_ptr->ports)
2582  {
2583    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2584
2585    if (!port_ptr->hidden)
2586    {
2587      graph_ptr->graph_version++;
2588      ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
2589    }
2590  }
2591
2592  list_for_each(node_ptr, &graph_ptr->connections)
2593  {
2594    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2595    if (!connection_ptr->hidden)
2596    {
2597      graph_ptr->graph_version++;
2598      ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
2599    }
2600  }
2601}
2602
2603#undef graph_ptr
2604#define graph_ptr ((struct ladish_graph *)context)
2605
2606static
2607bool
2608ladish_graph_copy_client_begin_callback(
2609  void * context,
2610  ladish_graph_handle graph_handle,
2611  bool hidden,
2612  ladish_client_handle client_handle,
2613  const char * client_name,
2614  void ** client_iteration_context_ptr_ptr)
2615{
2616  ladish_client_handle copy;
2617
2618  if (!ladish_client_create_copy(client_handle, &copy))
2619  {
2620    return false;
2621  }
2622
2623  if (!ladish_graph_add_client(context, copy, client_name, false))
2624  {
2625    ladish_client_destroy(copy);
2626    return false;
2627  }
2628
2629  *client_iteration_context_ptr_ptr = copy;
2630
2631  return true;
2632}
2633
2634static
2635bool
2636ladish_graph_copy_port_callback(
2637  void * context,
2638  ladish_graph_handle graph_handle,
2639  bool hidden,
2640  void * client_iteration_context_ptr,
2641  ladish_client_handle client_handle,
2642  const char * client_name,
2643  ladish_port_handle port_handle,
2644  const char * port_name,
2645  uint32_t port_type,
2646  uint32_t port_flags)
2647{
2648  ladish_port_handle copy;
2649
2650  if (!ladish_port_create_copy(port_handle, &copy))
2651  {
2652    return false;
2653  }
2654
2655  if (!ladish_graph_add_port(context, client_iteration_context_ptr, copy, port_name, port_type, port_flags, true))
2656  {
2657    ladish_port_destroy(copy);
2658    return false;
2659  }
2660
2661  return true;
2662}
2663
2664#undef graph_ptr
2665
2666bool ladish_graph_copy(ladish_graph_handle src, ladish_graph_handle dest)
2667{
2668  return ladish_graph_iterate_nodes(
2669    src,
2670    dest,
2671    ladish_graph_copy_client_begin_callback,
2672    ladish_graph_copy_port_callback,
2673    NULL);
2674}
2675
2676METHOD_ARGS_BEGIN(GetAllPorts, "Get all ports")
2677  METHOD_ARG_DESCRIBE_IN("ports_list", "as", "List of all ports")
2678METHOD_ARGS_END
2679
2680METHOD_ARGS_BEGIN(GetGraph, "Get whole graph")
2681METHOD_ARG_DESCRIBE_IN("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Known graph version")
2682  METHOD_ARG_DESCRIBE_OUT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Current graph version")
2683  METHOD_ARG_DESCRIBE_OUT("clients_and_ports", "a(tsa(tsuu))", "Clients and their ports")
2684  METHOD_ARG_DESCRIBE_OUT("connections", "a(tstststst)", "Connections array")
2685METHOD_ARGS_END
2686
2687METHOD_ARGS_BEGIN(ConnectPortsByName, "Connect ports")
2688  METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2689  METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2690  METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2691  METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2692METHOD_ARGS_END
2693
2694METHOD_ARGS_BEGIN(ConnectPortsByID, "Connect ports")
2695  METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2696  METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2697METHOD_ARGS_END
2698
2699METHOD_ARGS_BEGIN(DisconnectPortsByName, "Disconnect ports")
2700  METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2701  METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2702  METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2703  METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2704METHOD_ARGS_END
2705
2706METHOD_ARGS_BEGIN(DisconnectPortsByID, "Disconnect ports")
2707  METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2708  METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2709METHOD_ARGS_END
2710
2711METHOD_ARGS_BEGIN(DisconnectPortsByConnectionID, "Disconnect ports")
2712  METHOD_ARG_DESCRIBE_IN("connection_id", DBUS_TYPE_UINT64_AS_STRING, "id of connection to disconnect")
2713METHOD_ARGS_END
2714
2715METHOD_ARGS_BEGIN(GetClientPID, "get process id of client")
2716  METHOD_ARG_DESCRIBE_IN("client_id", DBUS_TYPE_UINT64_AS_STRING, "id of client")
2717  METHOD_ARG_DESCRIBE_OUT("process_id", DBUS_TYPE_INT64_AS_STRING, "pid of client")
2718METHOD_ARGS_END
2719
2720METHODS_BEGIN
2721  METHOD_DESCRIBE(GetAllPorts, get_all_ports)
2722  METHOD_DESCRIBE(GetGraph, get_graph)
2723  METHOD_DESCRIBE(ConnectPortsByName, connect_ports_by_name)
2724  METHOD_DESCRIBE(ConnectPortsByID, connect_ports_by_id)
2725  METHOD_DESCRIBE(DisconnectPortsByName, disconnect_ports_by_name)
2726  METHOD_DESCRIBE(DisconnectPortsByID, disconnect_ports_by_id)
2727  METHOD_DESCRIBE(DisconnectPortsByConnectionID, disconnect_ports_by_connection_id)
2728  METHOD_DESCRIBE(GetClientPID, get_client_pid)
2729METHODS_END
2730
2731SIGNAL_ARGS_BEGIN(GraphChanged, "")
2732  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2733SIGNAL_ARGS_END
2734
2735SIGNAL_ARGS_BEGIN(ClientAppeared, "")
2736  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2737  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2738  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2739SIGNAL_ARGS_END
2740
2741SIGNAL_ARGS_BEGIN(ClientDisappeared, "")
2742  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2743  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2744  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2745SIGNAL_ARGS_END
2746
2747SIGNAL_ARGS_BEGIN(PortAppeared, "")
2748  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2749  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2750  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2751  SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
2752  SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
2753  SIGNAL_ARG_DESCRIBE("port_flags", DBUS_TYPE_UINT32_AS_STRING, "")
2754  SIGNAL_ARG_DESCRIBE("port_type", DBUS_TYPE_UINT32_AS_STRING, "")
2755SIGNAL_ARGS_END
2756
2757SIGNAL_ARGS_BEGIN(PortDisappeared, "")
2758  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2759  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2760  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2761  SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
2762  SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
2763SIGNAL_ARGS_END
2764
2765SIGNAL_ARGS_BEGIN(PortsConnected, "")
2766  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2767  SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2768  SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
2769  SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2770  SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
2771  SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2772  SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
2773  SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2774  SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
2775  SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
2776SIGNAL_ARGS_END
2777
2778SIGNAL_ARGS_BEGIN(PortsDisconnected, "")
2779  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2780  SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2781  SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
2782  SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
2783  SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
2784  SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2785  SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
2786  SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
2787  SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
2788  SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
2789SIGNAL_ARGS_END
2790
2791SIGNALS_BEGIN
2792  SIGNAL_DESCRIBE(GraphChanged)
2793  SIGNAL_DESCRIBE(ClientAppeared)
2794  SIGNAL_DESCRIBE(ClientDisappeared)
2795  SIGNAL_DESCRIBE(PortAppeared)
2796  SIGNAL_DESCRIBE(PortDisappeared)
2797  SIGNAL_DESCRIBE(PortsConnected)
2798  SIGNAL_DESCRIBE(PortsDisconnected)
2799SIGNALS_END
2800
2801INTERFACE_BEGIN(g_interface_patchbay, JACKDBUS_IFACE_PATCHBAY)
2802  INTERFACE_DEFAULT_HANDLER
2803  INTERFACE_EXPOSE_METHODS
2804  INTERFACE_EXPOSE_SIGNALS
2805INTERFACE_END
Note: See TracBrowser for help on using the browser.