ladishd: clear project even if room project state is 'unloaded'. Fix for #117
[ladish.git] / proxies / graph_proxy.c
blob75f17e7d9a305fd22066de4123ed48230592b6c3
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009,2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation graph object that is backed through D-Bus
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "graph_proxy.h"
29 struct monitor
31 struct list_head siblings;
32 void * context;
33 void (* clear)(void * context);
34 void (* client_appeared)(void * context, uint64_t id, const char * name);
35 void (* client_renamed)(void * context, uint64_t client_id, const char * old_client_name, const char * new_client_name);
36 void (* client_disappeared)(void * context, uint64_t id);
37 void (* port_appeared)(void * context, uint64_t client_id, uint64_t port_id, const char * port_name, bool is_input, bool is_terminal, bool is_midi);
38 void (* port_renamed)(void * context, uint64_t client_id, uint64_t port_id, const char * old_port_name, const char * new_port_name);
39 void (* port_disappeared)(void * context, uint64_t client_id, uint64_t port_id);
40 void (* ports_connected)(void * context, uint64_t client1_id, uint64_t port1_id, uint64_t client2_id, uint64_t port2_id);
41 void (* ports_disconnected)(void * context, uint64_t client1_id, uint64_t port1_id, uint64_t client2_id, uint64_t port2_id);
44 struct graph
46 struct list_head monitors;
47 char * service;
48 char * object;
49 uint64_t version;
50 bool active;
51 bool graph_dict_supported;
54 static struct dbus_signal_hook g_signal_hooks[];
56 static void clear(struct graph * graph_ptr)
58 struct list_head * node_ptr;
59 struct monitor * monitor_ptr;
61 list_for_each(node_ptr, &graph_ptr->monitors)
63 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
64 monitor_ptr->clear(monitor_ptr->context);
68 static void client_appeared(struct graph * graph_ptr, uint64_t id, const char * name)
70 struct list_head * node_ptr;
71 struct monitor * monitor_ptr;
73 list_for_each(node_ptr, &graph_ptr->monitors)
75 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
76 monitor_ptr->client_appeared(monitor_ptr->context, id, name);
80 static
81 void
82 client_renamed(
83 struct graph * graph_ptr,
84 uint64_t client_id,
85 const char * old_client_name,
86 const char * new_client_name)
88 struct list_head * node_ptr;
89 struct monitor * monitor_ptr;
91 list_for_each(node_ptr, &graph_ptr->monitors)
93 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
94 if (monitor_ptr->client_renamed != NULL)
96 monitor_ptr->client_renamed(monitor_ptr->context, client_id, old_client_name, new_client_name);
101 static void client_disappeared(struct graph * graph_ptr, uint64_t id)
103 struct list_head * node_ptr;
104 struct monitor * monitor_ptr;
106 list_for_each(node_ptr, &graph_ptr->monitors)
108 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
109 monitor_ptr->client_disappeared(monitor_ptr->context, id);
113 static
114 void
115 port_appeared(
116 struct graph * graph_ptr,
117 uint64_t client_id,
118 uint64_t port_id,
119 const char * port_name,
120 uint32_t port_flags,
121 uint32_t port_type)
123 struct list_head * node_ptr;
124 struct monitor * monitor_ptr;
125 bool is_input;
126 bool is_terminal;
127 bool is_midi;
129 if (port_type != JACKDBUS_PORT_TYPE_AUDIO && port_type != JACKDBUS_PORT_TYPE_MIDI)
131 log_error("Unknown JACK D-Bus port type %d", (unsigned int)port_type);
132 return;
135 is_input = port_flags & JACKDBUS_PORT_FLAG_INPUT;
136 is_terminal = port_flags & JACKDBUS_PORT_FLAG_TERMINAL;
137 is_midi = port_type == JACKDBUS_PORT_TYPE_MIDI;
139 list_for_each(node_ptr, &graph_ptr->monitors)
141 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
142 monitor_ptr->port_appeared(monitor_ptr->context, client_id, port_id, port_name, is_input, is_terminal, is_midi);
146 static
147 void
148 port_disappeared(
149 struct graph * graph_ptr,
150 uint64_t client_id,
151 uint64_t port_id)
153 struct list_head * node_ptr;
154 struct monitor * monitor_ptr;
156 list_for_each(node_ptr, &graph_ptr->monitors)
158 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
159 monitor_ptr->port_disappeared(monitor_ptr->context, client_id, port_id);
163 static
164 void
165 port_renamed(
166 struct graph * graph_ptr,
167 uint64_t client_id,
168 uint64_t port_id,
169 const char * old_port_name,
170 const char * new_port_name)
172 struct list_head * node_ptr;
173 struct monitor * monitor_ptr;
175 list_for_each(node_ptr, &graph_ptr->monitors)
177 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
178 monitor_ptr->port_renamed(monitor_ptr->context, client_id, port_id, old_port_name, new_port_name);
182 static
183 void
184 ports_connected(
185 struct graph * graph_ptr,
186 uint64_t client1_id,
187 uint64_t port1_id,
188 uint64_t client2_id,
189 uint64_t port2_id)
191 struct list_head * node_ptr;
192 struct monitor * monitor_ptr;
194 list_for_each(node_ptr, &graph_ptr->monitors)
196 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
197 monitor_ptr->ports_connected(monitor_ptr->context, client1_id, port1_id, client2_id, port2_id);
201 static
202 void
203 ports_disconnected(
204 struct graph * graph_ptr,
205 uint64_t client1_id,
206 uint64_t port1_id,
207 uint64_t client2_id,
208 uint64_t port2_id)
210 struct list_head * node_ptr;
211 struct monitor * monitor_ptr;
213 list_for_each(node_ptr, &graph_ptr->monitors)
215 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
216 monitor_ptr->ports_disconnected(monitor_ptr->context, client1_id, port1_id, client2_id, port2_id);
220 static void refresh_internal(struct graph * graph_ptr, bool force)
222 DBusMessage* reply_ptr;
223 DBusMessageIter iter;
224 dbus_uint64_t version;
225 const char * reply_signature;
226 DBusMessageIter clients_array_iter;
227 DBusMessageIter client_struct_iter;
228 DBusMessageIter ports_array_iter;
229 DBusMessageIter port_struct_iter;
230 DBusMessageIter connections_array_iter;
231 DBusMessageIter connection_struct_iter;
232 dbus_uint64_t client_id;
233 const char *client_name;
234 dbus_uint64_t port_id;
235 const char *port_name;
236 dbus_uint32_t port_flags;
237 dbus_uint32_t port_type;
238 dbus_uint64_t client2_id;
239 const char *client2_name;
240 dbus_uint64_t port2_id;
241 const char *port2_name;
242 dbus_uint64_t connection_id;
244 log_info("refresh_internal() called");
246 if (force)
248 version = 0; // workaround module split/join stupidity
250 else
252 version = graph_ptr->version;
255 if (!dbus_call(graph_ptr->service, graph_ptr->object, JACKDBUS_IFACE_PATCHBAY, "GetGraph", "t", &version, NULL, &reply_ptr))
257 log_error("GetGraph() failed.");
258 return;
261 reply_signature = dbus_message_get_signature(reply_ptr);
263 if (strcmp(reply_signature, "ta(tsa(tsuu))a(tstststst)") != 0)
265 log_error("GetGraph() reply signature mismatch. '%s'", reply_signature);
266 goto unref;
269 dbus_message_iter_init(reply_ptr, &iter);
271 //log_info_msg("version " + (char)dbus_message_iter_get_arg_type(&iter));
272 dbus_message_iter_get_basic(&iter, &version);
273 dbus_message_iter_next(&iter);
275 if (!force && version <= graph_ptr->version)
277 goto unref;
280 clear(graph_ptr);
282 //log_info("got new graph version %llu", (unsigned long long)version);
283 graph_ptr->version = version;
285 //info_msg((std::string)"clients " + (char)dbus_message_iter_get_arg_type(&iter));
287 for (dbus_message_iter_recurse(&iter, &clients_array_iter);
288 dbus_message_iter_get_arg_type(&clients_array_iter) != DBUS_TYPE_INVALID;
289 dbus_message_iter_next(&clients_array_iter))
291 //info_msg((std::string)"a client " + (char)dbus_message_iter_get_arg_type(&clients_array_iter));
292 dbus_message_iter_recurse(&clients_array_iter, &client_struct_iter);
294 dbus_message_iter_get_basic(&client_struct_iter, &client_id);
295 dbus_message_iter_next(&client_struct_iter);
297 dbus_message_iter_get_basic(&client_struct_iter, &client_name);
298 dbus_message_iter_next(&client_struct_iter);
300 //info_msg((std::string)"client '" + client_name + "'");
302 client_appeared(graph_ptr, client_id, client_name);
304 for (dbus_message_iter_recurse(&client_struct_iter, &ports_array_iter);
305 dbus_message_iter_get_arg_type(&ports_array_iter) != DBUS_TYPE_INVALID;
306 dbus_message_iter_next(&ports_array_iter))
308 //info_msg((std::string)"a port " + (char)dbus_message_iter_get_arg_type(&ports_array_iter));
309 dbus_message_iter_recurse(&ports_array_iter, &port_struct_iter);
311 dbus_message_iter_get_basic(&port_struct_iter, &port_id);
312 dbus_message_iter_next(&port_struct_iter);
314 dbus_message_iter_get_basic(&port_struct_iter, &port_name);
315 dbus_message_iter_next(&port_struct_iter);
317 dbus_message_iter_get_basic(&port_struct_iter, &port_flags);
318 dbus_message_iter_next(&port_struct_iter);
320 dbus_message_iter_get_basic(&port_struct_iter, &port_type);
321 dbus_message_iter_next(&port_struct_iter);
323 //info_msg((std::string)"port: " + port_name);
325 port_appeared(graph_ptr, client_id, port_id, port_name, port_flags, port_type);
328 dbus_message_iter_next(&client_struct_iter);
331 dbus_message_iter_next(&iter);
333 for (dbus_message_iter_recurse(&iter, &connections_array_iter);
334 dbus_message_iter_get_arg_type(&connections_array_iter) != DBUS_TYPE_INVALID;
335 dbus_message_iter_next(&connections_array_iter))
337 //info_msg((std::string)"a connection " + (char)dbus_message_iter_get_arg_type(&connections_array_iter));
338 dbus_message_iter_recurse(&connections_array_iter, &connection_struct_iter);
340 dbus_message_iter_get_basic(&connection_struct_iter, &client_id);
341 dbus_message_iter_next(&connection_struct_iter);
343 dbus_message_iter_get_basic(&connection_struct_iter, &client_name);
344 dbus_message_iter_next(&connection_struct_iter);
346 dbus_message_iter_get_basic(&connection_struct_iter, &port_id);
347 dbus_message_iter_next(&connection_struct_iter);
349 dbus_message_iter_get_basic(&connection_struct_iter, &port_name);
350 dbus_message_iter_next(&connection_struct_iter);
352 dbus_message_iter_get_basic(&connection_struct_iter, &client2_id);
353 dbus_message_iter_next(&connection_struct_iter);
355 dbus_message_iter_get_basic(&connection_struct_iter, &client2_name);
356 dbus_message_iter_next(&connection_struct_iter);
358 dbus_message_iter_get_basic(&connection_struct_iter, &port2_id);
359 dbus_message_iter_next(&connection_struct_iter);
361 dbus_message_iter_get_basic(&connection_struct_iter, &port2_name);
362 dbus_message_iter_next(&connection_struct_iter);
364 dbus_message_iter_get_basic(&connection_struct_iter, &connection_id);
365 dbus_message_iter_next(&connection_struct_iter);
367 //info_msg(str(boost::format("connection(%llu) %s(%llu):%s(%llu) <-> %s(%llu):%s(%llu)") %
368 // connection_id %
369 // client_name %
370 // client_id %
371 // port_name %
372 // port_id %
373 // client2_name %
374 // client2_id %
375 // port2_name %
376 // port2_id));
378 ports_connected(graph_ptr, client_id, port_id, client2_id, port2_id);
381 unref:
382 dbus_message_unref(reply_ptr);
385 bool
386 graph_proxy_create(
387 const char * service,
388 const char * object,
389 bool graph_dict_supported,
390 graph_proxy_handle * graph_proxy_handle_ptr)
392 struct graph * graph_ptr;
394 graph_ptr = malloc(sizeof(struct graph));
395 if (graph_ptr == NULL)
397 log_error("malloc() failed to allocate struct graph");
398 goto fail;
401 graph_ptr->service = strdup(service);
402 if (graph_ptr->service == NULL)
404 log_error("strdup() failed too duplicate service name '%s'", service);
405 goto free_graph;
408 graph_ptr->object = strdup(object);
409 if (graph_ptr->object == NULL)
411 log_error("strdup() failed too duplicate object name '%s'", object);
412 goto free_service;
415 INIT_LIST_HEAD(&graph_ptr->monitors);
417 graph_ptr->version = 0;
418 graph_ptr->active = false;
420 graph_ptr->graph_dict_supported = graph_dict_supported;
422 *graph_proxy_handle_ptr = (graph_proxy_handle)graph_ptr;
424 return true;
426 free_service:
427 free(graph_ptr->service);
429 free_graph:
430 free(graph_ptr);
432 fail:
433 return false;
436 #define graph_ptr ((struct graph *)graph)
438 const char * graph_proxy_get_service(graph_proxy_handle graph)
440 return graph_ptr->service;
443 const char * graph_proxy_get_object(graph_proxy_handle graph)
445 return graph_ptr->object;
448 void
449 graph_proxy_destroy(
450 graph_proxy_handle graph)
452 ASSERT(list_empty(&graph_ptr->monitors));
454 if (graph_ptr->active)
456 dbus_unregister_object_signal_hooks(
457 g_dbus_connection,
458 graph_ptr->service,
459 graph_ptr->object,
460 JACKDBUS_IFACE_PATCHBAY);
463 free(graph_ptr->object);
464 free(graph_ptr->service);
465 free(graph_ptr);
468 bool
469 graph_proxy_activate(
470 graph_proxy_handle graph)
472 if (list_empty(&graph_ptr->monitors))
474 log_error("no monitors to activate");
475 return false;
478 if (graph_ptr->active)
480 log_error("graph already active");
481 return false;
484 if (!dbus_register_object_signal_hooks(
485 g_dbus_connection,
486 graph_ptr->service,
487 graph_ptr->object,
488 JACKDBUS_IFACE_PATCHBAY,
489 graph_ptr,
490 g_signal_hooks))
492 return false;
495 graph_ptr->active = true;
497 refresh_internal(graph_ptr, true);
499 return true;
502 bool
503 graph_proxy_attach(
504 graph_proxy_handle graph,
505 void * context,
506 void (* clear)(void * context),
507 void (* client_appeared)(void * context, uint64_t id, const char * name),
508 void (* client_renamed)(void * context, uint64_t client_id, const char * old_client_name, const char * new_client_name),
509 void (* client_disappeared)(void * context, uint64_t id),
510 void (* port_appeared)(void * context, uint64_t client_id, uint64_t port_id, const char * port_name, bool is_input, bool is_terminal, bool is_midi),
511 void (* port_renamed)(void * context, uint64_t client_id, uint64_t port_id, const char * old_port_name, const char * new_port_name),
512 void (* port_disappeared)(void * context, uint64_t client_id, uint64_t port_id),
513 void (* ports_connected)(void * context, uint64_t client1_id, uint64_t port1_id, uint64_t client2_id, uint64_t port2_id),
514 void (* ports_disconnected)(void * context, uint64_t client1_id, uint64_t port1_id, uint64_t client2_id, uint64_t port2_id))
516 struct monitor * monitor_ptr;
518 if (graph_ptr->active)
520 return false;
523 monitor_ptr = malloc(sizeof(struct monitor));
524 if (monitor_ptr == NULL)
526 log_error("malloc() failed to allocate struct monitor");
527 return false;
530 monitor_ptr->context = context;
531 monitor_ptr->clear = clear;
532 monitor_ptr->client_appeared = client_appeared;
533 monitor_ptr->client_renamed = client_renamed;
534 monitor_ptr->client_disappeared = client_disappeared;
535 monitor_ptr->port_appeared = port_appeared;
536 monitor_ptr->port_renamed = port_renamed;
537 monitor_ptr->port_disappeared = port_disappeared;
538 monitor_ptr->ports_connected = ports_connected;
539 monitor_ptr->ports_disconnected = ports_disconnected;
541 list_add_tail(&monitor_ptr->siblings, &graph_ptr->monitors);
543 return true;
546 void
547 graph_proxy_detach(
548 graph_proxy_handle graph,
549 void * context)
551 struct list_head * node_ptr;
552 struct monitor * monitor_ptr;
554 list_for_each(node_ptr, &graph_ptr->monitors)
556 monitor_ptr = list_entry(node_ptr, struct monitor, siblings);
557 if (monitor_ptr->context == context)
559 list_del(&monitor_ptr->siblings);
560 free(monitor_ptr);
561 return;
565 ASSERT(false);
568 bool
569 graph_proxy_connect_ports(
570 graph_proxy_handle graph,
571 uint64_t port1_id,
572 uint64_t port2_id)
574 if (!dbus_call(graph_ptr->service, graph_ptr->object, JACKDBUS_IFACE_PATCHBAY, "ConnectPortsByID", "tt", &port1_id, &port2_id, ""))
576 log_error("ConnectPortsByID() failed.");
577 return false;
580 return true;
583 bool
584 graph_proxy_disconnect_ports(
585 graph_proxy_handle graph,
586 uint64_t port1_id,
587 uint64_t port2_id)
589 if (!dbus_call(graph_ptr->service, graph_ptr->object, JACKDBUS_IFACE_PATCHBAY, "DisconnectPortsByID", "tt", &port1_id, &port2_id, ""))
591 log_error("DisconnectPortsByID() failed.");
592 return false;
595 return true;
598 static void on_client_appeared(void * graph, DBusMessage * message_ptr)
600 dbus_uint64_t new_graph_version;
601 dbus_uint64_t client_id;
602 const char * client_name;
604 if (!dbus_message_get_args(
605 message_ptr,
606 &g_dbus_error,
607 DBUS_TYPE_UINT64, &new_graph_version,
608 DBUS_TYPE_UINT64, &client_id,
609 DBUS_TYPE_STRING, &client_name,
610 DBUS_TYPE_INVALID))
612 log_error("dbus_message_get_args() failed to extract ClientAppeared signal arguments (%s)", g_dbus_error.message);
613 dbus_error_free(&g_dbus_error);
614 return;
617 //log_info("ClientAppeared, %s(%llu), graph %llu", client_name, client_id, new_graph_version);
619 if (new_graph_version > graph_ptr->version)
621 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
622 graph_ptr->version = new_graph_version;
623 client_appeared(graph_ptr, client_id, client_name);
627 static void on_client_renamed(void * graph, DBusMessage * message_ptr)
629 dbus_uint64_t new_graph_version;
630 dbus_uint64_t client_id;
631 const char * old_client_name;
632 const char * new_client_name;
634 if (!dbus_message_get_args(
635 message_ptr,
636 &g_dbus_error,
637 DBUS_TYPE_UINT64, &new_graph_version,
638 DBUS_TYPE_UINT64, &client_id,
639 DBUS_TYPE_STRING, &old_client_name,
640 DBUS_TYPE_STRING, &new_client_name,
641 DBUS_TYPE_INVALID))
643 log_error("dbus_message_get_args() failed to extract ClientRenamed signal arguments (%s)", g_dbus_error.message);
644 dbus_error_free(&g_dbus_error);
645 return;
648 if (new_graph_version > graph_ptr->version)
650 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
651 graph_ptr->version = new_graph_version;
652 client_renamed(graph_ptr, client_id, old_client_name, new_client_name);
656 static void on_client_disappeared(void * graph, DBusMessage * message_ptr)
658 dbus_uint64_t new_graph_version;
659 dbus_uint64_t client_id;
660 const char * client_name;
662 if (!dbus_message_get_args(
663 message_ptr,
664 &g_dbus_error,
665 DBUS_TYPE_UINT64, &new_graph_version,
666 DBUS_TYPE_UINT64, &client_id,
667 DBUS_TYPE_STRING, &client_name,
668 DBUS_TYPE_INVALID))
670 log_error("dbus_message_get_args() failed to extract ClientDisappeared signal arguments (%s)", g_dbus_error.message);
671 dbus_error_free(&g_dbus_error);
672 return;
675 //log_info("ClientDisappeared, %s(%llu)", client_name, client_id);
677 if (new_graph_version > graph_ptr->version)
679 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
680 graph_ptr->version = new_graph_version;
681 client_disappeared(graph_ptr, client_id);
685 static void on_port_appeared(void * graph, DBusMessage * message_ptr)
687 dbus_uint64_t new_graph_version;
688 dbus_uint64_t client_id;
689 const char * client_name;
690 dbus_uint64_t port_id;
691 const char * port_name;
692 dbus_uint32_t port_flags;
693 dbus_uint32_t port_type;
695 if (!dbus_message_get_args(
696 message_ptr,
697 &g_dbus_error,
698 DBUS_TYPE_UINT64, &new_graph_version,
699 DBUS_TYPE_UINT64, &client_id,
700 DBUS_TYPE_STRING, &client_name,
701 DBUS_TYPE_UINT64, &port_id,
702 DBUS_TYPE_STRING, &port_name,
703 DBUS_TYPE_UINT32, &port_flags,
704 DBUS_TYPE_UINT32, &port_type,
705 DBUS_TYPE_INVALID))
707 log_error("dbus_message_get_args() failed to extract PortAppeared signal arguments (%s)", g_dbus_error.message);
708 dbus_error_free(&g_dbus_error);
709 return;
712 //me->info_msg(str(boost::format("PortAppeared, %s(%llu):%s(%llu), %lu, %lu") % client_name % client_id % port_name % port_id % port_flags % port_type));
714 if (new_graph_version > graph_ptr->version)
716 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
717 graph_ptr->version = new_graph_version;
718 port_appeared(graph_ptr, client_id, port_id, port_name, port_flags, port_type);
722 static void on_port_renamed(void * graph, DBusMessage * message_ptr)
724 dbus_uint64_t new_graph_version;
725 dbus_uint64_t client_id;
726 const char * client_name;
727 dbus_uint64_t port_id;
728 const char * old_port_name;
729 const char * new_port_name;
731 if (!dbus_message_get_args(
732 message_ptr,
733 &g_dbus_error,
734 DBUS_TYPE_UINT64, &new_graph_version,
735 DBUS_TYPE_UINT64, &client_id,
736 DBUS_TYPE_STRING, &client_name,
737 DBUS_TYPE_UINT64, &port_id,
738 DBUS_TYPE_STRING, &old_port_name,
739 DBUS_TYPE_STRING, &new_port_name,
740 DBUS_TYPE_INVALID))
742 log_error("dbus_message_get_args() failed to extract PortRenamed signal arguments (%s)", g_dbus_error.message);
743 dbus_error_free(&g_dbus_error);
744 return;
747 if (new_graph_version > graph_ptr->version)
749 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
750 graph_ptr->version = new_graph_version;
751 port_renamed(graph_ptr, client_id, port_id, old_port_name, new_port_name);
755 static void on_port_disappeared(void * graph, DBusMessage * message_ptr)
757 dbus_uint64_t new_graph_version;
758 dbus_uint64_t client_id;
759 const char * client_name;
760 dbus_uint64_t port_id;
761 const char * port_name;
763 if (!dbus_message_get_args(
764 message_ptr,
765 &g_dbus_error,
766 DBUS_TYPE_UINT64, &new_graph_version,
767 DBUS_TYPE_UINT64, &client_id,
768 DBUS_TYPE_STRING, &client_name,
769 DBUS_TYPE_UINT64, &port_id,
770 DBUS_TYPE_STRING, &port_name,
771 DBUS_TYPE_INVALID))
773 log_error("dbus_message_get_args() failed to extract PortDisappeared signal arguments (%s)", g_dbus_error.message);
774 dbus_error_free(&g_dbus_error);
775 return;
778 //me->info_msg(str(boost::format("PortDisappeared, %s(%llu):%s(%llu)") % client_name % client_id % port_name % port_id));
780 if (new_graph_version > graph_ptr->version)
782 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
783 graph_ptr->version = new_graph_version;
784 port_disappeared(graph_ptr, client_id, port_id);
788 static void on_ports_connected(void * graph, DBusMessage * message_ptr)
790 dbus_uint64_t new_graph_version;
791 dbus_uint64_t client_id;
792 const char * client_name;
793 dbus_uint64_t port_id;
794 const char * port_name;
795 dbus_uint64_t client2_id;
796 const char * client2_name;
797 dbus_uint64_t port2_id;
798 const char * port2_name;
799 dbus_uint64_t connection_id;
801 if (!dbus_message_get_args(
802 message_ptr,
803 &g_dbus_error,
804 DBUS_TYPE_UINT64, &new_graph_version,
805 DBUS_TYPE_UINT64, &client_id,
806 DBUS_TYPE_STRING, &client_name,
807 DBUS_TYPE_UINT64, &port_id,
808 DBUS_TYPE_STRING, &port_name,
809 DBUS_TYPE_UINT64, &client2_id,
810 DBUS_TYPE_STRING, &client2_name,
811 DBUS_TYPE_UINT64, &port2_id,
812 DBUS_TYPE_STRING, &port2_name,
813 DBUS_TYPE_UINT64, &connection_id,
814 DBUS_TYPE_INVALID))
816 log_error("dbus_message_get_args() failed to extract PortsConnected signal arguments (%s)", g_dbus_error.message);
817 dbus_error_free(&g_dbus_error);
818 return;
821 if (new_graph_version > graph_ptr->version)
823 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
824 graph_ptr->version = new_graph_version;
825 ports_connected(graph_ptr, client_id, port_id, client2_id, port2_id);
829 static void on_ports_disconnected(void * graph, DBusMessage * message_ptr)
831 dbus_uint64_t new_graph_version;
832 dbus_uint64_t client_id;
833 const char * client_name;
834 dbus_uint64_t port_id;
835 const char * port_name;
836 dbus_uint64_t client2_id;
837 const char * client2_name;
838 dbus_uint64_t port2_id;
839 const char * port2_name;
840 dbus_uint64_t connection_id;
842 if (!dbus_message_get_args(
843 message_ptr,
844 &g_dbus_error,
845 DBUS_TYPE_UINT64, &new_graph_version,
846 DBUS_TYPE_UINT64, &client_id,
847 DBUS_TYPE_STRING, &client_name,
848 DBUS_TYPE_UINT64, &port_id,
849 DBUS_TYPE_STRING, &port_name,
850 DBUS_TYPE_UINT64, &client2_id,
851 DBUS_TYPE_STRING, &client2_name,
852 DBUS_TYPE_UINT64, &port2_id,
853 DBUS_TYPE_STRING, &port2_name,
854 DBUS_TYPE_UINT64, &connection_id,
855 DBUS_TYPE_INVALID))
857 log_error("dbus_message_get_args() failed to extract PortsConnected signal arguments (%s)", g_dbus_error.message);
858 dbus_error_free(&g_dbus_error);
859 return;
862 if (new_graph_version > graph_ptr->version)
864 //log_info("got new graph version %llu", (unsigned long long)new_graph_version);
865 graph_ptr->version = new_graph_version;
866 ports_disconnected(graph_ptr, client_id, port_id, client2_id, port2_id);
870 bool
871 graph_proxy_dict_entry_set(
872 graph_proxy_handle graph,
873 uint32_t object_type,
874 uint64_t object_id,
875 const char * key,
876 const char * value)
878 if (!graph_ptr->graph_dict_supported)
880 return false;
883 if (!dbus_call(graph_ptr->service, graph_ptr->object, IFACE_GRAPH_DICT, "Set", "utss", &object_type, &object_id, &key, &value, ""))
885 log_error(IFACE_GRAPH_DICT ".Set() failed.");
886 return false;
889 return true;
892 bool
893 graph_proxy_dict_entry_get(
894 graph_proxy_handle graph,
895 uint32_t object_type,
896 uint64_t object_id,
897 const char * key,
898 char ** value_ptr_ptr)
900 DBusMessage * reply_ptr;
901 const char * reply_signature;
902 DBusMessageIter iter;
903 const char * cvalue_ptr;
904 char * value_ptr;
906 if (!graph_ptr->graph_dict_supported)
908 return false;
911 if (!dbus_call(graph_ptr->service, graph_ptr->object, IFACE_GRAPH_DICT, "Get", "uts", &object_type, &object_id, &key, NULL, &reply_ptr))
913 log_error(IFACE_GRAPH_DICT ".Get() failed.");
914 return false;
917 reply_signature = dbus_message_get_signature(reply_ptr);
919 if (strcmp(reply_signature, "s") != 0)
921 log_error("reply signature is '%s' but expected signature is 's'", reply_signature);
922 dbus_message_unref(reply_ptr);
923 return false;
926 dbus_message_iter_init(reply_ptr, &iter);
927 dbus_message_iter_get_basic(&iter, &cvalue_ptr);
928 value_ptr = strdup(cvalue_ptr);
929 dbus_message_unref(reply_ptr);
930 if (value_ptr == NULL)
932 log_error("strdup() failed for dict value");
933 return false;
935 *value_ptr_ptr = value_ptr;
936 return true;
939 bool
940 graph_proxy_dict_entry_drop(
941 graph_proxy_handle graph,
942 uint32_t object_type,
943 uint64_t object_id,
944 const char * key)
946 if (!graph_ptr->graph_dict_supported)
948 return false;
951 if (!dbus_call(graph_ptr->service, graph_ptr->object, IFACE_GRAPH_DICT, "Drop", "uts", &object_type, &object_id, &key, ""))
953 log_error(IFACE_GRAPH_DICT ".Drop() failed.");
954 return false;
957 return true;
960 bool graph_proxy_get_client_pid(graph_proxy_handle graph, uint64_t client_id, pid_t * pid_ptr)
962 int64_t pid;
964 if (!dbus_call(graph_ptr->service, graph_ptr->object, JACKDBUS_IFACE_PATCHBAY, "GetClientPID", "t", &client_id, "x", &pid))
966 log_error("GetClientPID() failed.");
967 return false;
970 *pid_ptr = pid;
972 return true;
975 /* this must be static because it is referenced by the
976 * dbus helper layer when hooks are active */
977 static struct dbus_signal_hook g_signal_hooks[] =
979 {"ClientAppeared", on_client_appeared},
980 {"ClientRenamed", on_client_renamed},
981 {"ClientDisappeared", on_client_disappeared},
982 {"PortAppeared", on_port_appeared},
983 {"PortRenamed", on_port_renamed},
984 {"PortDisappeared", on_port_disappeared},
985 {"PortsConnected", on_ports_connected},
986 {"PortsDisconnected", on_ports_disconnected},
987 {NULL, NULL}