1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the graph virtualizer object
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 "virtualizer.h"
28 #include "../dbus_constants.h"
29 #include "../proxies/a2j_proxy.h"
30 #include "../proxies/jmcore_proxy.h"
32 #include "app_supervisor.h"
33 #include "studio_internal.h"
34 #include "../common/catdup.h"
40 graph_proxy_handle jack_graph_proxy
;
41 ladish_graph_handle jack_graph
;
42 uint64_t system_client_id
;
43 unsigned int our_clients_count
;
46 /* 47c1cd18-7b21-4389-bec4-6e0658e1d6b1 */
47 UUID_DEFINE(g_system_capture_uuid
,0x47,0xC1,0xCD,0x18,0x7B,0x21,0x43,0x89,0xBE,0xC4,0x6E,0x06,0x58,0xE1,0xD6,0xB1);
49 /* b2a0bb06-28d8-4bfe-956e-eb24378f9629 */
50 UUID_DEFINE(g_system_playback_uuid
,0xB2,0xA0,0xBB,0x06,0x28,0xD8,0x4B,0xFE,0x95,0x6E,0xEB,0x24,0x37,0x8F,0x96,0x29);
52 /* be23a242-e2b2-11de-b795-002618af5e42 */
53 UUID_DEFINE(g_a2j_uuid
,0xBE,0x23,0xA2,0x42,0xE2,0xB2,0x11,0xDE,0xB7,0x95,0x00,0x26,0x18,0xAF,0x5E,0x42);
55 struct app_find_context
58 ladish_graph_handle graph
;
59 ladish_app_handle app
;
62 #define app_find_context_ptr ((struct app_find_context *)context)
64 static bool lookup_app_in_supervisor(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
67 ladish_app_handle app
;
69 /* we stop iteration when app is found */
70 ASSERT(app_find_context_ptr
->app
== NULL
&& app_find_context_ptr
->graph
== NULL
);
72 //log_info("checking app supervisor \"%s\" for pid %llu", ladish_app_supervisor_get_name(app_supervisor), (unsigned long long)pid);
74 pid
= app_find_context_ptr
->pid
;
77 app
= ladish_app_supervisor_find_app_by_pid(app_supervisor
, pid
);
81 pid
= (pid_t
)procfs_get_process_parent((unsigned long long)pid
);
85 log_info("parent pid %llu", (unsigned long long)pid
);
92 { /* app not found in current supervisor */
93 return true; /* continue app supervisor iteration */
96 app_find_context_ptr
->app
= app
;
97 app_find_context_ptr
->graph
= graph
;
99 return false; /* stop app supervisor iteration */
102 #undef app_find_context_ptr
104 static ladish_app_handle
ladish_virtualizer_find_app_by_pid(struct virtualizer
* virtualizer_ptr
, pid_t pid
, ladish_graph_handle
* graph_ptr
)
106 struct app_find_context context
;
110 context
.graph
= NULL
;
112 ladish_studio_iterate_virtual_graphs(&context
, lookup_app_in_supervisor
);
114 if (context
.app
== NULL
)
115 { /* app not found */
116 ASSERT(context
.graph
== NULL
);
120 ASSERT(context
.graph
!= NULL
);
121 *graph_ptr
= context
.graph
;
126 struct find_link_port_context
130 ladish_port_handle port
;
131 ladish_graph_handle graph
;
134 #define find_link_port_context_ptr ((struct find_link_port_context *)context)
136 static bool find_link_port_vgraph_callback_by_uuid(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
138 ladish_port_handle port
;
140 port
= ladish_graph_find_port_by_uuid(graph
, find_link_port_context_ptr
->uuid
, true);
143 find_link_port_context_ptr
->port
= port
;
144 find_link_port_context_ptr
->graph
= graph
;
148 return true; /* continue vgraph iteration */
151 static bool find_link_port_vgraph_callback_by_jack_id(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
153 ladish_port_handle port
;
156 log_info("searching link port with jack id %"PRIu64
" in graph %s", find_link_port_context_ptr
->jack_id
, ladish_graph_get_description(graph
));
158 room
= graph
!= g_studio
.studio_graph
;
160 port
= ladish_graph_find_port_by_jack_id(graph
, find_link_port_context_ptr
->jack_id
, room
, !room
);
163 find_link_port_context_ptr
->port
= port
;
164 find_link_port_context_ptr
->graph
= graph
;
168 return true; /* continue vgraph iteration */
171 #undef find_link_port_context_ptr
173 static ladish_graph_handle
find_link_port_vgraph_by_uuid(struct virtualizer
* virtualizer_ptr
, const char * port_name
, ladish_port_handle
* port_ptr
)
175 struct find_link_port_context context
;
177 uuid_parse(port_name
, context
.uuid
);
178 context
.graph
= NULL
;
181 ladish_studio_iterate_virtual_graphs(&context
, find_link_port_vgraph_callback_by_uuid
);
183 if (port_ptr
!= NULL
&& context
.graph
!= NULL
)
185 *port_ptr
= context
.port
;
188 return context
.graph
;
191 static ladish_graph_handle
find_link_port_vgraph_by_jack_id(struct virtualizer
* virtualizer_ptr
, uint64_t jack_id
, ladish_port_handle
* port_ptr
)
193 struct find_link_port_context context
;
195 context
.jack_id
= jack_id
;
196 context
.graph
= NULL
;
199 ladish_studio_iterate_virtual_graphs(&context
, find_link_port_vgraph_callback_by_jack_id
);
201 if (port_ptr
!= NULL
&& context
.graph
!= NULL
)
203 *port_ptr
= context
.port
;
206 return context
.graph
;
212 struct virtualizer
* virtualizer_ptr
,
214 ladish_port_handle
* port_ptr
,
215 ladish_graph_handle
* vgraph_ptr
)
217 ladish_port_handle port
;
218 ladish_client_handle jclient
;
219 ladish_graph_handle vgraph
;
221 port
= ladish_graph_find_port_by_jack_id(virtualizer_ptr
->jack_graph
, port_id
, true, true);
224 log_error("Unknown JACK port with id %"PRIu64
" (dis)connected", port_id
);
228 jclient
= ladish_graph_get_port_client(virtualizer_ptr
->jack_graph
, port
);
231 log_error("Port %"PRIu64
" without jack client was (dis)connected", port_id
);
235 vgraph
= ladish_client_get_vgraph(jclient
);
238 vgraph
= find_link_port_vgraph_by_jack_id(virtualizer_ptr
, port_id
, NULL
);
241 log_error("Cannot find vgraph for (dis)connected jmcore port");
245 log_info("link port found in graph %s", ladish_graph_get_description(vgraph
));
249 *vgraph_ptr
= vgraph
;
253 #define virtualizer_ptr ((struct virtualizer *)context)
255 static void clear(void * context
)
260 static void client_appeared(void * context
, uint64_t id
, const char * jack_name
)
262 ladish_client_handle client
;
263 const char * a2j_name
;
265 ladish_app_handle app
;
269 ladish_graph_handle graph
;
272 log_info("client_appeared(%"PRIu64
", %s)", id
, jack_name
);
274 a2j_name
= a2j_proxy_get_jack_client_name_cached();
275 is_a2j
= a2j_name
!= NULL
&& strcmp(a2j_name
, jack_name
) == 0;
282 if (!graph_proxy_get_client_pid(virtualizer_ptr
->jack_graph_proxy
, id
, &pid
))
284 log_info("client %"PRIu64
" pid is unknown", id
);
288 log_info("client pid is %"PRId64
, (int64_t)pid
);
290 if (pid
!= 0) /* skip internal clients that will match the pending clients in the graph, both have zero pid */
292 jmcore
= pid
== jmcore_proxy_get_pid_cached();
295 log_info("jmcore client appeared");
299 app
= ladish_virtualizer_find_app_by_pid(virtualizer_ptr
, pid
, &graph
);
302 ladish_app_get_uuid(app
, app_uuid
);
303 ASSERT(!uuid_is_null(app_uuid
));
304 name
= ladish_app_get_name(app
);
305 log_info("app name is '%s'", name
);
315 client
= ladish_graph_find_client_by_uuid(virtualizer_ptr
->jack_graph
, g_a2j_uuid
);
319 client
= ladish_graph_find_client_by_app(virtualizer_ptr
->jack_graph
, app_uuid
);
322 log_info("Lookup by app uuid failed, attempting lookup by name '%s'", name
);
323 client
= ladish_graph_find_client_by_name(virtualizer_ptr
->jack_graph
, name
, true);
329 log_info("found existing client");
330 if (ladish_client_get_jack_id(client
) != 0)
332 log_error("Ignoring client with duplicate name '%s' ('%s')", name
, jack_name
);
336 ladish_client_set_jack_id(client
, id
);
337 ladish_graph_show_client(virtualizer_ptr
->jack_graph
, client
);
342 if (!ladish_client_create(is_a2j
? g_a2j_uuid
: NULL
, &client
))
344 log_error("ladish_client_create() failed. Ignoring client %"PRIu64
" (%s)", id
, jack_name
);
348 ladish_client_set_jack_id(client
, id
);
350 if (!ladish_graph_add_client(virtualizer_ptr
->jack_graph
, client
, name
, false))
352 log_error("ladish_graph_add_client() failed to add client %"PRIu64
" (%s) to JACK graph", id
, name
);
353 ladish_client_destroy(client
);
358 if (strcmp(jack_name
, "system") == 0)
360 virtualizer_ptr
->system_client_id
= id
;
365 /* interlink client and app */
366 ladish_app_add_pid(app
, pid
);
367 ladish_client_set_pid(client
, pid
);
368 ladish_client_set_app(client
, app_uuid
);
371 ladish_client_set_vgraph(client
, graph
);
372 virtualizer_ptr
->our_clients_count
++;
376 ladish_client_set_pid(client
, pid
);
377 ASSERT(ladish_client_get_vgraph(client
) == NULL
);
381 /* unknown and internal clients appear in the studio graph */
382 ladish_client_set_vgraph(client
, g_studio
.studio_graph
);
389 static void client_disappeared(void * context
, uint64_t id
)
391 ladish_client_handle client
;
393 ladish_graph_handle vgraph
;
395 log_info("client_disappeared(%"PRIu64
")", id
);
397 client
= ladish_graph_find_client_by_jack_id(virtualizer_ptr
->jack_graph
, id
);
400 log_error("Unknown JACK client with id %"PRIu64
" disappeared", id
);
404 log_info("client disappeared: '%s'", ladish_graph_get_client_name(virtualizer_ptr
->jack_graph
, client
));
406 vgraph
= ladish_client_get_vgraph(client
);
408 pid
= ladish_client_get_pid(client
);
409 if (pid
!= 0 && pid
!= jmcore_proxy_get_pid_cached())
411 virtualizer_ptr
->our_clients_count
--;
414 if (id
== virtualizer_ptr
->system_client_id
)
416 virtualizer_ptr
->system_client_id
= 0;
419 if (vgraph
!= NULL
&& ladish_graph_is_persist(vgraph
)) /* if client is supposed to be persisted */
421 ladish_client_set_jack_id(client
, 0);
422 ladish_graph_hide_client(virtualizer_ptr
->jack_graph
, client
);
426 ladish_graph_remove_client(virtualizer_ptr
->jack_graph
, client
);
427 ladish_client_destroy(client
);
428 /* no need to clear vclient interlink because it either does not exist (vgraph is NULL) or
429 * it will be destroyed before it is accessed (persist flag is cleared on room deletion) */
439 const char * real_jack_port_name
,
444 ladish_client_handle jack_client
;
445 ladish_client_handle vclient
;
446 ladish_port_handle port
;
449 const char * jack_client_name
;
455 char * alsa_client_name
;
456 char * alsa_port_name
;
457 char * a2j_fake_jack_port_name
= NULL
;
458 uint32_t alsa_client_id
;
459 const char * jack_port_name
;
460 const char * vport_name
;
461 ladish_graph_handle vgraph
;
463 log_info("port_appeared(%"PRIu64
", %"PRIu64
", %s (%s, %s))", client_id
, port_id
, real_jack_port_name
, is_input
? "in" : "out", is_midi
? "midi" : "audio");
465 type
= is_midi
? JACKDBUS_PORT_TYPE_MIDI
: JACKDBUS_PORT_TYPE_AUDIO
;
466 flags
= is_input
? JACKDBUS_PORT_FLAG_INPUT
: JACKDBUS_PORT_FLAG_OUTPUT
;
469 flags
|= JACKDBUS_PORT_FLAG_TERMINAL
;
472 /********************/
473 /* gather info about the appeared port */
475 jack_client
= ladish_graph_find_client_by_jack_id(virtualizer_ptr
->jack_graph
, client_id
);
476 if (jack_client
== NULL
)
478 log_error("Port of unknown JACK client with id %"PRIu64
" appeared", client_id
);
482 has_app
= ladish_client_get_app(jack_client
, app_uuid
);
484 /* find the virtual graph that owns the app that owns the client that owns the appeared port */
485 vgraph
= ladish_client_get_vgraph(jack_client
);
488 vgraph
= find_link_port_vgraph_by_uuid(virtualizer_ptr
, real_jack_port_name
, &port
);
491 log_error("Cannot find vgraph for appeared jmcore port '%s'", real_jack_port_name
);
495 /* jmcore port appeared */
497 log_info("jmcore port appeared in vgraph %s", ladish_graph_get_description(vgraph
));
499 if (!ladish_graph_add_port(virtualizer_ptr
->jack_graph
, jack_client
, port
, real_jack_port_name
, type
, flags
, false))
501 log_error("ladish_graph_add_port() failed.");
505 if (vgraph
== g_studio
.studio_graph
)
507 ladish_port_set_jack_id(port
, port_id
);
511 ladish_port_set_jack_id_room(port
, port_id
);
514 vclient
= ladish_graph_get_port_client(vgraph
, port
);
517 log_error("link port client not found in vgraph %s", ladish_graph_get_description(vgraph
));
522 ladish_graph_show_port(vgraph
, port
);
526 jack_client_name
= ladish_graph_get_client_name(virtualizer_ptr
->jack_graph
, jack_client
);
528 ladish_client_get_uuid(jack_client
, jclient_uuid
);
529 is_a2j
= uuid_compare(jclient_uuid
, g_a2j_uuid
) == 0;
532 log_info("a2j port appeared");
533 if (!a2j_proxy_map_jack_port(real_jack_port_name
, &alsa_client_name
, &alsa_port_name
, &alsa_client_id
))
536 alsa_client_name
= catdup("FAILED ", jack_client_name
);
537 if (alsa_client_name
== NULL
)
539 log_error("catdup failed to duplicate a2j jack client name after map failure");
543 alsa_port_name
= strdup(real_jack_port_name
);
544 if (alsa_port_name
== NULL
)
546 log_error("catdup failed to duplicate a2j jack port name after map failure");
547 free(alsa_client_name
);
553 log_info("a2j: '%s':'%s' (%"PRIu32
")", alsa_client_name
, alsa_port_name
, alsa_client_id
);
556 a2j_fake_jack_port_name
= catdup4(alsa_client_name
, is_input
? " (playback)" : " (capture)", ": ", alsa_port_name
);
557 if (a2j_fake_jack_port_name
== NULL
)
559 log_error("catdup4() failed");
560 goto free_alsa_names
;
563 jack_port_name
= a2j_fake_jack_port_name
;
567 jack_port_name
= real_jack_port_name
;
570 /********************/
572 /* search (by name) the appeared port in jack graph
573 * if found - show it in both graphs.
574 * if not found - create new port and add it to the jack graph.
575 * Then process to adding it to virtual graph */
577 port
= ladish_graph_find_port_by_name(virtualizer_ptr
->jack_graph
, jack_client
, jack_port_name
);
580 log_info("found existing port");
582 if (ladish_port_get_jack_id(port
) != 0)
584 log_error("Ignoring duplicate JACK port '%s':'%s'", jack_client_name
, jack_port_name
);
585 goto free_alsa_names
;
588 ladish_port_set_jack_id(port
, port_id
);
589 ladish_graph_adjust_port(virtualizer_ptr
->jack_graph
, port
, type
, flags
);
590 ladish_graph_show_port(virtualizer_ptr
->jack_graph
, port
);
592 vclient
= ladish_graph_get_port_client(vgraph
, port
);
595 log_error("JACK port not found in virtual graph");
597 goto free_alsa_names
;
600 ladish_client_set_jack_id(vclient
, client_id
);
601 ladish_graph_adjust_port(vgraph
, port
, type
, flags
);
602 ladish_graph_show_port(vgraph
, port
);
603 goto free_alsa_names
;
606 if (!ladish_port_create(NULL
, false, &port
))
608 log_error("ladish_port_create() failed.");
609 goto free_alsa_names
;
612 /* set port jack id so invisible connections to/from it can be restored */
613 ladish_port_set_jack_id(port
, port_id
);
615 if (!ladish_graph_add_port(virtualizer_ptr
->jack_graph
, jack_client
, port
, jack_port_name
, type
, flags
, false))
617 log_error("ladish_graph_add_port() failed.");
618 ladish_port_destroy(port
);
619 goto free_alsa_names
;
622 /********************/
623 /* find/create the virtual client where port will be added */
627 vclient
= ladish_graph_find_client_by_name(vgraph
, alsa_client_name
, false);
630 if (!ladish_client_create(NULL
, &vclient
))
632 log_error("ladish_client_create() failed.");
633 goto free_alsa_names
;
636 if (!ladish_graph_add_client(vgraph
, vclient
, alsa_client_name
, false))
638 log_error("ladish_graph_add_client() failed.");
639 ladish_client_destroy(vclient
);
640 goto free_alsa_names
;
644 else if (client_id
== virtualizer_ptr
->system_client_id
)
646 log_info("system client port appeared");
649 { /* output capture port */
651 vclient
= ladish_graph_find_client_by_uuid(vgraph
, g_system_capture_uuid
);
654 if (!ladish_client_create(g_system_capture_uuid
, &vclient
))
656 log_error("ladish_client_create() failed.");
657 goto free_alsa_names
;
660 if (!ladish_graph_add_client(vgraph
, vclient
, "Hardware Capture", false))
662 log_error("ladish_graph_add_client() failed.");
663 ladish_client_destroy(vclient
);
664 goto free_alsa_names
;
669 { /* input playback port */
670 vclient
= ladish_graph_find_client_by_uuid(vgraph
, g_system_playback_uuid
);
673 if (!ladish_client_create(g_system_playback_uuid
, &vclient
))
675 log_error("ladish_client_create() failed.");
676 goto free_alsa_names
;
679 if (!ladish_graph_add_client(vgraph
, vclient
, "Hardware Playback", false))
681 ladish_client_destroy(vclient
);
682 goto free_alsa_names
;
688 { /* non-system client */
689 log_info("non-system client port appeared");
691 if (ladish_client_get_interlink(jack_client
, vclient_uuid
))
693 vclient
= ladish_graph_find_client_by_uuid(vgraph
, vclient_uuid
);
694 ASSERT(vclient
!= NULL
);
698 log_info("creating new vclient");
699 if (!ladish_client_create(NULL
, &vclient
))
701 log_error("ladish_client_create() failed.");
702 goto free_alsa_names
;
705 ladish_client_interlink(vclient
, jack_client
);
709 ladish_client_set_app(vclient
, app_uuid
);
712 if (!ladish_graph_add_client(vgraph
, vclient
, jack_client_name
, false))
714 log_error("ladish_graph_add_client() failed to add client '%s' to virtual graph", jack_client_name
);
715 ladish_client_destroy(vclient
);
716 goto free_alsa_names
;
721 /********************/
722 /* add newly appeared port to the virtual graph */
726 vport_name
= alsa_port_name
;
730 vport_name
= jack_port_name
;
733 if (!ladish_graph_add_port(vgraph
, vclient
, port
, vport_name
, type
, flags
, false))
735 log_error("ladish_graph_add_port() failed.");
736 goto free_alsa_names
;
740 if (a2j_fake_jack_port_name
!= NULL
)
742 free(a2j_fake_jack_port_name
);
747 free(alsa_client_name
);
748 free(alsa_port_name
);
755 static void port_disappeared(void * context
, uint64_t client_id
, uint64_t port_id
)
757 ladish_client_handle jclient
;
758 ladish_client_handle vclient
;
759 ladish_port_handle port
;
760 ladish_graph_handle vgraph
;
763 log_info("port_disappeared(%"PRIu64
", %"PRIu64
")", client_id
, port_id
);
765 jclient
= ladish_graph_find_client_by_jack_id(virtualizer_ptr
->jack_graph
, client_id
);
768 log_error("Port of unknown JACK client with id %"PRIu64
" disappeared", client_id
);
772 port
= ladish_graph_find_port_by_jack_id(virtualizer_ptr
->jack_graph
, port_id
, true, true);
775 log_error("Unknown JACK port with id %"PRIu64
" disappeared", port_id
);
779 /* find the virtual graph that owns the app that owns the client that owns the disappeared port */
781 vgraph
= ladish_client_get_vgraph(jclient
);
784 vgraph
= find_link_port_vgraph_by_uuid(virtualizer_ptr
, ladish_graph_get_port_name(virtualizer_ptr
->jack_graph
, port
), NULL
);
787 log_error("Cannot find vgraph for disappeared jmcore port");
793 ladish_graph_remove_port_by_jack_id(virtualizer_ptr
->jack_graph
, port_id
, true, true);
796 if (ladish_graph_is_persist(vgraph
)) /* if port is supposed to be persisted */
800 ladish_port_set_jack_id(port
, 0);
801 ladish_graph_hide_port(virtualizer_ptr
->jack_graph
, port
);
805 ladish_graph_hide_port(vgraph
, port
);
806 vclient
= ladish_graph_get_port_client(vgraph
, port
);
807 if (ladish_graph_client_looks_empty(vgraph
, vclient
))
809 ladish_graph_hide_client(vgraph
, vclient
);
817 ladish_graph_remove_port(virtualizer_ptr
->jack_graph
, port
);
822 vclient
= ladish_graph_remove_port(vgraph
, port
);
825 if (ladish_graph_client_is_empty(vgraph
, vclient
))
827 ladish_graph_remove_client(vgraph
, vclient
);
828 ladish_client_clear_interlink(jclient
);
835 static void port_renamed(void * context
, uint64_t client_id
, uint64_t port_id
, const char * old_port_name
, const char * new_port_name
)
837 ladish_client_handle client
;
838 ladish_port_handle port
;
839 ladish_graph_handle vgraph
;
841 log_info("port_renamed(%"PRIu64
", '%s', '%s')", port_id
, old_port_name
, new_port_name
);
843 client
= ladish_graph_find_client_by_jack_id(virtualizer_ptr
->jack_graph
, client_id
);
846 log_error("Port of unknown JACK client with id %"PRIu64
" was renamed", client_id
);
850 /* find the virtual graph that owns the app that owns the client that owns the renamed port */
851 vgraph
= ladish_client_get_vgraph(client
);
853 port
= ladish_graph_find_port_by_jack_id(virtualizer_ptr
->jack_graph
, port_id
, true, true);
856 log_error("Unknown JACK port with id %"PRIu64
" was renamed", port_id
);
860 if (!ladish_graph_rename_port(virtualizer_ptr
->jack_graph
, port
, new_port_name
))
862 log_error("renaming of port in jack graph failed");
865 if (!ladish_graph_rename_port(vgraph
, port
, new_port_name
))
867 log_error("renaming of port in virtual graph failed");
871 static bool ports_connect_request(void * context
, ladish_graph_handle graph_handle
, ladish_port_handle port1
, ladish_port_handle port2
)
876 ASSERT(ladish_graph_get_opath(graph_handle
)); /* studio or room virtual graph */
877 log_info("virtualizer: ports connect request");
879 if (graph_handle
== g_studio
.studio_graph
)
881 port1_id
= ladish_port_get_jack_id(port1
);
882 port2_id
= ladish_port_get_jack_id(port2
);
886 port1_id
= ladish_port_get_jack_id_room(port1
);
887 port2_id
= ladish_port_get_jack_id_room(port2
);
890 return graph_proxy_connect_ports(virtualizer_ptr
->jack_graph_proxy
, port1_id
, port2_id
);
893 static bool ports_disconnect_request(void * context
, ladish_graph_handle graph_handle
, uint64_t connection_id
)
895 ladish_port_handle port1
;
896 ladish_port_handle port2
;
900 ASSERT(ladish_graph_get_opath(graph_handle
)); /* studio or room virtual graph */
901 log_info("virtualizer: ports disconnect request");
903 if (!ladish_graph_get_connection_ports(graph_handle
, connection_id
, &port1
, &port2
))
905 log_error("cannot find ports that are disconnect-requested");
910 if (graph_handle
== g_studio
.studio_graph
)
912 port1_id
= ladish_port_get_jack_id(port1
);
913 port2_id
= ladish_port_get_jack_id(port2
);
917 port1_id
= ladish_port_get_jack_id_room(port1
);
918 port2_id
= ladish_port_get_jack_id_room(port2
);
921 return graph_proxy_disconnect_ports(virtualizer_ptr
->jack_graph_proxy
, port1_id
, port2_id
);
924 static void ports_connected(void * context
, uint64_t client1_id
, uint64_t port1_id
, uint64_t client2_id
, uint64_t port2_id
)
926 ladish_port_handle port1
;
927 ladish_port_handle port2
;
928 uint64_t connection_id
;
929 ladish_graph_handle vgraph1
;
930 ladish_graph_handle vgraph2
;
932 log_info("ports_connected %"PRIu64
":%"PRIu64
" %"PRIu64
":%"PRIu64
"", client1_id
, port1_id
, client2_id
, port2_id
);
934 if (!lookup_port(virtualizer_ptr
, port1_id
, &port1
, &vgraph1
))
939 if (!lookup_port(virtualizer_ptr
, port2_id
, &port2
, &vgraph2
))
944 if (vgraph1
!= vgraph2
)
947 log_error("ignoring connection with endpoints in different vgraphs");
951 ladish_graph_add_connection(virtualizer_ptr
->jack_graph
, port1
, port2
, false);
953 if (ladish_graph_find_connection(vgraph1
, port1
, port2
, &connection_id
))
955 log_info("showing hidden virtual connection");
956 ladish_graph_show_connection(vgraph1
, connection_id
);
960 log_info("creating new virtual connection");
961 ladish_graph_add_connection(vgraph1
, port1
, port2
, false);
965 static void ports_disconnected(void * context
, uint64_t client1_id
, uint64_t port1_id
, uint64_t client2_id
, uint64_t port2_id
)
967 ladish_port_handle port1
;
968 ladish_port_handle port2
;
969 uint64_t connection_id
;
970 ladish_graph_handle vgraph1
;
971 ladish_graph_handle vgraph2
;
973 log_info("ports_disconnected %"PRIu64
":%"PRIu64
" %"PRIu64
":%"PRIu64
"", client1_id
, port1_id
, client2_id
, port2_id
);
975 if (!lookup_port(virtualizer_ptr
, port1_id
, &port1
, &vgraph1
))
980 if (!lookup_port(virtualizer_ptr
, port2_id
, &port2
, &vgraph2
))
985 if (vgraph1
!= vgraph2
)
988 log_error("ignoring connection with endpoints in different vgraphs");
992 if (ladish_graph_find_connection(virtualizer_ptr
->jack_graph
, port1
, port2
, &connection_id
))
994 ladish_graph_remove_connection(virtualizer_ptr
->jack_graph
, connection_id
, true);
998 log_error("ports %"PRIu64
":%"PRIu64
" and %"PRIu64
":%"PRIu64
" are not connected in the JACK graph", client1_id
, port1_id
, client2_id
, port2_id
);
1001 if (ladish_graph_find_connection(vgraph1
, port1
, port2
, &connection_id
))
1003 ladish_graph_remove_connection(vgraph1
, connection_id
, false);
1007 log_error("ports %"PRIu64
":%"PRIu64
" and %"PRIu64
":%"PRIu64
" are not connected in the virtual graph", client1_id
, port1_id
, client2_id
, port2_id
);
1011 #undef virtualizer_ptr
1014 ladish_virtualizer_create(
1015 graph_proxy_handle jack_graph_proxy
,
1016 ladish_graph_handle jack_graph
,
1017 ladish_virtualizer_handle
* handle_ptr
)
1019 struct virtualizer
* virtualizer_ptr
;
1021 virtualizer_ptr
= malloc(sizeof(struct virtualizer
));
1022 if (virtualizer_ptr
== NULL
)
1024 log_error("malloc() failed for struct virtualizer");
1028 virtualizer_ptr
->jack_graph_proxy
= jack_graph_proxy
;
1029 virtualizer_ptr
->jack_graph
= jack_graph
;
1030 virtualizer_ptr
->system_client_id
= 0;
1031 virtualizer_ptr
->our_clients_count
= 0;
1033 if (!graph_proxy_attach(
1038 NULL
, /* jackdbus does not have client rename functionality (yet) */
1044 ports_disconnected
))
1046 free(virtualizer_ptr
);
1050 *handle_ptr
= (ladish_virtualizer_handle
)virtualizer_ptr
;
1054 #define virtualizer_ptr ((struct virtualizer *)handle)
1057 ladish_virtualizer_set_graph_connection_handlers(
1058 ladish_virtualizer_handle handle
,
1059 ladish_graph_handle graph
)
1061 ladish_graph_set_connection_handlers(graph
, virtualizer_ptr
, ports_connect_request
, ports_disconnect_request
);
1065 ladish_virtualizer_get_our_clients_count(
1066 ladish_virtualizer_handle handle
)
1068 return virtualizer_ptr
->our_clients_count
;
1072 ladish_virtualizer_is_hidden_app(
1073 ladish_graph_handle jack_graph
,
1074 const uuid_t app_uuid
,
1075 const char * app_name
)
1077 ladish_client_handle jclient
;
1078 ladish_graph_handle vgraph
;
1079 uuid_t vclient_uuid
;
1080 ladish_client_handle vclient
;
1082 uuid_t jclient_uuid
;
1085 //ladish_graph_dump(g_studio.jack_graph);
1087 jclient
= ladish_graph_find_client_by_app(jack_graph
, app_uuid
);
1088 if (jclient
== NULL
)
1090 log_info("App without JACK client is treated as hidden one");
1094 ladish_client_get_uuid(jclient
, jclient_uuid
);
1095 is_a2j
= uuid_compare(jclient_uuid
, g_a2j_uuid
) == 0;
1096 is_empty
= ladish_graph_client_is_empty(jack_graph
, jclient
);
1098 vgraph
= ladish_client_get_vgraph(jclient
);
1105 //ladish_graph_dump(vgraph);
1107 if (!ladish_graph_client_looks_empty(jack_graph
, jclient
) ||
1108 !ladish_graph_client_is_hidden(jack_graph
, jclient
))
1115 /* The a2j jclient has no interlinked vclient */
1119 if (!ladish_client_get_interlink(jclient
, vclient_uuid
))
1123 log_info("jack client of app '%s' has no interlinked vgraph client and no ports", app_name
);
1127 log_error("jack client of app '%s' has no interlinked vgraph client", app_name
);
1133 vclient
= ladish_graph_find_client_by_uuid(vgraph
, vclient_uuid
);
1134 if (vclient
== NULL
)
1140 if (!ladish_graph_client_looks_empty(vgraph
, vclient
))
1145 ASSERT(ladish_graph_client_is_hidden(vgraph
, vclient
)); /* vclients are automatically hidden when they start looking empty (on port disappear) */
1150 ladish_virtualizer_remove_app(
1151 ladish_graph_handle jack_graph
,
1152 const uuid_t app_uuid
,
1153 const char * app_name
)
1155 ladish_client_handle jclient
;
1156 ladish_graph_handle vgraph
;
1157 uuid_t vclient_uuid
;
1158 ladish_client_handle vclient
;
1160 uuid_t jclient_uuid
;
1163 //ladish_graph_dump(g_studio.jack_graph);
1165 jclient
= ladish_graph_find_client_by_app(jack_graph
, app_uuid
);
1166 if (jclient
== NULL
)
1168 log_info("removing app without JACK client");
1172 ladish_client_get_uuid(jclient
, jclient_uuid
);
1173 is_a2j
= uuid_compare(jclient_uuid
, g_a2j_uuid
) == 0;
1174 is_empty
= ladish_graph_client_is_empty(jack_graph
, jclient
);
1176 vgraph
= ladish_client_get_vgraph(jclient
);
1183 //ladish_graph_dump(vgraph);
1185 ladish_graph_remove_client(jack_graph
, jclient
);
1189 /* The a2j jclient has no interlinked vclient */
1193 if (!ladish_client_get_interlink(jclient
, vclient_uuid
))
1197 /* jack client without ports and thus without vgraph client */
1201 log_error("jack client of app '%s' has no interlinked vgraph client", app_name
);
1202 ladish_graph_dump(g_studio
.jack_graph
);
1203 ladish_graph_dump(vgraph
);
1208 vclient
= ladish_graph_find_client_by_uuid(vgraph
, vclient_uuid
);
1209 if (vclient
== NULL
)
1215 ladish_graph_remove_client(vgraph
, vclient
);
1216 ladish_graph_dump(g_studio
.jack_graph
);
1217 ladish_graph_dump(vgraph
);
1221 ladish_virtualizer_destroy(
1222 ladish_virtualizer_handle handle
)
1224 log_info("ladish_virtualizer_destroy() called");
1226 graph_proxy_detach((graph_proxy_handle
)handle
, virtualizer_ptr
);
1227 free(virtualizer_ptr
);
1230 #undef virtualizer_ptr
1232 #define vgraph ((ladish_graph_handle)vgraph_context)
1234 ladish_virtualizer_rename_app(
1235 void * vgraph_context
,
1237 const char * old_name
,
1238 const char * new_app_name
)
1240 ladish_client_handle client
;
1242 client
= ladish_graph_find_client_by_app(vgraph
, uuid
);
1245 ladish_graph_rename_client(vgraph
, client
, new_app_name
);
1248 client
= ladish_graph_find_client_by_app(g_studio
.jack_graph
, uuid
);
1251 ladish_graph_rename_client(g_studio
.jack_graph
, client
, new_app_name
);
1257 ladish_virtualizer_is_system_client(
1260 if (uuid_compare(uuid
, g_system_capture_uuid
) == 0)
1265 if (uuid_compare(uuid
, g_system_playback_uuid
) == 0)