root/daemon/graph.c @ facd3090fdc3df401e563d243b5667feca02d9cf

Revision facd3090fdc3df401e563d243b5667feca02d9cf, 85.3 KB (checked in by Nedko Arnaudov <nedko@…>, 2 years ago)

ladishd: fix log line

  • 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, 2011 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
199bool
200ladish_graph_find_connection_ports_by_name_internal(
201  struct ladish_graph * graph_ptr,
202  const char * client1_name,
203  const char * port1_name,
204  const char * client2_name,
205  const char * port2_name,
206  struct ladish_graph_port ** port1_ptr_ptr,
207  struct ladish_graph_port ** port2_ptr_ptr)
208{
209  struct list_head * client1_node_ptr;
210  struct ladish_graph_client * client1_ptr;
211  struct list_head * port1_node_ptr;
212  struct ladish_graph_port * port1_ptr;
213  struct list_head * client2_node_ptr;
214  struct ladish_graph_client * client2_ptr;
215  struct list_head * port2_node_ptr;
216  struct ladish_graph_port * port2_ptr;
217
218  /*
219   * Port names are not unique, so in order to find best match,
220   * ports are searched with these assumptions:
221   *
222   *  1. port1 and port2 are of same type (midi or audio)
223   *  2. port1 is a source (capture, output) port
224   *  3. port2 is a destination (playback, input) port
225   *
226   * all these conditions have to be met for a port pair to match
227   */
228  list_for_each(client1_node_ptr, &graph_ptr->clients)
229  {
230    client1_ptr = list_entry(client1_node_ptr, struct ladish_graph_client, siblings);
231    if (strcmp(client1_ptr->name, client1_name) == 0)
232    {
233      list_for_each(port1_node_ptr, &client1_ptr->ports)
234      {
235        port1_ptr = list_entry(port1_node_ptr, struct ladish_graph_port, siblings_client);
236        if (JACKDBUS_PORT_IS_OUTPUT(port1_ptr->flags) &&
237            strcmp(port1_ptr->name, port1_name) == 0)
238        {
239          list_for_each(client2_node_ptr, &graph_ptr->clients)
240          {
241            client2_ptr = list_entry(client2_node_ptr, struct ladish_graph_client, siblings);
242            if (strcmp(client2_ptr->name, client2_name) == 0)
243            {
244              list_for_each(port2_node_ptr, &client2_ptr->ports)
245              {
246                port2_ptr = list_entry(port2_node_ptr, struct ladish_graph_port, siblings_client);
247                if (port2_ptr->type == port1_ptr->type &&
248                    JACKDBUS_PORT_IS_INPUT(port2_ptr->flags) &&
249                    strcmp(port2_ptr->name, port2_name) == 0)
250                {
251                  *port1_ptr_ptr = port1_ptr;
252                  *port2_ptr_ptr = port2_ptr;
253                  return true;
254                }
255              }
256            }
257          }
258        }
259      }
260    }
261  }
262
263  return false;
264}
265
266static
267bool
268ladish_graph_find_connection_ports_by_name(
269  struct ladish_graph * graph_ptr,
270  const char * client1_name,
271  const char * port1_name,
272  const char * client2_name,
273  const char * port2_name,
274  struct ladish_graph_port ** port1_ptr_ptr,
275  struct ladish_graph_port ** port2_ptr_ptr)
276{
277  if (ladish_graph_find_connection_ports_by_name_internal(
278        graph_ptr,
279        client1_name,
280        port1_name,
281        client2_name,
282        port2_name,
283        port1_ptr_ptr,
284        port2_ptr_ptr))
285  {
286    return true;
287  }
288
289  if (ladish_graph_find_connection_ports_by_name_internal(
290        graph_ptr,
291        client2_name,
292        port2_name,
293        client1_name,
294        port1_name,
295        port1_ptr_ptr,
296        port2_ptr_ptr))
297  {
298    return true;
299  }
300
301  return false;
302}
303
304static struct ladish_graph_port * ladish_graph_find_port_by_id_internal(struct ladish_graph * graph_ptr, uint64_t port_id)
305{
306  struct list_head * node_ptr;
307  struct ladish_graph_port * port_ptr;
308
309  list_for_each(node_ptr, &graph_ptr->ports)
310  {
311    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
312    if (port_ptr->id == port_id)
313    {
314      return port_ptr;
315    }
316  }
317
318  return NULL;
319}
320
321//#define LOG_PORT_LOOKUP
322
323static struct ladish_graph_port *
324ladish_graph_find_port_by_uuid_internal(
325  struct ladish_graph * graph_ptr,
326  struct ladish_graph_client * client_ptr,
327  const uuid_t uuid,
328  bool use_link_override_uuids,
329  void * vgraph_filter)
330{
331  struct list_head * node_ptr;
332  struct ladish_graph_port * port_ptr;
333  uuid_t current_uuid;
334#if defined(LOG_PORT_LOOKUP)
335  char uuid1_str[37];
336  char uuid2_str[37];
337
338  log_info("searching by uuid for port in graph %s", ladish_graph_get_description((ladish_graph_handle)graph_ptr));
339  uuid_unparse(uuid, uuid1_str);
340#endif
341
342  list_for_each(node_ptr, &graph_ptr->ports)
343  {
344    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
345
346    if (client_ptr != NULL && port_ptr->client_ptr != client_ptr)
347    {
348      continue;
349    }
350
351    if (vgraph_filter != NULL && ladish_port_get_vgraph(port_ptr->port) != vgraph_filter)
352    {
353      continue;
354    }
355
356#if defined(LOG_PORT_LOOKUP)
357    if (port_ptr->link)
358    {
359      uuid_unparse(port_ptr->link_uuid_override, uuid2_str);
360      log_info("comparing link uuid %s with %s", uuid2_str, uuid1_str);
361    }
362#endif
363
364    if (use_link_override_uuids && port_ptr->link && uuid_compare(port_ptr->link_uuid_override, uuid) == 0)
365    {
366#if defined(LOG_PORT_LOOKUP)
367      log_info("found link port %p of client '%s'", port_ptr->port, port_ptr->client_ptr->name);
368#endif
369      return port_ptr;
370    }
371
372    ladish_port_get_uuid(port_ptr->port, current_uuid);
373#if defined(LOG_PORT_LOOKUP)
374    uuid_unparse(current_uuid, uuid2_str);
375    log_info("comparing port uuid %s with %s", uuid2_str, uuid1_str);
376#endif
377    if (uuid_compare(current_uuid, uuid) == 0)
378    {
379#if defined(LOG_PORT_LOOKUP)
380      log_info("found port %p of client '%s'", port_ptr->port, port_ptr->client_ptr->name);
381#endif
382      return port_ptr;
383    }
384  }
385
386  return NULL;
387}
388
389static struct ladish_graph_connection * ladish_graph_find_connection_by_id(struct ladish_graph * graph_ptr, uint64_t connection_id)
390{
391  struct list_head * node_ptr;
392  struct ladish_graph_connection * connection_ptr;
393
394  list_for_each(node_ptr, &graph_ptr->connections)
395  {
396    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
397    if (connection_ptr->id == connection_id)
398    {
399      return connection_ptr;
400    }
401  }
402
403  return NULL;
404}
405
406static
407struct ladish_graph_connection *
408ladish_graph_find_connection_by_ports(
409  struct ladish_graph * graph_ptr,
410  struct ladish_graph_port * port1_ptr,
411  struct ladish_graph_port * port2_ptr)
412{
413  struct list_head * node_ptr;
414  struct ladish_graph_connection * connection_ptr;
415
416  list_for_each(node_ptr, &graph_ptr->connections)
417  {
418    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
419    if ((connection_ptr->port1_ptr == port1_ptr && connection_ptr->port2_ptr == port2_ptr) ||
420        (connection_ptr->port1_ptr == port2_ptr && connection_ptr->port2_ptr == port1_ptr))
421    {
422      return connection_ptr;
423    }
424  }
425
426  return NULL;
427}
428
429#define graph_ptr ((struct ladish_graph *)call_ptr->iface_context)
430
431static void get_all_ports(struct dbus_method_call * call_ptr)
432{
433  DBusMessageIter iter, sub_iter;
434
435  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
436  if (call_ptr->reply == NULL)
437  {
438    goto fail;
439  }
440
441  dbus_message_iter_init_append(call_ptr->reply, &iter);
442
443  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
444  {
445    goto fail_unref;
446  }
447
448  if (!dbus_message_iter_close_container(&iter, &sub_iter))
449  {
450    goto fail_unref;
451  }
452
453  return;
454
455fail_unref:
456  dbus_message_unref(call_ptr->reply);
457  call_ptr->reply = NULL;
458
459fail:
460  log_error("Ran out of memory trying to construct method return");
461}
462
463static void get_graph(struct dbus_method_call * call_ptr)
464{
465  dbus_uint64_t known_version;
466  dbus_uint64_t current_version;
467  DBusMessageIter iter;
468  DBusMessageIter clients_array_iter;
469  DBusMessageIter connections_array_iter;
470  DBusMessageIter client_struct_iter;
471  struct list_head * client_node_ptr;
472  struct ladish_graph_client * client_ptr;
473  DBusMessageIter ports_array_iter;
474  struct list_head * port_node_ptr;
475  struct ladish_graph_port * port_ptr;
476  DBusMessageIter port_struct_iter;
477  struct list_head * connection_node_ptr;
478  struct ladish_graph_connection * connection_ptr;
479  DBusMessageIter connection_struct_iter;
480
481  //log_info("get_graph() called");
482
483  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &known_version, DBUS_TYPE_INVALID))
484  {
485    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, g_dbus_error.message);
486    dbus_error_free(&g_dbus_error);
487    return;
488  }
489
490  //log_info("Getting graph, known version is %" PRIu64, known_version);
491
492  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
493  if (call_ptr->reply == NULL)
494  {
495    log_error("Ran out of memory trying to construct method return");
496    goto exit;
497  }
498
499  dbus_message_iter_init_append(call_ptr->reply, &iter);
500
501  current_version = graph_ptr->graph_version;
502  if (known_version > current_version)
503  {
504    lash_dbus_error(
505      call_ptr,
506      LASH_DBUS_ERROR_INVALID_ARGS,
507      "known graph version %" PRIu64 " is newer than actual version %" PRIu64,
508      known_version,
509      current_version);
510    goto exit;
511  }
512
513  if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &current_version))
514  {
515    goto nomem;
516  }
517
518  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
519  {
520    goto nomem;
521  }
522
523  if (known_version < current_version)
524  {
525    list_for_each(client_node_ptr, &graph_ptr->clients)
526    {
527      client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
528
529      if (client_ptr->hidden)
530      {
531        continue;
532      }
533
534      if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
535      {
536        goto nomem_close_clients_array;
537      }
538
539      if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
540      {
541        goto nomem_close_client_struct;
542      }
543
544      log_info("client '%s' (%llu)", client_ptr->name, (unsigned long long)client_ptr->id);
545      if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name))
546      {
547        goto nomem_close_client_struct;
548      }
549
550      if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
551      {
552        goto nomem_close_client_struct;
553      }
554
555      list_for_each(port_node_ptr, &client_ptr->ports)
556      {
557        port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
558
559        if (port_ptr->hidden)
560        {
561          continue;
562        }
563
564        if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
565        {
566          goto nomem_close_ports_array;
567        }
568
569        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
570        {
571          goto nomem_close_port_struct;
572        }
573
574        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
575        {
576          goto nomem_close_port_struct;
577        }
578
579        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
580        {
581          goto nomem_close_port_struct;
582        }
583
584        if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
585        {
586          goto nomem_close_port_struct;
587        }
588
589        if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
590        {
591          goto nomem_close_ports_array;
592        }
593      }
594
595      if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
596      {
597        goto nomem_close_client_struct;
598      }
599
600      if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
601      {
602        goto nomem_close_clients_array;
603      }
604    }
605  }
606
607  if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
608  {
609    goto nomem;
610  }
611
612  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
613  {
614    goto nomem;
615  }
616
617  if (known_version < current_version)
618  {
619    list_for_each(connection_node_ptr, &graph_ptr->connections)
620    {
621      connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
622
623      if (connection_ptr->hidden)
624      {
625        continue;
626      }
627
628      if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
629      {
630        goto nomem_close_connections_array;
631      }
632
633      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->client_ptr->id))
634      {
635        goto nomem_close_connection_struct;
636      }
637
638      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->client_ptr->name))
639      {
640        goto nomem_close_connection_struct;
641      }
642
643      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1_ptr->id))
644      {
645        goto nomem_close_connection_struct;
646      }
647
648      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1_ptr->name))
649      {
650        goto nomem_close_connection_struct;
651      }
652
653      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->client_ptr->id))
654      {
655        goto nomem_close_connection_struct;
656      }
657
658      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->client_ptr->name))
659      {
660        goto nomem_close_connection_struct;
661      }
662
663      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2_ptr->id))
664      {
665        goto nomem_close_connection_struct;
666      }
667
668      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2_ptr->name))
669      {
670        goto nomem_close_connection_struct;
671      }
672
673      if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
674      {
675        goto nomem_close_connection_struct;
676      }
677
678      if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
679      {
680        goto nomem_close_connections_array;
681      }
682    }
683  }
684
685  if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
686  {
687    goto nomem;
688  }
689
690  return;
691
692nomem_close_connection_struct:
693  dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
694
695nomem_close_connections_array:
696  dbus_message_iter_close_container(&iter, &connections_array_iter);
697  goto nomem;
698
699nomem_close_port_struct:
700  dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
701
702nomem_close_ports_array:
703  dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
704
705nomem_close_client_struct:
706  dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
707
708nomem_close_clients_array:
709  dbus_message_iter_close_container(&iter, &clients_array_iter);
710
711nomem:
712  dbus_message_unref(call_ptr->reply);
713  call_ptr->reply = NULL;
714  log_error("Ran out of memory trying to construct method return");
715
716exit:
717  return;
718}
719
720static void connect_ports_by_name(struct dbus_method_call * call_ptr)
721{
722  const char * client1_name;
723  const char * port1_name;
724  const char * client2_name;
725  const char * port2_name;
726  struct ladish_graph_port * port1;
727  struct ladish_graph_port * port2;
728
729  if (!dbus_message_get_args(
730        call_ptr->message,
731        &g_dbus_error,
732        DBUS_TYPE_STRING, &client1_name,
733        DBUS_TYPE_STRING, &port1_name,
734        DBUS_TYPE_STRING, &client2_name,
735        DBUS_TYPE_STRING, &port2_name,
736        DBUS_TYPE_INVALID))
737  {
738    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
739    dbus_error_free(&g_dbus_error);
740    return;
741  }
742
743  log_info("connect_ports_by_name(\"%s\", \"%s\", \"%s\", \"%s\") called.", client1_name, port1_name, client2_name, port2_name);
744
745  if (!ladish_graph_find_connection_ports_by_name(graph_ptr, client1_name, port1_name, client2_name, port2_name, &port1, &port2))
746  {
747    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown ports");
748    return;
749  }
750
751  if (graph_ptr->connect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, port1->port, port2->port))
752  {
753    method_return_new_void(call_ptr);
754  }
755  else
756  {
757    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect failed");
758  }
759}
760
761static void connect_ports_by_id(struct dbus_method_call * call_ptr)
762{
763  dbus_uint64_t port1_id;
764  dbus_uint64_t port2_id;
765  struct ladish_graph_port * port1_ptr;
766  struct ladish_graph_port * port2_ptr;
767
768  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &port1_id, DBUS_TYPE_UINT64, &port2_id, DBUS_TYPE_INVALID))
769  {
770    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
771    dbus_error_free(&g_dbus_error);
772    return;
773  }
774
775  log_info("connect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
776
777  if (graph_ptr->connect_handler == NULL)
778  {
779    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");
780    return;
781  }
782
783  port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
784  if (port1_ptr == NULL)
785  {
786    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port1_id);
787    return;
788  }
789
790  port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
791  if (port2_ptr == NULL)
792  {
793    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot connect unknown port with id %"PRIu64, port2_id);
794    return;
795  }
796
797  log_info("connecting '%s':'%s' to '%s':'%s'", port1_ptr->client_ptr->name, port1_ptr->name, port2_ptr->client_ptr->name, port2_ptr->name);
798
799  if (graph_ptr->connect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, port1_ptr->port, port2_ptr->port))
800  {
801    method_return_new_void(call_ptr);
802  }
803  else
804  {
805    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "connect failed");
806  }
807}
808
809static void disconnect_ports(struct dbus_method_call * call_ptr, struct ladish_graph_connection * connection_ptr)
810{
811  log_info(
812    "disconnecting '%s':'%s' from '%s':'%s'",
813    connection_ptr->port1_ptr->client_ptr->name,
814    connection_ptr->port1_ptr->name,
815    connection_ptr->port2_ptr->client_ptr->name,
816    connection_ptr->port2_ptr->name);
817
818  connection_ptr->changing = true;
819  if (graph_ptr->disconnect_handler(graph_ptr->context, (ladish_graph_handle)graph_ptr, connection_ptr->id))
820  {
821    method_return_new_void(call_ptr);
822  }
823  else
824  {
825    connection_ptr->changing = false;
826    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "disconnect failed");
827  }
828}
829
830static void disconnect_ports_by_name(struct dbus_method_call * call_ptr)
831{
832  const char * client1_name;
833  const char * port1_name;
834  const char * client2_name;
835  const char * port2_name;
836  struct ladish_graph_port * port1;
837  struct ladish_graph_port * port2;
838  struct ladish_graph_connection * connection_ptr;
839
840  if (!dbus_message_get_args(
841        call_ptr->message,
842        &g_dbus_error,
843        DBUS_TYPE_STRING, &client1_name,
844        DBUS_TYPE_STRING, &port1_name,
845        DBUS_TYPE_STRING, &client2_name,
846        DBUS_TYPE_STRING, &port2_name,
847        DBUS_TYPE_INVALID))
848  {
849    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
850    dbus_error_free(&g_dbus_error);
851    return;
852  }
853
854  log_info("disconnect_ports_by_name(\"%s\", \"%s\", \"%s\", \"%s\") called.", client1_name, port1_name, client2_name, port2_name);
855
856  if (!ladish_graph_find_connection_ports_by_name(graph_ptr, client1_name, port1_name, client2_name, port2_name, &port1, &port2))
857  {
858    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown ports");
859    return;
860  }
861
862  connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1, port2);
863  if (connection_ptr == NULL)
864  {
865    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect not connected ports");
866    return;
867  }
868
869  disconnect_ports(call_ptr, connection_ptr);
870}
871
872static void disconnect_ports_by_id(struct dbus_method_call * call_ptr)
873{
874  dbus_uint64_t port1_id;
875  dbus_uint64_t port2_id;
876  struct ladish_graph_port * port1_ptr;
877  struct ladish_graph_port * port2_ptr;
878  struct ladish_graph_connection * connection_ptr;
879
880  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &port1_id, DBUS_TYPE_UINT64, &port2_id, DBUS_TYPE_INVALID))
881  {
882    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
883    dbus_error_free(&g_dbus_error);
884    return;
885  }
886
887  log_info("disconnect_ports_by_id(%"PRIu64",%"PRIu64") called.", port1_id, port2_id);
888
889  if (graph_ptr->disconnect_handler == NULL)
890  {
891    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");
892    return;
893  }
894
895  port1_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port1_id);
896  if (port1_ptr == NULL)
897  {
898    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port1_id);
899    return;
900  }
901
902  port2_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port2_id);
903  if (port2_ptr == NULL)
904  {
905    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect unknown port with id %"PRIu64, port2_id);
906    return;
907  }
908
909  connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
910  if (connection_ptr == NULL)
911  {
912    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot disconnect not connected ports %"PRIu64" and %"PRIu64, port1_id, port2_id);
913    return;
914  }
915
916  disconnect_ports(call_ptr, connection_ptr);
917}
918
919static void disconnect_ports_by_connection_id(struct dbus_method_call * call_ptr)
920{
921  dbus_uint64_t connection_id;
922  struct ladish_graph_connection * connection_ptr;
923
924  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_UINT64, &connection_id, DBUS_TYPE_INVALID))
925  {
926    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
927    dbus_error_free(&g_dbus_error);
928    return;
929  }
930
931  log_info("disconnect_ports_by_connection_id(%"PRIu64") called.", connection_id);
932
933  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
934  if (connection_ptr == NULL)
935  {
936    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Cannot find connection with id %"PRIu64, connection_id);
937    return;
938  }
939
940  disconnect_ports(call_ptr, connection_ptr);
941}
942
943static void get_client_pid(struct dbus_method_call * call_ptr)
944{
945  int64_t pid = 0;
946  method_return_new_single(call_ptr, DBUS_TYPE_INT64, &pid);
947}
948
949#undef graph_ptr
950
951bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * opath)
952{
953  struct ladish_graph * graph_ptr;
954
955  graph_ptr = malloc(sizeof(struct ladish_graph));
956  if (graph_ptr == NULL)
957  {
958    log_error("malloc() failed to allocate struct graph_implementator");
959    return false;
960  }
961
962  if (opath != NULL)
963  {
964    graph_ptr->opath = strdup(opath);
965    if (graph_ptr->opath == NULL)
966    {
967      log_error("strdup() failed for graph opath");
968      free(graph_ptr);
969      return false;
970    }
971  }
972  else
973  {
974    graph_ptr->opath = NULL;
975  }
976
977  if (!ladish_dict_create(&graph_ptr->dict))
978  {
979    log_error("ladish_dict_create() failed for graph");
980    if (graph_ptr->opath != NULL)
981    {
982      free(graph_ptr->opath);
983    }
984    free(graph_ptr);
985    return false;
986  }
987
988  INIT_LIST_HEAD(&graph_ptr->clients);
989  INIT_LIST_HEAD(&graph_ptr->ports);
990  INIT_LIST_HEAD(&graph_ptr->connections);
991
992  graph_ptr->graph_version = 1;
993  graph_ptr->next_client_id = 1;
994  graph_ptr->next_port_id = 1;
995  graph_ptr->next_connection_id = 1;
996
997  graph_ptr->context = NULL;
998  graph_ptr->connect_handler = NULL;
999  graph_ptr->disconnect_handler = NULL;
1000
1001  graph_ptr->persist = true;
1002
1003  *graph_handle_ptr = (ladish_graph_handle)graph_ptr;
1004  return true;
1005}
1006
1007static
1008struct ladish_graph_client *
1009ladish_graph_find_client(
1010  struct ladish_graph * graph_ptr,
1011  ladish_client_handle client)
1012{
1013  struct list_head * node_ptr;
1014  struct ladish_graph_client * client_ptr;
1015
1016  list_for_each(node_ptr, &graph_ptr->clients)
1017  {
1018    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1019    if (client_ptr->client == client)
1020    {
1021      return client_ptr;
1022    }
1023  }
1024
1025  return NULL;
1026}
1027
1028static
1029struct ladish_graph_port *
1030ladish_graph_find_port(
1031  struct ladish_graph * graph_ptr,
1032  ladish_port_handle port)
1033{
1034  struct list_head * node_ptr;
1035  struct ladish_graph_port * port_ptr;
1036
1037  //log_info("searching port %p", port);
1038
1039  list_for_each(node_ptr, &graph_ptr->ports)
1040  {
1041    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
1042    //log_info("checking port %s:%s, %p", port_ptr->client_ptr->name, port_ptr->name, port_ptr->port);
1043    if (port_ptr->port == port)
1044    {
1045      return port_ptr;
1046    }
1047  }
1048
1049  return NULL;
1050}
1051
1052#if defined(LOG_PORT_LOOKUP)
1053#undef LOG_PORT_LOOKUP
1054#endif
1055//#define LOG_PORT_LOOKUP
1056
1057static
1058struct ladish_graph_port *
1059ladish_graph_find_port_by_jack_id_internal(
1060  struct ladish_graph * graph_ptr,
1061  uint64_t port_id,
1062  bool room,
1063  bool studio)
1064{
1065  struct list_head * node_ptr;
1066  struct ladish_graph_port * port_ptr;
1067
1068  ASSERT(room || studio);
1069
1070#if defined(LOG_PORT_LOOKUP)
1071  log_info(
1072    "searching (in %s, %s) by jack id %"PRIu64" for port in graph %s",
1073    studio ? "studio" : "",
1074    room ? "room" : "",
1075    port_id,
1076    ladish_graph_get_description((ladish_graph_handle)graph_ptr));
1077#endif
1078
1079  list_for_each(node_ptr, &graph_ptr->ports)
1080  {
1081    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
1082#if defined(LOG_PORT_LOOKUP)
1083    log_info(
1084      "checking jack port id of port %s:%s, %p; studio id %"PRIu64", room id %"PRIu64,
1085      port_ptr->client_ptr->name,
1086      port_ptr->name, port_ptr->port,
1087      ladish_port_get_jack_id(port_ptr->port),
1088      ladish_port_get_jack_id_room(port_ptr->port));
1089#endif
1090    if ((studio && ladish_port_get_jack_id(port_ptr->port) == port_id) ||
1091        (room && port_ptr->link && ladish_port_get_jack_id_room(port_ptr->port) == port_id))
1092    {
1093      //log_info("found");
1094      return port_ptr;
1095    }
1096  }
1097
1098  return NULL;
1099}
1100
1101#if 0
1102static
1103struct ladish_graph_port *
1104ladish_graph_find_client_port(
1105  struct ladish_graph * graph_ptr,
1106  struct ladish_graph_client * client_ptr,
1107  ladish_port_handle port)
1108{
1109  struct list_head * node_ptr;
1110  struct ladish_graph_port * port_ptr;
1111
1112  list_for_each(node_ptr, &client_ptr->ports)
1113  {
1114    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1115    if (port_ptr->port == port)
1116    {
1117      return port_ptr;
1118    }
1119  }
1120
1121  return NULL;
1122}
1123#endif
1124
1125static void ladish_graph_hide_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
1126{
1127  ASSERT(!connection_ptr->hidden);
1128  connection_ptr->hidden = true;
1129  graph_ptr->graph_version++;
1130
1131  if (graph_ptr->opath != NULL)
1132  {
1133    ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
1134  }
1135}
1136
1137static void ladish_graph_show_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1138{
1139  if (port_ptr->client_ptr->hidden)
1140  {
1141    port_ptr->client_ptr->hidden = false;
1142    graph_ptr->graph_version++;
1143    if (graph_ptr->opath != NULL)
1144    {
1145      ladish_graph_emit_client_appeared(graph_ptr, port_ptr->client_ptr);
1146    }
1147  }
1148
1149  ASSERT(port_ptr->hidden);
1150  port_ptr->hidden = false;
1151  graph_ptr->graph_version++;
1152  if (graph_ptr->opath != NULL)
1153  {
1154    ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
1155    ladish_try_connect_hidden_connections((ladish_graph_handle)graph_ptr);
1156  }
1157}
1158
1159static void ladish_graph_hide_port_internal(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1160{
1161  ASSERT(!port_ptr->hidden);
1162  port_ptr->hidden = true;
1163  graph_ptr->graph_version++;
1164
1165  if (graph_ptr->opath != NULL)
1166  {
1167    ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
1168  }
1169}
1170
1171static void ladish_graph_hide_client_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
1172{
1173  ASSERT(!client_ptr->hidden);
1174  client_ptr->hidden = true;
1175  graph_ptr->graph_version++;
1176
1177  if (graph_ptr->opath != NULL)
1178  {
1179    ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1180  }
1181}
1182
1183static void ladish_hide_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1184{
1185  struct list_head * node_ptr;
1186  struct ladish_graph_connection * connection_ptr;
1187
1188  log_info("hidding connections of port %"PRIu64, port_ptr->id);
1189
1190  ASSERT(graph_ptr->opath != NULL);
1191
1192  list_for_each(node_ptr, &graph_ptr->connections)
1193  {
1194    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
1195    if (!connection_ptr->hidden && (connection_ptr->port1_ptr == port_ptr || connection_ptr->port2_ptr == port_ptr))
1196    {
1197      log_info("hidding connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
1198      ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
1199    }
1200  }
1201}
1202
1203static void ladish_graph_remove_connection_internal(struct ladish_graph * graph_ptr, struct ladish_graph_connection * connection_ptr)
1204{
1205  list_del(&connection_ptr->siblings);
1206  graph_ptr->graph_version++;
1207
1208  if (!connection_ptr->hidden && graph_ptr->opath != NULL)
1209  {
1210    ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
1211  }
1212
1213  ladish_dict_destroy(connection_ptr->dict);
1214  free(connection_ptr);
1215}
1216
1217static void ladish_graph_remove_port_connections(struct ladish_graph * graph_ptr, struct ladish_graph_port * port_ptr)
1218{
1219  struct list_head * node_ptr;
1220  struct list_head * temp_node_ptr;
1221  struct ladish_graph_connection * connection_ptr;
1222
1223  list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
1224  {
1225    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
1226    if (connection_ptr->port1_ptr == port_ptr || connection_ptr->port2_ptr == port_ptr)
1227    {
1228      log_info("removing connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
1229      ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1230    }
1231  }
1232}
1233
1234static
1235void
1236ladish_graph_remove_port_internal(
1237  struct ladish_graph * graph_ptr,
1238  struct ladish_graph_client * client_ptr,
1239  struct ladish_graph_port * port_ptr)
1240{
1241  ladish_graph_remove_port_connections(graph_ptr, port_ptr);
1242
1243  ladish_port_del_ref(port_ptr->port);
1244
1245  list_del(&port_ptr->siblings_client);
1246  list_del(&port_ptr->siblings_graph);
1247
1248  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");
1249  if (graph_ptr->opath != NULL && !port_ptr->hidden)
1250  {
1251    ASSERT(port_ptr->client_ptr == client_ptr);
1252    ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
1253  }
1254
1255  free(port_ptr->name);
1256  free(port_ptr);
1257}
1258
1259static
1260void
1261ladish_graph_remove_client_internal(
1262  struct ladish_graph * graph_ptr,
1263  struct ladish_graph_client * client_ptr,
1264  bool destroy_client,
1265  ladish_graph_simple_port_callback port_callback)
1266{
1267  struct ladish_graph_port * port_ptr;
1268
1269  while (!list_empty(&client_ptr->ports))
1270  {
1271    port_ptr = list_entry(client_ptr->ports.next, struct ladish_graph_port, siblings_client);
1272    if (port_callback != NULL)
1273    {
1274      port_callback(port_ptr->port);
1275    }
1276    ladish_graph_remove_port_internal(graph_ptr, client_ptr, port_ptr);
1277  }
1278
1279  graph_ptr->graph_version++;
1280  list_del(&client_ptr->siblings);
1281  log_info("removing client '%s' (%"PRIu64") from graph %s", client_ptr->name, client_ptr->id, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1282  if (graph_ptr->opath != NULL && !client_ptr->hidden)
1283  {
1284    ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
1285  }
1286
1287  free(client_ptr->name);
1288
1289  if (destroy_client)
1290  {
1291    ladish_client_destroy(client_ptr->client);
1292  }
1293
1294  free(client_ptr);
1295}
1296
1297bool ladish_graph_client_looks_empty_internal(struct ladish_graph * graph_ptr, struct ladish_graph_client * client_ptr)
1298{
1299  struct list_head * node_ptr;
1300  struct ladish_graph_port * port_ptr;
1301
1302  list_for_each(node_ptr, &client_ptr->ports)
1303  {
1304    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1305    if (!port_ptr->hidden)
1306    {
1307      //log_info("port '%s' is visible, client '%s' does not look empty", port_ptr->name, client_ptr->name);
1308      return false;
1309    }
1310    else
1311    {
1312      //log_info("port '%s' is invisible", port_ptr->name);
1313    }
1314  }
1315
1316  //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1317  return true;
1318}
1319
1320#define graph_ptr ((struct ladish_graph *)graph_handle)
1321
1322void ladish_graph_destroy(ladish_graph_handle graph_handle)
1323{
1324  ladish_graph_clear(graph_handle, NULL);
1325  ladish_dict_destroy(graph_ptr->dict);
1326  if (graph_ptr->opath != NULL)
1327  {
1328    free(graph_ptr->opath);
1329  }
1330  free(graph_ptr);
1331}
1332
1333const char * ladish_graph_get_opath(ladish_graph_handle graph_handle)
1334{
1335  return graph_ptr->opath;
1336}
1337
1338const char * ladish_graph_get_description(ladish_graph_handle graph_handle)
1339{
1340  return graph_ptr->opath != NULL ? graph_ptr->opath : "JACK";
1341}
1342
1343void
1344ladish_graph_set_connection_handlers(
1345  ladish_graph_handle graph_handle,
1346  void * graph_context,
1347  ladish_graph_connect_request_handler connect_handler,
1348  ladish_graph_disconnect_request_handler disconnect_handler)
1349{
1350  log_info("setting connection handlers for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1351  graph_ptr->context = graph_context;
1352  graph_ptr->connect_handler = connect_handler;
1353  graph_ptr->disconnect_handler = disconnect_handler;
1354}
1355
1356void ladish_graph_clear(ladish_graph_handle graph_handle, ladish_graph_simple_port_callback port_callback)
1357{
1358  struct ladish_graph_client * client_ptr;
1359  struct ladish_graph_connection * connection_ptr;
1360
1361  log_info("ladish_graph_clear() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1362
1363  while (!list_empty(&graph_ptr->connections))
1364  {
1365    connection_ptr = list_entry(graph_ptr->connections.next, struct ladish_graph_connection, siblings);
1366    ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1367  }
1368
1369  while (!list_empty(&graph_ptr->clients))
1370  {
1371    client_ptr = list_entry(graph_ptr->clients.next, struct ladish_graph_client, siblings);
1372    ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, port_callback);
1373  }
1374}
1375
1376void * ladish_graph_get_dbus_context(ladish_graph_handle graph_handle)
1377{
1378  return graph_handle;
1379}
1380
1381ladish_dict_handle ladish_graph_get_dict(ladish_graph_handle graph_handle)
1382{
1383  return graph_ptr->dict;
1384}
1385
1386void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id)
1387{
1388  struct ladish_graph_connection * connection_ptr;
1389
1390  log_info("ladish_graph_show_connection() called.");
1391
1392  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1393  if (connection_ptr == NULL)
1394  {
1395    ASSERT_NO_PASS;
1396    return;
1397  }
1398
1399  ASSERT(graph_ptr->opath != NULL);
1400  ASSERT(connection_ptr->hidden);
1401  connection_ptr->hidden = false;
1402  connection_ptr->changing = false;
1403  graph_ptr->graph_version++;
1404
1405  ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1406}
1407
1408void ladish_graph_show_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1409{
1410  struct ladish_graph_port * port_ptr;
1411
1412  //log_info("ladish_graph_show_port() called.");
1413
1414  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1415  if (port_ptr == NULL)
1416  {
1417    ASSERT_NO_PASS;
1418    return;
1419  }
1420
1421  //log_info("port '%s' is %s", port_ptr->name, port_ptr->hidden ? "invisible" : "visible");
1422
1423  ladish_graph_show_port_internal(graph_ptr, port_ptr);
1424}
1425
1426void ladish_graph_hide_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1427{
1428  struct ladish_graph_port * port_ptr;
1429
1430  log_info("ladish_graph_hide_port() called.");
1431
1432  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1433  if (port_ptr == NULL)
1434  {
1435    ASSERT_NO_PASS;
1436    return;
1437  }
1438
1439  log_info("Hidding port %"PRIu64, port_ptr->id);
1440
1441  ASSERT(!port_ptr->hidden);
1442
1443  if (graph_ptr->opath != NULL)
1444  {
1445    ladish_hide_connections(graph_ptr, port_ptr);
1446  }
1447
1448  ladish_graph_hide_port_internal(graph_ptr, port_ptr);
1449}
1450
1451void ladish_graph_hide_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1452{
1453  struct ladish_graph_client * client_ptr;
1454
1455  log_info("ladish_graph_hide_client() called.");
1456
1457  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1458  if (client_ptr == NULL)
1459  {
1460    ASSERT_NO_PASS;
1461    return;
1462  }
1463
1464  ladish_graph_hide_client_internal(graph_ptr, client_ptr);
1465}
1466
1467void ladish_graph_show_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
1468{
1469  struct ladish_graph_client * client_ptr;
1470
1471  log_info("ladish_graph_show_client() called.");
1472
1473  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1474  if (client_ptr == NULL)
1475  {
1476    ASSERT_NO_PASS;
1477    return;
1478  }
1479
1480  ASSERT(client_ptr->hidden);
1481  client_ptr->hidden = false;
1482  graph_ptr->graph_version++;
1483
1484  if (graph_ptr->opath != NULL)
1485  {
1486    ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1487  }
1488}
1489
1490void ladish_graph_adjust_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle, uint32_t type, uint32_t flags)
1491{
1492  struct ladish_graph_port * port_ptr;
1493
1494  //log_info("ladish_graph_adjust_port() called.");
1495
1496  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1497  if (port_ptr == NULL)
1498  {
1499    ASSERT_NO_PASS;
1500    return;
1501  }
1502
1503  port_ptr->type = type;
1504  port_ptr->flags = flags;
1505}
1506
1507bool ladish_graph_add_client(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const char * name, bool hidden)
1508{
1509  struct ladish_graph_client * client_ptr;
1510
1511  log_info("adding client '%s' (%p) to graph %s", name, client_handle, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1512
1513  client_ptr = malloc(sizeof(struct ladish_graph_client));
1514  if (client_ptr == NULL)
1515  {
1516    log_error("malloc() failed for struct ladish_graph_client");
1517    return false;
1518  }
1519
1520  client_ptr->name = strdup(name);
1521  if (client_ptr->name == NULL)
1522  {
1523    log_error("strdup() failed for graph client name");
1524    free(client_ptr);
1525    return false;
1526  }
1527
1528  client_ptr->id = graph_ptr->next_client_id++;
1529  client_ptr->client = client_handle;
1530  client_ptr->hidden = hidden;
1531  graph_ptr->graph_version++;
1532
1533  INIT_LIST_HEAD(&client_ptr->ports);
1534
1535  list_add_tail(&client_ptr->siblings, &graph_ptr->clients);
1536
1537  if (!hidden && graph_ptr->opath != NULL)
1538  {
1539    ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
1540  }
1541
1542  return true;
1543}
1544
1545void
1546ladish_graph_remove_client(
1547  ladish_graph_handle graph_handle,
1548  ladish_client_handle client_handle)
1549{
1550  struct ladish_graph_client * client_ptr;
1551
1552  log_info("ladish_graph_remove_client() called.");
1553
1554  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1555  if (client_ptr != NULL)
1556  {
1557    ladish_graph_remove_client_internal(graph_ptr, client_ptr, false, NULL);
1558  }
1559  else
1560  {
1561    ASSERT_NO_PASS;
1562  }
1563}
1564
1565bool
1566ladish_graph_add_port(
1567  ladish_graph_handle graph_handle,
1568  ladish_client_handle client_handle,
1569  ladish_port_handle port_handle,
1570  const char * name,
1571  uint32_t type,
1572  uint32_t flags,
1573  bool hidden)
1574{
1575  struct ladish_graph_client * client_ptr;
1576  struct ladish_graph_port * port_ptr;
1577
1578  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1579  if (client_ptr == NULL)
1580  {
1581    log_error("cannot find client to add port to. graph is %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
1582    ASSERT_NO_PASS;
1583    return false;
1584  }
1585
1586  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");
1587
1588  port_ptr = malloc(sizeof(struct ladish_graph_port));
1589  if (port_ptr == NULL)
1590  {
1591    log_error("malloc() failed for struct ladish_graph_port");
1592    return false;
1593  }
1594
1595  port_ptr->name = strdup(name);
1596  if (port_ptr->name == NULL)
1597  {
1598    log_error("strdup() failed for graph port name");
1599    free(port_ptr);
1600    return false;
1601  }
1602
1603  port_ptr->type = type;
1604  port_ptr->flags = flags;
1605
1606  port_ptr->id = graph_ptr->next_port_id++;
1607  port_ptr->port = port_handle;
1608  ladish_port_add_ref(port_ptr->port);
1609  port_ptr->hidden = true;
1610
1611  port_ptr->link = ladish_port_is_link(port_handle);
1612  if (port_ptr->link)
1613  {
1614    uuid_generate(port_ptr->link_uuid_override);
1615  }
1616
1617  port_ptr->client_ptr = client_ptr;
1618  list_add_tail(&port_ptr->siblings_client, &client_ptr->ports);
1619  list_add_tail(&port_ptr->siblings_graph, &graph_ptr->ports);
1620
1621  if (!hidden)
1622  {
1623    ladish_graph_show_port_internal(graph_ptr, port_ptr);
1624  }
1625
1626  return true;
1627}
1628
1629uint64_t
1630ladish_graph_add_connection(
1631  ladish_graph_handle graph_handle,
1632  ladish_port_handle port1_handle,
1633  ladish_port_handle port2_handle,
1634  bool hidden)
1635{
1636  struct ladish_graph_port * port1_ptr;
1637  struct ladish_graph_port * port2_ptr;
1638  struct ladish_graph_connection * connection_ptr;
1639
1640  port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1641  ASSERT(port1_ptr != NULL);
1642  port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1643  ASSERT(port2_ptr != NULL);
1644
1645  connection_ptr = malloc(sizeof(struct ladish_graph_connection));
1646  if (connection_ptr == NULL)
1647  {
1648    log_error("malloc() failed for struct ladish_graph_connection");
1649    return 0;
1650  }
1651
1652  if (!ladish_dict_create(&connection_ptr->dict))
1653  {
1654    log_error("ladish_dict_create() failed for connection");
1655    free(connection_ptr);
1656    return 0;
1657  }
1658
1659  connection_ptr->id = graph_ptr->next_connection_id++;
1660  connection_ptr->port1_ptr = port1_ptr;
1661  connection_ptr->port2_ptr = port2_ptr;
1662  connection_ptr->hidden = hidden;
1663  connection_ptr->changing = false;
1664  graph_ptr->graph_version++;
1665
1666  list_add_tail(&connection_ptr->siblings, &graph_ptr->connections);
1667
1668  /* log_info( */
1669  /*   "new connection %"PRIu64" between '%s':'%s' and '%s':'%s'", */
1670  /*   connection_ptr->id, */
1671  /*   port1_ptr->client_ptr->name, */
1672  /*   port1_ptr->name, */
1673  /*   port2_ptr->client_ptr->name, */
1674  /*   port2_ptr->name); */
1675
1676  if (!hidden && graph_ptr->opath != NULL)
1677  {
1678    ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
1679  }
1680
1681  return connection_ptr->id;
1682}
1683
1684void
1685ladish_graph_remove_connection(
1686  ladish_graph_handle graph_handle,
1687  uint64_t connection_id,
1688  bool force)
1689{
1690  struct ladish_graph_connection * connection_ptr;
1691
1692  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1693  if (connection_ptr == NULL)
1694  {
1695    ASSERT_NO_PASS;
1696    return;
1697  }
1698
1699  if (force || connection_ptr->changing || !graph_ptr->persist)
1700  {
1701    /* log_info( */
1702    /*   "removing connection '%s':'%s' - '%s':'%s'", */
1703    /*   connection_ptr->port1_ptr->client_ptr->name, */
1704    /*   connection_ptr->port1_ptr->name, */
1705    /*   connection_ptr->port2_ptr->client_ptr->name, */
1706    /*   connection_ptr->port2_ptr->name); */
1707
1708    ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
1709  }
1710  else
1711  {
1712    /* log_info( */
1713    /*   "hiding connection '%s':'%s' - '%s':'%s'", */
1714    /*   connection_ptr->port1_ptr->client_ptr->name, */
1715    /*   connection_ptr->port1_ptr->name, */
1716    /*   connection_ptr->port2_ptr->client_ptr->name, */
1717    /*   connection_ptr->port2_ptr->name); */
1718
1719    ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
1720  }
1721}
1722
1723bool
1724ladish_graph_get_connection_ports(
1725  ladish_graph_handle graph_handle,
1726  uint64_t connection_id,
1727  ladish_port_handle * port1_handle_ptr,
1728  ladish_port_handle * port2_handle_ptr)
1729{
1730  struct ladish_graph_connection * connection_ptr;
1731
1732  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1733  if (connection_ptr == NULL)
1734  {
1735    return false;
1736  }
1737
1738  *port1_handle_ptr = connection_ptr->port1_ptr->port;
1739  *port2_handle_ptr = connection_ptr->port2_ptr->port;
1740
1741  return true;
1742}
1743
1744ladish_dict_handle ladish_graph_get_connection_dict(ladish_graph_handle graph_handle, uint64_t connection_id)
1745{
1746  struct ladish_graph_connection * connection_ptr;
1747
1748  connection_ptr = ladish_graph_find_connection_by_id(graph_ptr, connection_id);
1749  if (connection_ptr == NULL)
1750  {
1751    return NULL;
1752  }
1753
1754  return connection_ptr->dict;
1755}
1756
1757bool
1758ladish_graph_find_connection(
1759  ladish_graph_handle graph_handle,
1760  ladish_port_handle port1_handle,
1761  ladish_port_handle port2_handle,
1762  uint64_t * connection_id_ptr)
1763{
1764  struct ladish_graph_port * port1_ptr;
1765  struct ladish_graph_port * port2_ptr;
1766  struct ladish_graph_connection * connection_ptr;
1767
1768  port1_ptr = ladish_graph_find_port(graph_ptr, port1_handle);
1769  if (port1_ptr == NULL)
1770  {
1771    return false;
1772  }
1773     
1774  port2_ptr = ladish_graph_find_port(graph_ptr, port2_handle);
1775  if (port1_ptr == NULL)
1776  {
1777    return false;
1778  }
1779
1780  connection_ptr = ladish_graph_find_connection_by_ports(graph_ptr, port1_ptr, port2_ptr);
1781  if (connection_ptr == NULL)
1782  {
1783    return false;
1784  }
1785
1786  *connection_id_ptr = connection_ptr->id;
1787
1788  return true;
1789}
1790
1791ladish_client_handle ladish_graph_find_client_by_name(ladish_graph_handle graph_handle, const char * name, bool appless)
1792{
1793  struct list_head * node_ptr;
1794  struct ladish_graph_client * client_ptr;
1795
1796  list_for_each(node_ptr, &graph_ptr->clients)
1797  {
1798    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1799    if (strcmp(client_ptr->name, name) == 0 &&
1800        (!appless || !ladish_client_has_app(client_ptr->client))) /* if appless is true, then an appless client is being searched */
1801    {
1802      return client_ptr->client;
1803    }
1804  }
1805
1806  return NULL;
1807}
1808
1809ladish_client_handle ladish_graph_find_client_by_app(ladish_graph_handle graph_handle, const uuid_t app_uuid)
1810{
1811  struct list_head * node_ptr;
1812  struct ladish_graph_client * client_ptr;
1813  uuid_t current_uuid;
1814
1815  list_for_each(node_ptr, &graph_ptr->clients)
1816  {
1817    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1818    if(! ladish_client_get_app(client_ptr->client, current_uuid))
1819      continue;
1820
1821    if (uuid_compare(current_uuid, app_uuid) == 0)
1822    {
1823      return client_ptr->client;
1824    }
1825  }
1826
1827  return NULL;
1828}
1829
1830ladish_port_handle
1831ladish_graph_find_port_by_name(
1832  ladish_graph_handle graph_handle,
1833  ladish_client_handle client_handle,
1834  const char * name,
1835  void * vgraph_filter)
1836{
1837  struct ladish_graph_client * client_ptr;
1838  struct list_head * node_ptr;
1839  struct ladish_graph_port * port_ptr;
1840
1841  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1842  if (client_ptr != NULL)
1843  {
1844    list_for_each(node_ptr, &client_ptr->ports)
1845    {
1846      port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1847
1848      if (vgraph_filter != NULL && ladish_port_get_vgraph(port_ptr->port) != vgraph_filter)
1849      {
1850        continue;
1851      }
1852
1853      if (strcmp(port_ptr->name, name) == 0)
1854      {
1855        return port_ptr->port;
1856      }
1857    }
1858  }
1859  else
1860  {
1861    ASSERT_NO_PASS;
1862  }
1863
1864  return NULL;
1865}
1866
1867ladish_client_handle ladish_graph_find_client_by_uuid(ladish_graph_handle graph_handle, const uuid_t uuid)
1868{
1869  struct list_head * node_ptr;
1870  struct ladish_graph_client * client_ptr;
1871  uuid_t current_uuid;
1872
1873  list_for_each(node_ptr, &graph_ptr->clients)
1874  {
1875    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1876    ladish_client_get_uuid(client_ptr->client, current_uuid);
1877    if (uuid_compare(current_uuid, uuid) == 0)
1878    {
1879      return client_ptr->client;
1880    }
1881  }
1882
1883  return NULL;
1884}
1885
1886ladish_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)
1887{
1888  struct ladish_graph_port * port_ptr;
1889
1890  port_ptr = ladish_graph_find_port_by_uuid_internal(graph_ptr, NULL, uuid, use_link_override_uuids, vgraph_filter);
1891  if (port_ptr != NULL)
1892  {
1893    return port_ptr->port;
1894  }
1895
1896  return NULL;
1897}
1898
1899ladish_client_handle ladish_graph_get_port_client(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1900{
1901  struct ladish_graph_port * port_ptr;
1902
1903  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
1904  if (port_ptr == NULL)
1905  {
1906    return NULL;
1907  }
1908
1909  return port_ptr->client_ptr->client;
1910}
1911
1912bool ladish_graph_is_port_present(ladish_graph_handle graph_handle, ladish_port_handle port_handle)
1913{
1914  return ladish_graph_find_port(graph_ptr, port_handle) != NULL;
1915}
1916
1917ladish_client_handle ladish_graph_find_client_by_id(ladish_graph_handle graph_handle, uint64_t client_id)
1918{
1919  struct list_head * node_ptr;
1920  struct ladish_graph_client * client_ptr;
1921
1922  list_for_each(node_ptr, &graph_ptr->clients)
1923  {
1924    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1925    if (client_ptr->id == client_id)
1926    {
1927      return client_ptr->client;
1928    }
1929  }
1930
1931  return NULL;
1932}
1933
1934ladish_port_handle ladish_graph_find_port_by_id(ladish_graph_handle graph_handle, uint64_t port_id)
1935{
1936  struct ladish_graph_port * port_ptr;
1937
1938  port_ptr = ladish_graph_find_port_by_id_internal(graph_ptr, port_id);
1939  if (port_ptr == NULL)
1940  {
1941    return NULL;
1942  }
1943
1944  return port_ptr->port;
1945}
1946
1947ladish_client_handle ladish_graph_find_client_by_jack_id(ladish_graph_handle graph_handle, uint64_t client_id)
1948{
1949  struct list_head * node_ptr;
1950  struct ladish_graph_client * client_ptr;
1951
1952  list_for_each(node_ptr, &graph_ptr->clients)
1953  {
1954    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
1955    if (ladish_client_get_jack_id(client_ptr->client) == client_id)
1956    {
1957      return client_ptr->client;
1958    }
1959  }
1960
1961  return NULL;
1962}
1963
1964ladish_port_handle ladish_graph_find_port_by_jack_id(ladish_graph_handle graph_handle, uint64_t port_id, bool room, bool studio)
1965{
1966  struct ladish_graph_port * port_ptr;
1967
1968  port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, port_id, room, studio);
1969  if (port_ptr == NULL)
1970  {
1971    return NULL;
1972  }
1973
1974  return port_ptr->port;
1975}
1976
1977bool ladish_graph_client_has_visible_app_port(ladish_graph_handle graph_handle, ladish_client_handle client_handle, const uuid_t app_uuid)
1978{
1979  struct ladish_graph_client * client_ptr;
1980  struct list_head * node_ptr;
1981  struct ladish_graph_port * port_ptr;
1982
1983  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
1984  if (client_ptr == NULL)
1985  {
1986    ASSERT_NO_PASS;
1987    return false;
1988  }
1989
1990  list_for_each(node_ptr, &client_ptr->ports)
1991  {
1992    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_client);
1993    if (port_ptr->hidden)
1994    {
1995      continue;
1996    }
1997
1998    if (ladish_port_belongs_to_app(port_ptr->port, app_uuid))
1999    {
2000      ASSERT(!client_ptr->hidden);
2001      return true;
2002    }
2003  }
2004
2005  return false;
2006}
2007
2008ladish_client_handle
2009ladish_graph_remove_port(
2010  ladish_graph_handle graph_handle,
2011  ladish_port_handle port)
2012{
2013  struct ladish_graph_port * port_ptr;
2014  ladish_client_handle client;
2015
2016  port_ptr = ladish_graph_find_port(graph_ptr, port);
2017  if (port_ptr == NULL)
2018  {
2019    return NULL;
2020  }
2021
2022  client = port_ptr->client_ptr->client;
2023  ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
2024  return client;
2025}
2026
2027ladish_client_handle
2028ladish_graph_remove_port_by_jack_id(
2029  ladish_graph_handle graph_handle,
2030  uint64_t jack_port_id,
2031  bool room,
2032  bool studio)
2033{
2034  struct ladish_graph_port * port_ptr;
2035  ladish_client_handle client;
2036
2037  port_ptr = ladish_graph_find_port_by_jack_id_internal(graph_ptr, jack_port_id, room, studio);
2038  if (port_ptr == NULL)
2039  {
2040    return NULL;
2041  }
2042
2043  client = port_ptr->client_ptr->client;
2044  ladish_graph_remove_port_internal(graph_ptr, port_ptr->client_ptr, port_ptr);
2045  return client;
2046}
2047
2048bool
2049ladish_graph_rename_client(
2050  ladish_graph_handle graph_handle,
2051  ladish_client_handle client_handle,
2052  const char * new_client_name)
2053{
2054  char * name;
2055  struct ladish_graph_client * client_ptr;
2056  char * old_name;
2057
2058  name = strdup(new_client_name);
2059  if (name == NULL)
2060  {
2061    log_error("strdup('%s') failed.", new_client_name);
2062    return false;
2063  }
2064
2065  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2066  if (client_ptr == NULL)
2067  {
2068    free(name);
2069    ASSERT_NO_PASS;
2070    return false;
2071  }
2072
2073  old_name = client_ptr->name;
2074  client_ptr->name = name;
2075
2076  graph_ptr->graph_version++;
2077
2078  if (!client_ptr->hidden && graph_ptr->opath != NULL)
2079  {
2080    dbus_signal_emit(
2081      g_dbus_connection,
2082      graph_ptr->opath,
2083      JACKDBUS_IFACE_PATCHBAY,
2084      "ClientRenamed",
2085      "ttss",
2086      &graph_ptr->graph_version,
2087      &client_ptr->id,
2088      &old_name,
2089      &client_ptr->name);
2090  }
2091
2092  free(old_name);
2093
2094  return true;
2095}
2096
2097bool
2098ladish_graph_rename_port(
2099  ladish_graph_handle graph_handle,
2100  ladish_port_handle port_handle,
2101  const char * new_port_name)
2102{
2103  char * name;
2104  struct ladish_graph_port * port_ptr;
2105  char * old_name;
2106
2107  name = strdup(new_port_name);
2108  if (name == NULL)
2109  {
2110    log_error("strdup('%s') failed.", new_port_name);
2111    return false;
2112  }
2113
2114  port_ptr = ladish_graph_find_port(graph_ptr, port_handle);
2115  if (port_ptr == NULL)
2116  {
2117    ASSERT_NO_PASS;
2118    free(name);
2119    return false;
2120  }
2121
2122  old_name = port_ptr->name;
2123  port_ptr->name = name;
2124
2125  graph_ptr->graph_version++;
2126
2127  if (!port_ptr->hidden && graph_ptr->opath != NULL)
2128  {
2129    dbus_signal_emit(
2130      g_dbus_connection,
2131      graph_ptr->opath,
2132      JACKDBUS_IFACE_PATCHBAY,
2133      "PortRenamed",
2134      "ttstss",
2135      &graph_ptr->graph_version,
2136      &port_ptr->client_ptr->id,
2137      &port_ptr->client_ptr->name,
2138      &port_ptr->id,
2139      &old_name,
2140      &port_ptr->name);
2141  }
2142
2143  free(old_name);
2144
2145  return true;
2146}
2147
2148const char * ladish_graph_get_client_name(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2149{
2150  struct ladish_graph_client * client_ptr;
2151
2152  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2153  if (client_ptr != NULL)
2154  {
2155      return client_ptr->name;
2156  }
2157
2158  ASSERT_NO_PASS;
2159  return NULL;
2160}
2161
2162bool ladish_graph_client_is_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2163{
2164  struct ladish_graph_client * client_ptr;
2165
2166  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2167  if (client_ptr != NULL)
2168  {
2169    return list_empty(&client_ptr->ports);
2170  }
2171
2172  ASSERT_NO_PASS;
2173  return true;
2174}
2175
2176bool ladish_graph_client_looks_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2177{
2178  struct ladish_graph_client * client_ptr;
2179
2180  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2181  if (client_ptr == NULL)
2182  {
2183    ASSERT_NO_PASS;
2184    return true;
2185  }
2186
2187  if (ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2188  {
2189    //log_info("client '%s' looks empty in graph %s", client_ptr->name, graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2190    return true;
2191  }
2192
2193  return false;
2194}
2195
2196bool ladish_graph_client_is_hidden(ladish_graph_handle graph_handle, ladish_client_handle client_handle)
2197{
2198  struct ladish_graph_client * client_ptr;
2199
2200  client_ptr = ladish_graph_find_client(graph_ptr, client_handle);
2201  if (client_ptr != NULL)
2202  {
2203    return client_ptr->hidden;
2204  }
2205
2206  ASSERT_NO_PASS;
2207  return true;
2208}
2209
2210void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle)
2211{
2212  struct list_head * node_ptr;
2213  struct ladish_graph_connection * connection_ptr;
2214
2215  if (!list_empty(&graph_ptr->connections) && graph_ptr->connect_handler == NULL)
2216  {
2217    ASSERT_NO_PASS;
2218    return;
2219  }
2220
2221  ASSERT(graph_ptr->opath != NULL);
2222
2223  list_for_each(node_ptr, &graph_ptr->connections)
2224  {
2225    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2226    log_debug(
2227      "checking connection (%s, %s) '%s':'%s' (%s) to '%s':'%s' (%s)",
2228      connection_ptr->hidden ? "hidden" : "visible",
2229      connection_ptr->changing ? "changing" : "not changing",
2230      connection_ptr->port1_ptr->client_ptr->name,
2231      connection_ptr->port1_ptr->name,
2232      connection_ptr->port1_ptr->hidden ? "hidden" : "visible",
2233      connection_ptr->port2_ptr->client_ptr->name,
2234      connection_ptr->port2_ptr->name,
2235      connection_ptr->port2_ptr->hidden ? "hidden" : "visible");
2236    if (connection_ptr->hidden &&
2237        !connection_ptr->changing &&
2238        !connection_ptr->port1_ptr->hidden &&
2239        !connection_ptr->port2_ptr->hidden)
2240    {
2241      log_info(
2242        "auto connecting '%s':'%s' to '%s':'%s'",
2243        connection_ptr->port1_ptr->client_ptr->name,
2244        connection_ptr->port1_ptr->name,
2245        connection_ptr->port2_ptr->client_ptr->name,
2246        connection_ptr->port2_ptr->name);
2247
2248      connection_ptr->changing = true;
2249      if (!graph_ptr->connect_handler(graph_ptr->context, graph_handle, connection_ptr->port1_ptr->port, connection_ptr->port2_ptr->port))
2250      {
2251        connection_ptr->changing = false;
2252        log_error("auto connect failed.");
2253      }
2254    }
2255  }
2256}
2257
2258bool ladish_disconnect_visible_connections(ladish_graph_handle graph_handle)
2259{
2260  struct list_head * node_ptr;
2261  struct ladish_graph_connection * connection_ptr;
2262
2263  if (graph_ptr->disconnect_handler == NULL)
2264  {
2265    ASSERT_NO_PASS;
2266    return false;
2267  }
2268
2269  ASSERT(graph_ptr->opath != NULL);
2270
2271  list_for_each(node_ptr, &graph_ptr->connections)
2272  {
2273    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2274    log_debug(
2275      "checking connection (%s, %s) '%s':'%s' (%s) to '%s':'%s' (%s)",
2276      connection_ptr->hidden ? "hidden" : "visible",
2277      connection_ptr->changing ? "changing" : "not changing",
2278      connection_ptr->port1_ptr->client_ptr->name,
2279      connection_ptr->port1_ptr->name,
2280      connection_ptr->port1_ptr->hidden ? "hidden" : "visible",
2281      connection_ptr->port2_ptr->client_ptr->name,
2282      connection_ptr->port2_ptr->name,
2283      connection_ptr->port2_ptr->hidden ? "hidden" : "visible");
2284    if (!connection_ptr->hidden &&
2285        !connection_ptr->changing &&
2286        !connection_ptr->port1_ptr->hidden &&
2287        !connection_ptr->port2_ptr->hidden)
2288    {
2289      log_info(
2290        "disconnecting '%s':'%s' from '%s':'%s'",
2291        connection_ptr->port1_ptr->client_ptr->name,
2292        connection_ptr->port1_ptr->name,
2293        connection_ptr->port2_ptr->client_ptr->name,
2294        connection_ptr->port2_ptr->name);
2295
2296      connection_ptr->changing = true;
2297      if (!graph_ptr->disconnect_handler(graph_ptr->context, graph_handle, connection_ptr->id))
2298      {
2299        connection_ptr->changing = false;
2300        log_error("disconnect failed.");
2301        return false;
2302      }
2303    }
2304  }
2305
2306  return true;
2307}
2308
2309void ladish_graph_hide_non_virtual(ladish_graph_handle graph_handle)
2310{
2311  struct list_head * node_ptr;
2312  struct ladish_graph_connection * connection_ptr;
2313  struct ladish_graph_port * port_ptr;
2314  struct ladish_graph_client * client_ptr;
2315
2316  log_info("hiding everything in graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2317
2318  list_for_each(node_ptr, &graph_ptr->connections)
2319  {
2320    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2321    if (!connection_ptr->hidden &&
2322        (ladish_client_get_jack_id(connection_ptr->port1_ptr->client_ptr->client) != 0 ||
2323         ladish_client_get_jack_id(connection_ptr->port2_ptr->client_ptr->client) != 0))
2324    {
2325      log_debug("hidding connection between ports %"PRIu64" and %"PRIu64, connection_ptr->port1_ptr->id, connection_ptr->port2_ptr->id);
2326      ladish_graph_hide_connection_internal(graph_ptr, connection_ptr);
2327    }
2328  }
2329
2330  list_for_each(node_ptr, &graph_ptr->ports)
2331  {
2332    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2333    if (!port_ptr->hidden && ladish_client_get_jack_id(port_ptr->client_ptr->client) != 0)
2334    {
2335      ladish_port_set_jack_id(port_ptr->port, 0);
2336      ladish_graph_hide_port_internal(graph_ptr, port_ptr);
2337    }
2338  }
2339
2340  list_for_each(node_ptr, &graph_ptr->clients)
2341  {
2342    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2343    if (!client_ptr->hidden && ladish_client_get_jack_id(client_ptr->client) != 0)
2344    {
2345      ladish_client_set_jack_id(client_ptr->client, 0);
2346      ladish_graph_hide_client_internal(graph_ptr, client_ptr);
2347    }
2348  }
2349}
2350
2351void ladish_graph_get_port_uuid(ladish_graph_handle graph_handle, ladish_port_handle port, uuid_t uuid_ptr)
2352{
2353  struct ladish_graph_port * port_ptr;
2354
2355  port_ptr = ladish_graph_find_port(graph_ptr, port);
2356  ASSERT(port_ptr != NULL);
2357  ASSERT(port_ptr->link);
2358
2359  uuid_copy(uuid_ptr, port_ptr->link_uuid_override);
2360}
2361
2362const char * ladish_graph_get_port_name(ladish_graph_handle graph_handle, ladish_port_handle port)
2363{
2364  struct ladish_graph_port * port_ptr;
2365
2366  port_ptr = ladish_graph_find_port(graph_ptr, port);
2367  ASSERT(port_ptr != NULL);
2368
2369  return port_ptr->name;
2370}
2371
2372ladish_port_handle
2373ladish_graph_find_client_port_by_uuid(
2374  ladish_graph_handle graph_handle,
2375  ladish_client_handle client,
2376  const uuid_t uuid,
2377  bool use_link_override_uuids)
2378{
2379  struct ladish_graph_client * client_ptr;
2380  struct ladish_graph_port * port_ptr;
2381
2382  client_ptr = ladish_graph_find_client(graph_ptr, client);
2383  ASSERT(client_ptr != NULL);
2384
2385  port_ptr = ladish_graph_find_port_by_uuid_internal(graph_ptr, client_ptr, uuid, use_link_override_uuids, NULL);
2386  if (port_ptr != NULL)
2387  {
2388    return port_ptr->port;
2389  }
2390
2391  return NULL;
2392}
2393
2394void
2395ladish_graph_set_link_port_override_uuid(
2396  ladish_graph_handle graph_handle,
2397  ladish_port_handle port,
2398  const uuid_t override_uuid)
2399{
2400  struct ladish_graph_port * port_ptr;
2401
2402  port_ptr = ladish_graph_find_port(graph_ptr, port);
2403  ASSERT(ladish_port_is_link(port_ptr->port));
2404
2405  uuid_copy(port_ptr->link_uuid_override, override_uuid);
2406}
2407
2408bool
2409ladish_graph_iterate_nodes(
2410  ladish_graph_handle graph_handle,
2411  void * callback_context,
2412  bool
2413  (* client_begin_callback)(
2414    void * context,
2415    ladish_graph_handle graph_handle,
2416    bool hidden,
2417    ladish_client_handle client_handle,
2418    const char * client_name,
2419    void ** client_iteration_context_ptr_ptr),
2420  bool
2421  (* port_callback)(
2422    void * context,
2423    ladish_graph_handle graph_handle,
2424    bool hidden,
2425    void * client_iteration_context_ptr,
2426    ladish_client_handle client_handle,
2427    const char * client_name,
2428    ladish_port_handle port_handle,
2429    const char * port_name,
2430    uint32_t port_type,
2431    uint32_t port_flags),
2432  bool
2433  (* client_end_callback)(
2434    void * context,
2435    ladish_graph_handle graph_handle,
2436    bool hidden,
2437    ladish_client_handle client_handle,
2438    const char * client_name,
2439    void * client_iteration_context_ptr))
2440{
2441  struct list_head * client_node_ptr;
2442  struct ladish_graph_client * client_ptr;
2443  void * client_context;
2444  struct list_head * port_node_ptr;
2445  struct list_head * port_temp_node_ptr;
2446  struct ladish_graph_port * port_ptr;
2447
2448  list_for_each(client_node_ptr, &graph_ptr->clients)
2449  {
2450    client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2451
2452    if (client_begin_callback != NULL)
2453    {
2454      if (!client_begin_callback(callback_context, graph_handle, client_ptr->hidden, client_ptr->client, client_ptr->name, &client_context))
2455      {
2456        return false;
2457      }
2458    }
2459    else
2460    {
2461      client_context = NULL;
2462    }
2463
2464    if (port_callback == NULL)
2465    {
2466      continue;
2467    }
2468
2469    list_for_each_safe(port_node_ptr, port_temp_node_ptr, &client_ptr->ports)
2470    {
2471      port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2472
2473      if (!port_callback(
2474            callback_context,
2475            graph_handle,
2476            port_ptr->hidden,
2477            client_context,
2478            client_ptr->client,
2479            client_ptr->name,
2480            port_ptr->port,
2481            port_ptr->name,
2482            port_ptr->type,
2483            port_ptr->flags))
2484      {
2485        return false;
2486      }
2487    }
2488
2489    if (client_end_callback != NULL)
2490    {
2491      if (!client_end_callback(callback_context, graph_handle, client_ptr->hidden, client_ptr->client, client_ptr->name, &client_context))
2492      {
2493        return false;
2494      }
2495    }
2496  }
2497
2498  return true;
2499}
2500
2501bool
2502ladish_graph_iterate_connections(
2503  ladish_graph_handle graph_handle,
2504  void * callback_context,
2505  bool (* callback)(
2506    void * context,
2507    ladish_graph_handle graph_handle,
2508    bool connection_hidden,
2509    ladish_client_handle client1_handle,
2510    ladish_port_handle port1_handle,
2511    bool port1_hidden,
2512    ladish_client_handle client2_handle,
2513    ladish_port_handle port2_handle,
2514    bool port2_hidden,
2515    ladish_dict_handle dict))
2516{
2517  struct list_head * node_ptr;
2518  struct ladish_graph_connection * connection_ptr;
2519
2520  list_for_each(node_ptr, &graph_ptr->connections)
2521  {
2522    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2523
2524    if (!callback(
2525          callback_context,
2526          graph_handle,
2527          connection_ptr->hidden,
2528          connection_ptr->port1_ptr->client_ptr->client,
2529          connection_ptr->port1_ptr->port,
2530          connection_ptr->port1_ptr->hidden,
2531          connection_ptr->port2_ptr->client_ptr->client,
2532          connection_ptr->port2_ptr->port,
2533          connection_ptr->port2_ptr->hidden,
2534          connection_ptr->dict))
2535    {
2536      return false;
2537    }
2538  }
2539
2540  return true;
2541}
2542
2543bool
2544ladish_graph_interate_client_ports(
2545  ladish_graph_handle graph_handle,
2546  ladish_client_handle client,
2547  void * callback_context,
2548  bool
2549  (* port_callback)(
2550    void * context,
2551    ladish_graph_handle graph_handle,
2552    bool hidden,
2553    ladish_client_handle client_handle,
2554    const char * client_name,
2555    ladish_port_handle port_handle,
2556    const char * port_name,
2557    uint32_t port_type,
2558    uint32_t port_flags))
2559{
2560  struct ladish_graph_client * client_ptr;
2561  struct list_head * port_node_ptr;
2562  struct list_head * port_temp_node_ptr;
2563  struct ladish_graph_port * port_ptr;
2564
2565  client_ptr = ladish_graph_find_client(graph_ptr, client);
2566  if (client_ptr == NULL)
2567  {
2568    ASSERT_NO_PASS;
2569    return false;
2570  }
2571
2572  list_for_each_safe(port_node_ptr, port_temp_node_ptr, &client_ptr->ports)
2573  {
2574    port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2575
2576    if (!port_callback(
2577          callback_context,
2578          graph_handle,
2579          port_ptr->hidden,
2580          client_ptr->client,
2581          client_ptr->name,
2582          port_ptr->port,
2583          port_ptr->name,
2584          port_ptr->type,
2585          port_ptr->flags))
2586    {
2587      return false;
2588    }
2589  }
2590
2591  return true;
2592}
2593
2594static
2595bool
2596dump_dict_entry(
2597  void * context,
2598  const char * key,
2599  const char * value)
2600{
2601  log_info("%s  key '%s' with value '%s'", (const char *)context, key, value);
2602  return true;
2603}
2604
2605static
2606void
2607dump_dict(
2608  const char * indent,
2609  ladish_dict_handle dict)
2610{
2611  if (ladish_dict_is_empty(dict))
2612  {
2613    return;
2614  }
2615
2616  log_info("%sdict:", indent);
2617  ladish_dict_iterate(dict, (void *)indent, dump_dict_entry);
2618}
2619
2620void ladish_graph_dump(ladish_graph_handle graph_handle)
2621{
2622  struct list_head * client_node_ptr;
2623  struct ladish_graph_client * client_ptr;
2624  struct list_head * port_node_ptr;
2625  struct ladish_graph_port * port_ptr;
2626  struct list_head * connection_node_ptr;
2627  struct ladish_graph_connection * connection_ptr;
2628  uuid_t uuid;
2629  char uuid_str[37];
2630  ladish_graph_handle vgraph;
2631
2632  log_info("graph %s", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2633  log_info("  version %"PRIu64, graph_ptr->graph_version);
2634  log_info("  persist: %s", graph_ptr->persist ? "yes" : "no");
2635  dump_dict("  ", graph_ptr->dict);
2636  log_info("  clients:");
2637  list_for_each(client_node_ptr, &graph_ptr->clients)
2638  {
2639    client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings);
2640    log_info("    %s client '%s', id=%"PRIu64", ptr=%p", client_ptr->hidden ? "invisible" : "visible", client_ptr->name, client_ptr->id, client_ptr->client);
2641
2642    ladish_client_get_uuid(client_ptr->client, uuid);
2643    uuid_unparse(uuid, uuid_str);
2644    log_info("    uuid=%s", uuid_str);
2645
2646    if (ladish_client_get_interlink(client_ptr->client, uuid))
2647    {
2648      uuid_unparse(uuid, uuid_str);
2649      log_info("    interlink=%s", uuid_str);
2650    }
2651    else
2652    {
2653      log_info("    no interlink");
2654    }
2655
2656    if (ladish_client_get_app(client_ptr->client, uuid))
2657    {
2658      uuid_unparse(uuid, uuid_str);
2659      log_info("    app=%s", uuid_str);
2660    }
2661    else
2662    {
2663      log_info("    appless client");
2664    }
2665
2666    dump_dict("      ", ladish_client_get_dict(client_ptr->client));
2667    log_info("      ports:");
2668    list_for_each(port_node_ptr, &client_ptr->ports)
2669    {
2670      port_ptr = list_entry(port_node_ptr, struct ladish_graph_port, siblings_client);
2671
2672      ladish_port_get_uuid(port_ptr->port, uuid);
2673      uuid_unparse(uuid, uuid_str);
2674
2675      vgraph = ladish_port_get_vgraph(port_ptr->port);
2676
2677      log_info("        %s port '%s', uuid=%s, id=%"PRIu64"", port_ptr->hidden ? "invisible" : "visible", port_ptr->name, uuid_str, port_ptr->id);
2678      log_info("          type=0x%"PRIX32", flags=0x%"PRIX32", ptr=%p, vgraph=%s", port_ptr->type, port_ptr->flags, port_ptr->port, vgraph != NULL ? ladish_graph_get_description(vgraph) : "NULL");
2679
2680      if (ladish_port_get_app(port_ptr->port, uuid))
2681      {
2682        uuid_unparse(uuid, uuid_str);
2683        log_info("          app=%s", uuid_str);
2684      }
2685      else
2686      {
2687        log_info("          appless port");
2688      }
2689
2690      dump_dict("        ", ladish_port_get_dict(port_ptr->port));
2691    }
2692  }
2693  log_info("  connections:");
2694  list_for_each(connection_node_ptr, &graph_ptr->connections)
2695  {
2696    connection_ptr = list_entry(connection_node_ptr, struct ladish_graph_connection, siblings);
2697
2698    log_info(
2699      "    %s connection '%s':'%s' - '%s':'%s'%s",
2700      connection_ptr->hidden ? "invisible" : "visible",
2701      connection_ptr->port1_ptr->client_ptr->name,
2702      connection_ptr->port1_ptr->name,
2703      connection_ptr->port2_ptr->client_ptr->name,
2704      connection_ptr->port2_ptr->name,
2705      connection_ptr->changing ? " [changing]" : "");
2706    dump_dict("      ", connection_ptr->dict);
2707  }
2708}
2709
2710void ladish_graph_clear_persist(ladish_graph_handle graph_handle)
2711{
2712  log_info("Clearing persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2713  graph_ptr->persist = false;
2714}
2715
2716void ladish_graph_set_persist(ladish_graph_handle graph_handle)
2717{
2718  log_info("Setting persist flag for graph", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2719  graph_ptr->persist = true;
2720}
2721
2722bool ladish_graph_is_persist(ladish_graph_handle graph_handle)
2723{
2724  return graph_ptr->persist;
2725}
2726
2727bool ladish_graph_has_visible_connections(ladish_graph_handle graph_handle)
2728{
2729  struct list_head * node_ptr;
2730  struct ladish_graph_connection * connection_ptr;
2731
2732  list_for_each(node_ptr, &graph_ptr->connections)
2733  {
2734    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2735
2736    if (!connection_ptr->hidden)
2737    {
2738      return true;
2739    }
2740  }
2741
2742  return false;
2743}
2744
2745bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
2746{
2747  struct list_head * node_ptr;
2748  struct ladish_graph_client * client_ptr;
2749
2750  if (ladish_graph_has_visible_connections(graph_handle))
2751  {
2752    return false;
2753  }
2754
2755  list_for_each(node_ptr, &graph_ptr->clients)
2756  {
2757    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2758    if (!ladish_graph_client_looks_empty_internal(graph_ptr, client_ptr))
2759    {
2760      return false;
2761    }
2762  }
2763
2764  return true;
2765}
2766
2767void ladish_graph_remove_hidden_objects(ladish_graph_handle graph_handle)
2768{
2769  struct list_head * node_ptr;
2770  struct list_head * temp_node_ptr;
2771  struct ladish_graph_client * client_ptr;
2772  struct ladish_graph_connection * connection_ptr;
2773
2774  log_info("ladish_graph_remove_hidden_objects() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
2775
2776  list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
2777  {
2778    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2779    if (connection_ptr->hidden)
2780    {
2781      ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
2782    }
2783  }
2784
2785  list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->clients)
2786  {
2787    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2788    if (client_ptr->hidden)
2789    {
2790      ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, NULL);
2791    }
2792  }
2793}
2794
2795/* Trick the world that graph objects disappear and the reapper so the new dict values are fetched */
2796/* This is a nasty hack and should be removed once dict object can emit signals */
2797void ladish_graph_trick_dicts(ladish_graph_handle graph_handle)
2798{
2799  struct list_head * node_ptr;
2800  struct ladish_graph_connection * connection_ptr;
2801  struct ladish_graph_client * client_ptr;
2802  struct ladish_graph_port * port_ptr;
2803
2804  list_for_each(node_ptr, &graph_ptr->connections)
2805  {
2806    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2807    if (!connection_ptr->hidden)
2808    {
2809      graph_ptr->graph_version++;
2810      ladish_graph_emit_ports_disconnected(graph_ptr, connection_ptr);
2811    }
2812  }
2813
2814  list_for_each(node_ptr, &graph_ptr->ports)
2815  {
2816    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2817
2818    if (!port_ptr->hidden)
2819    {
2820      graph_ptr->graph_version++;
2821      ladish_graph_emit_port_disappeared(graph_ptr, port_ptr);
2822    }
2823  }
2824
2825  list_for_each(node_ptr, &graph_ptr->clients)
2826  {
2827    client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
2828
2829    if (!client_ptr->hidden)
2830    {
2831      graph_ptr->graph_version++;
2832      ladish_graph_emit_client_disappeared(graph_ptr, client_ptr);
2833      graph_ptr->graph_version++;
2834      ladish_graph_emit_client_appeared(graph_ptr, client_ptr);
2835    }
2836  }
2837
2838  list_for_each(node_ptr, &graph_ptr->ports)
2839  {
2840    port_ptr = list_entry(node_ptr, struct ladish_graph_port, siblings_graph);
2841
2842    if (!port_ptr->hidden)
2843    {
2844      graph_ptr->graph_version++;
2845      ladish_graph_emit_port_appeared(graph_ptr, port_ptr);
2846    }
2847  }
2848
2849  list_for_each(node_ptr, &graph_ptr->connections)
2850  {
2851    connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
2852    if (!connection_ptr->hidden)
2853    {
2854      graph_ptr->graph_version++;
2855      ladish_graph_emit_ports_connected(graph_ptr, connection_ptr);
2856    }
2857  }
2858}
2859
2860#undef graph_ptr
2861#define graph_ptr ((struct ladish_graph *)context)
2862
2863static
2864bool
2865ladish_graph_copy_client_begin_callback(
2866  void * context,
2867  ladish_graph_handle graph_handle,
2868  bool hidden,
2869  ladish_client_handle client_handle,
2870  const char * client_name,
2871  void ** client_iteration_context_ptr_ptr)
2872{
2873  ladish_client_handle copy;
2874
2875  if (!ladish_client_create_copy(client_handle, &copy))
2876  {
2877    return false;
2878  }
2879
2880  if (!ladish_graph_add_client(context, copy, client_name, false))
2881  {
2882    ladish_client_destroy(copy);
2883    return false;
2884  }
2885
2886  *client_iteration_context_ptr_ptr = copy;
2887
2888  return true;
2889}
2890
2891static
2892bool
2893ladish_graph_copy_port_callback(
2894  void * context,
2895  ladish_graph_handle graph_handle,
2896  bool hidden,
2897  void * client_iteration_context_ptr,
2898  ladish_client_handle client_handle,
2899  const char * client_name,
2900  ladish_port_handle port_handle,
2901  const char * port_name,
2902  uint32_t port_type,
2903  uint32_t port_flags)
2904{
2905  ladish_port_handle copy;
2906
2907  if (!ladish_port_create_copy(port_handle, &copy))
2908  {
2909    return false;
2910  }
2911
2912  if (!ladish_graph_add_port(context, client_iteration_context_ptr, copy, port_name, port_type, port_flags, true))
2913  {
2914    ladish_port_destroy(copy);
2915    return false;
2916  }
2917
2918  return true;
2919}
2920
2921#undef graph_ptr
2922
2923bool ladish_graph_copy(ladish_graph_handle src, ladish_graph_handle dest)
2924{
2925  return ladish_graph_iterate_nodes(
2926    src,
2927    dest,
2928    ladish_graph_copy_client_begin_callback,
2929    ladish_graph_copy_port_callback,
2930    NULL);
2931}
2932
2933METHOD_ARGS_BEGIN(GetAllPorts, "Get all ports")
2934  METHOD_ARG_DESCRIBE_IN("ports_list", "as", "List of all ports")
2935METHOD_ARGS_END
2936
2937METHOD_ARGS_BEGIN(GetGraph, "Get whole graph")
2938METHOD_ARG_DESCRIBE_IN("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Known graph version")
2939  METHOD_ARG_DESCRIBE_OUT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, "Current graph version")
2940  METHOD_ARG_DESCRIBE_OUT("clients_and_ports", "a(tsa(tsuu))", "Clients and their ports")
2941  METHOD_ARG_DESCRIBE_OUT("connections", "a(tstststst)", "Connections array")
2942METHOD_ARGS_END
2943
2944METHOD_ARGS_BEGIN(ConnectPortsByName, "Connect ports")
2945  METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2946  METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2947  METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2948  METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2949METHOD_ARGS_END
2950
2951METHOD_ARGS_BEGIN(ConnectPortsByID, "Connect ports")
2952  METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2953  METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2954METHOD_ARGS_END
2955
2956METHOD_ARGS_BEGIN(DisconnectPortsByName, "Disconnect ports")
2957  METHOD_ARG_DESCRIBE_IN("client1_name", DBUS_TYPE_STRING_AS_STRING, "name first port client")
2958  METHOD_ARG_DESCRIBE_IN("port1_name", DBUS_TYPE_STRING_AS_STRING, "name of first port")
2959  METHOD_ARG_DESCRIBE_IN("client2_name", DBUS_TYPE_STRING_AS_STRING, "name second port client")
2960  METHOD_ARG_DESCRIBE_IN("port2_name", DBUS_TYPE_STRING_AS_STRING, "name of second port")
2961METHOD_ARGS_END
2962
2963METHOD_ARGS_BEGIN(DisconnectPortsByID, "Disconnect ports")
2964  METHOD_ARG_DESCRIBE_IN("port1_id", DBUS_TYPE_UINT64_AS_STRING, "id of first port")
2965  METHOD_ARG_DESCRIBE_IN("port2_id", DBUS_TYPE_UINT64_AS_STRING, "if of second port")
2966METHOD_ARGS_END
2967
2968METHOD_ARGS_BEGIN(DisconnectPortsByConnectionID, "Disconnect ports")
2969  METHOD_ARG_DESCRIBE_IN("connection_id", DBUS_TYPE_UINT64_AS_STRING, "id of connection to disconnect")
2970METHOD_ARGS_END
2971
2972METHOD_ARGS_BEGIN(GetClientPID, "get process id of client")
2973  METHOD_ARG_DESCRIBE_IN("client_id", DBUS_TYPE_UINT64_AS_STRING, "id of client")
2974  METHOD_ARG_DESCRIBE_OUT("process_id", DBUS_TYPE_INT64_AS_STRING, "pid of client")
2975METHOD_ARGS_END
2976
2977METHODS_BEGIN
2978  METHOD_DESCRIBE(GetAllPorts, get_all_ports)
2979  METHOD_DESCRIBE(GetGraph, get_graph)
2980  METHOD_DESCRIBE(ConnectPortsByName, connect_ports_by_name)
2981  METHOD_DESCRIBE(ConnectPortsByID, connect_ports_by_id)
2982  METHOD_DESCRIBE(DisconnectPortsByName, disconnect_ports_by_name)
2983  METHOD_DESCRIBE(DisconnectPortsByID, disconnect_ports_by_id)
2984  METHOD_DESCRIBE(DisconnectPortsByConnectionID, disconnect_ports_by_connection_id)
2985  METHOD_DESCRIBE(GetClientPID, get_client_pid)
2986METHODS_END
2987
2988SIGNAL_ARGS_BEGIN(GraphChanged, "")
2989  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2990SIGNAL_ARGS_END
2991
2992SIGNAL_ARGS_BEGIN(ClientAppeared, "")
2993  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
2994  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
2995  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
2996SIGNAL_ARGS_END
2997
2998SIGNAL_ARGS_BEGIN(ClientDisappeared, "")
2999  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
3000  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
3001  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
3002SIGNAL_ARGS_END
3003
3004SIGNAL_ARGS_BEGIN(PortAppeared, "")
3005  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
3006  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
3007  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
3008  SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
3009  SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
3010  SIGNAL_ARG_DESCRIBE("port_flags", DBUS_TYPE_UINT32_AS_STRING, "")
3011  SIGNAL_ARG_DESCRIBE("port_type", DBUS_TYPE_UINT32_AS_STRING, "")
3012SIGNAL_ARGS_END
3013
3014SIGNAL_ARGS_BEGIN(PortDisappeared, "")
3015  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
3016  SIGNAL_ARG_DESCRIBE("client_id", DBUS_TYPE_UINT64_AS_STRING, "")
3017  SIGNAL_ARG_DESCRIBE("client_name", DBUS_TYPE_STRING_AS_STRING, "")
3018  SIGNAL_ARG_DESCRIBE("port_id", DBUS_TYPE_UINT64_AS_STRING, "")
3019  SIGNAL_ARG_DESCRIBE("port_name", DBUS_TYPE_STRING_AS_STRING, "")
3020SIGNAL_ARGS_END
3021
3022SIGNAL_ARGS_BEGIN(PortsConnected, "")
3023  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
3024  SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
3025  SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
3026  SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
3027  SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
3028  SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
3029  SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
3030  SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
3031  SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
3032  SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
3033SIGNAL_ARGS_END
3034
3035SIGNAL_ARGS_BEGIN(PortsDisconnected, "")
3036  SIGNAL_ARG_DESCRIBE("new_graph_version", DBUS_TYPE_UINT64_AS_STRING, "")
3037  SIGNAL_ARG_DESCRIBE("client1_id", DBUS_TYPE_UINT64_AS_STRING, "")
3038  SIGNAL_ARG_DESCRIBE("client1_name", DBUS_TYPE_STRING_AS_STRING, "")
3039  SIGNAL_ARG_DESCRIBE("port1_id", DBUS_TYPE_UINT64_AS_STRING, "")
3040  SIGNAL_ARG_DESCRIBE("port1_name", DBUS_TYPE_STRING_AS_STRING, "")
3041  SIGNAL_ARG_DESCRIBE("client2_id", DBUS_TYPE_UINT64_AS_STRING, "")
3042  SIGNAL_ARG_DESCRIBE("client2_name", DBUS_TYPE_STRING_AS_STRING, "")
3043  SIGNAL_ARG_DESCRIBE("port2_id", DBUS_TYPE_UINT64_AS_STRING, "")
3044  SIGNAL_ARG_DESCRIBE("port2_name", DBUS_TYPE_STRING_AS_STRING, "")
3045  SIGNAL_ARG_DESCRIBE("connection_id", DBUS_TYPE_UINT64_AS_STRING, "")
3046SIGNAL_ARGS_END
3047
3048SIGNALS_BEGIN
3049  SIGNAL_DESCRIBE(GraphChanged)
3050  SIGNAL_DESCRIBE(ClientAppeared)
3051  SIGNAL_DESCRIBE(ClientDisappeared)
3052  SIGNAL_DESCRIBE(PortAppeared)
3053  SIGNAL_DESCRIBE(PortDisappeared)
3054  SIGNAL_DESCRIBE(PortsConnected)
3055  SIGNAL_DESCRIBE(PortsDisconnected)
3056SIGNALS_END
3057
3058INTERFACE_BEGIN(g_interface_patchbay, JACKDBUS_IFACE_PATCHBAY)
3059  INTERFACE_DEFAULT_HANDLER
3060  INTERFACE_EXPOSE_METHODS
3061  INTERFACE_EXPOSE_SIGNALS
3062INTERFACE_END
Note: See TracBrowser for help on using the browser.