Merge branch 'stable' into 'main'
[ladish.git] / daemon / cmd_load_studio.c
blobc43c096277c5ffc623ceb1e29c79ef21a63f0636
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009,2010,2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the "load studio" command
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 "common.h"
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
34 #include "escape.h"
35 #include "cmd.h"
36 #include "studio_internal.h"
37 #include "../proxies/notify_proxy.h"
38 #include "load.h"
40 #define context_ptr ((struct ladish_parse_context *)data)
42 static void callback_chrdata(void * data, const XML_Char * s, int len)
44 if (context_ptr->error)
46 return;
49 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER ||
50 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY ||
51 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
53 if ((size_t)(context_ptr->data_used + len) >= sizeof(context_ptr->data))
55 log_error("xml parse max char data length reached");
56 context_ptr->error = XML_TRUE;
57 return;
60 memcpy(context_ptr->data + context_ptr->data_used, s, len);
61 context_ptr->data_used += len;
65 static void callback_elstart(void * data, const char * el, const char ** attr)
67 const char * name;
68 const char * level;
69 char * name_dup;
70 const char * path;
71 const char * uuid_str;
72 uuid_t uuid;
73 const char * uuid2_str;
74 uuid_t uuid2;
75 ladish_port_handle port1;
76 ladish_port_handle port2;
77 uint32_t port_type;
78 uint32_t port_flags;
79 size_t len;
81 name_dup = NULL;
83 if (context_ptr->error)
85 goto free;
88 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
90 log_error("xml parse max stack depth reached");
91 context_ptr->error = XML_TRUE;
92 goto free;
95 if (strcmp(el, "studio") == 0)
97 //log_info("<studio>");
98 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_STUDIO;
99 goto free;
102 if (strcmp(el, "jack") == 0)
104 //log_info("<jack>");
105 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
106 goto free;
109 if (strcmp(el, "conf") == 0)
111 //log_info("<conf>");
112 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONF;
113 goto free;
116 if (strcmp(el, "parameter") == 0)
118 //log_info("<parameter>");
119 path = ladish_get_string_attribute(attr, "path");
120 if (path == NULL)
122 log_error("<parameter> XML element without \"path\" attribute");
123 context_ptr->error = XML_TRUE;
124 goto free;
127 context_ptr->str = strdup(path);
128 if (context_ptr->str == NULL)
130 log_error("strdup() failed");
131 context_ptr->error = XML_TRUE;
132 goto free;
135 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PARAMETER;
136 context_ptr->data_used = 0;
137 goto free;
140 if (strcmp(el, "clients") == 0)
142 //log_info("<clients>");
143 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENTS;
144 goto free;
147 if (strcmp(el, "rooms") == 0)
149 //log_info("<rooms>");
150 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ROOMS;
151 goto free;
154 if (strcmp(el, "room") == 0)
156 //log_info("<room>");
157 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ROOM;
159 if (context_ptr->room != NULL)
161 log_error("nested rooms");
162 context_ptr->error = XML_TRUE;
163 goto free;
166 if (context_ptr->depth == 2 &&
167 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
168 context_ptr->element[1] == PARSE_CONTEXT_ROOMS)
170 if (!ladish_get_name_and_uuid_attributes("/studio/rooms/room", attr, &name, &uuid_str, uuid))
172 context_ptr->error = XML_TRUE;
173 goto free;
176 if (!ladish_room_create(uuid, name, NULL, g_studio.studio_graph, &context_ptr->room))
178 log_error("ladish_room_create() failed.");
179 context_ptr->error = XML_TRUE;
180 ASSERT(context_ptr->room == NULL);
181 goto free;
184 goto free;
187 log_error("ignoring <room> element in wrong context");
188 goto free;
191 if (strcmp(el, "client") == 0)
193 //log_info("<client>");
194 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENT;
196 if (context_ptr->client != NULL)
198 log_error("nested clients");
199 context_ptr->error = XML_TRUE;
200 goto free;
203 if (context_ptr->depth == 3 &&
204 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
205 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
206 context_ptr->element[2] == PARSE_CONTEXT_CLIENTS)
208 if (!ladish_get_name_and_uuid_attributes("/studio/jack/clients/client", attr, &name, &uuid_str, uuid))
210 context_ptr->error = XML_TRUE;
211 goto free;
214 name_dup = unescape_dup(name);
215 if (name_dup == NULL)
217 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
218 context_ptr->error = XML_TRUE;
219 goto free;
222 log_info("jack client \"%s\" with uuid %s", name_dup, uuid_str);
224 if (!ladish_client_create(uuid, &context_ptr->client))
226 log_error("ladish_client_create() failed.");
227 context_ptr->error = XML_TRUE;
228 ASSERT(context_ptr->client == NULL);
229 goto free;
232 if (!ladish_graph_add_client(g_studio.jack_graph, context_ptr->client, name_dup, true))
234 log_error("ladish_graph_add_client() failed to add client '%s' to JACK graph", name_dup);
235 context_ptr->error = XML_TRUE;
236 ladish_client_destroy(context_ptr->client);
237 context_ptr->client = NULL;
238 goto free;
241 else if (context_ptr->depth == 2 &&
242 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
243 context_ptr->element[1] == PARSE_CONTEXT_CLIENTS)
245 if (!ladish_get_name_and_uuid_attributes("/studio/clients/client", attr, &name, &uuid_str, uuid))
247 context_ptr->error = XML_TRUE;
248 goto free;
251 name_dup = unescape_dup(name);
252 if (name_dup == NULL)
254 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
255 context_ptr->error = XML_TRUE;
256 goto free;
259 log_info("studio client \"%s\" with uuid %s", name_dup, uuid_str);
261 context_ptr->client = ladish_graph_find_client_by_uuid(g_studio.studio_graph, uuid);
262 if (context_ptr->client != NULL)
264 log_info("Found existing client");
265 goto free;
268 if (!ladish_client_create(uuid, &context_ptr->client))
270 log_error("ladish_client_create() failed.");
271 context_ptr->error = XML_TRUE;
272 ASSERT(context_ptr->client == NULL);
273 goto free;
276 if (ladish_get_uuid_attribute(attr, "app", context_ptr->uuid, true))
278 ladish_client_set_app(context_ptr->client, context_ptr->uuid);
281 if (!ladish_graph_add_client(g_studio.studio_graph, context_ptr->client, name_dup, true))
283 log_error("ladish_graph_add_client() failed to add client '%s' to studio graph", name_dup);
284 context_ptr->error = XML_TRUE;
285 ladish_client_destroy(context_ptr->client);
286 context_ptr->client = NULL;
287 goto free;
291 goto free;
294 if (strcmp(el, "ports") == 0)
296 //log_info("<ports>");
297 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORTS;
298 goto free;
301 if (strcmp(el, "port") == 0)
303 //log_info("<port>");
304 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORT;
306 if (context_ptr->port != NULL)
308 log_error("nested ports");
309 context_ptr->error = XML_TRUE;
310 goto free;
313 if (context_ptr->depth >= 3 &&
314 context_ptr->element[context_ptr->depth - 3] == PARSE_CONTEXT_CLIENTS &&
315 context_ptr->element[context_ptr->depth - 2] == PARSE_CONTEXT_CLIENT &&
316 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORTS)
318 //log_info("client port");
319 if (context_ptr->client == NULL)
321 log_error("client-less port");
322 context_ptr->error = XML_TRUE;
323 goto free;
326 if (context_ptr->depth == 5 && context_ptr->element[0] == PARSE_CONTEXT_STUDIO && context_ptr->element[1] == PARSE_CONTEXT_JACK)
328 if (!ladish_get_name_and_uuid_attributes("/studio/jack/clients/client/ports/port", attr, &name, &uuid_str, uuid))
330 context_ptr->error = XML_TRUE;
331 goto free;
334 name_dup = unescape_dup(name);
335 if (name_dup == NULL)
337 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
338 context_ptr->error = XML_TRUE;
339 goto free;
342 log_info("jack port \"%s\" with uuid %s", name_dup, uuid_str);
344 if (!ladish_port_create(uuid, false, &context_ptr->port))
346 log_error("ladish_port_create() failed.");
347 goto free;
350 ladish_port_set_vgraph(context_ptr->port, g_studio.studio_graph);
352 if (!ladish_graph_add_port(g_studio.jack_graph, context_ptr->client, context_ptr->port, name_dup, 0, 0, true))
354 log_error("ladish_graph_add_port() failed.");
355 ladish_port_destroy(context_ptr->port);
356 context_ptr->port = NULL;
359 goto free;
361 else if (context_ptr->depth == 4 && context_ptr->element[0] == PARSE_CONTEXT_STUDIO)
363 if (!ladish_get_name_and_uuid_attributes("/studio/clients/client/ports/port", attr, &name, &uuid_str, uuid))
365 context_ptr->error = XML_TRUE;
366 goto free;
369 name_dup = unescape_dup(name);
370 if (name_dup == NULL)
372 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
373 context_ptr->error = XML_TRUE;
374 goto free;
377 uuid2_str = ladish_get_uuid_attribute(attr, "link_uuid", uuid2, true);
379 log_info("studio port \"%s\" with uuid %s (%s)", name_dup, uuid_str, uuid2_str == NULL ? "normal" : "room link");
381 if (uuid2_str == NULL)
382 { /* normal studio port */
383 context_ptr->port = ladish_graph_find_port_by_uuid(g_studio.jack_graph, uuid, false, g_studio.studio_graph);
384 if (context_ptr->port == NULL)
386 log_error("studio client with non-jack port %s", uuid_str);
387 context_ptr->error = XML_TRUE;
388 goto free;
391 if (!ladish_graph_add_port(g_studio.studio_graph, context_ptr->client, context_ptr->port, name_dup, 0, 0, true))
393 log_error("ladish_graph_add_port() failed.");
394 ladish_port_destroy(context_ptr->port);
395 context_ptr->port = NULL;
396 goto free;
399 goto free;
402 /* room link port */
403 context_ptr->port = ladish_graph_find_client_port_by_uuid(g_studio.studio_graph, context_ptr->client, uuid2, false);
404 if (context_ptr->port == NULL)
406 log_error("room link port not found");
407 context_ptr->error = XML_TRUE;
408 goto free;
411 ladish_graph_set_link_port_override_uuid(g_studio.studio_graph, context_ptr->port, uuid);
412 goto free;
415 else if (context_ptr->depth == 3 &&
416 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
417 context_ptr->element[1] == PARSE_CONTEXT_ROOMS &&
418 context_ptr->element[2] == PARSE_CONTEXT_ROOM)
420 ASSERT(context_ptr->room != NULL);
421 //log_info("room port");
423 if (!ladish_get_name_and_uuid_attributes("/studio/rooms/room/port", attr, &name, &uuid_str, uuid))
425 context_ptr->error = XML_TRUE;
426 goto free;
429 name_dup = unescape_dup(name);
430 if (name_dup == NULL)
432 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
433 context_ptr->error = XML_TRUE;
434 goto free;
437 log_info("room port \"%s\" with uuid %s", name_dup, uuid_str);
439 if (!ladish_parse_port_type_and_direction_attributes("/studio/rooms/room/port", attr, &port_type, &port_flags))
441 context_ptr->error = XML_TRUE;
442 goto free;
445 context_ptr->port = ladish_room_add_port(context_ptr->room, uuid, name_dup, port_type, port_flags);
446 if (context_ptr->port == NULL)
448 log_error("ladish_room_add_port() failed.");
449 context_ptr->port = NULL;
452 goto free;
455 log_error("port element in wrong place");
456 ladish_dump_element_stack(context_ptr);
457 context_ptr->error = XML_TRUE;
458 goto free;
461 if (strcmp(el, "connections") == 0)
463 //log_info("<connections>");
464 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTIONS;
465 goto free;
468 if (strcmp(el, "connection") == 0)
470 //log_info("<connection>");
471 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTION;
473 uuid_str = ladish_get_uuid_attribute(attr, "port1", uuid, false);
474 if (uuid_str == NULL)
476 log_error("/studio/connections/connection \"port1\" attribute is not available.");
477 context_ptr->error = XML_TRUE;
478 goto free;
481 uuid2_str = ladish_get_uuid_attribute(attr, "port2", uuid2, false);
482 if (uuid2_str == NULL)
484 log_error("/studio/connections/connection \"port2\" attribute is not available.");
485 context_ptr->error = XML_TRUE;
486 goto free;
489 log_info("studio connection between port %s and port %s", uuid_str, uuid2_str);
491 port1 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid, true, NULL);
492 if (port1 == NULL)
494 log_error("studio client with unknown port %s", uuid_str);
495 context_ptr->error = XML_TRUE;
496 goto free;
499 port2 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid2, true, NULL);
500 if (port2 == NULL)
502 log_error("studio client with unknown port %s", uuid2_str);
503 context_ptr->error = XML_TRUE;
504 goto free;
507 context_ptr->connection_id = ladish_graph_add_connection(g_studio.studio_graph, port1, port2, true);
508 if (context_ptr->connection_id == 0)
510 log_error("ladish_graph_add_connection() failed.");
511 goto free;
514 goto free;
517 if (strcmp(el, "applications") == 0)
519 //log_info("<applications>");
520 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATIONS;
521 goto free;
524 if (strcmp(el, "application") == 0)
526 //log_info("<application>");
527 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATION;
529 name = ladish_get_string_attribute(attr, "name");
530 if (name == NULL)
532 log_error("application \"name\" attribute is not available.");
533 context_ptr->error = XML_TRUE;
534 goto free;
537 if (!ladish_get_uuid_attribute(attr, "uuid", context_ptr->uuid, true))
539 uuid_clear(context_ptr->uuid);
542 if (ladish_get_bool_attribute(attr, "terminal", &context_ptr->terminal) == NULL)
544 log_error("application \"terminal\" attribute is not available. name=\"%s\"", name);
545 context_ptr->error = XML_TRUE;
546 goto free;
549 if (ladish_get_bool_attribute(attr, "autorun", &context_ptr->autorun) == NULL)
551 log_error("application \"autorun\" attribute is not available. name=\"%s\"", name);
552 context_ptr->error = XML_TRUE;
553 goto free;
556 level = ladish_get_string_attribute(attr, "level");
557 if (level == NULL)
559 log_error("application \"level\" attribute is not available. name=\"%s\"", name);
560 context_ptr->error = XML_TRUE;
561 goto free;
564 if (!ladish_check_app_level_validity(level, &len))
566 log_error("application \"level\" attribute has invalid value \"%s\", name=\"%s\"", level, name);
567 context_ptr->error = XML_TRUE;
568 goto free;
571 memcpy(context_ptr->level, level, len + 1);
573 context_ptr->str = strdup(name);
574 if (context_ptr->str == NULL)
576 log_error("strdup() failed");
577 context_ptr->error = XML_TRUE;
578 goto free;
581 context_ptr->data_used = 0;
582 goto free;
585 if (strcmp(el, "dict") == 0)
587 //log_info("<dict>");
588 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DICT;
590 if (context_ptr->dict != NULL)
592 log_error("nested dicts");
593 context_ptr->error = XML_TRUE;
594 goto free;
597 if (context_ptr->depth == 1 &&
598 context_ptr->element[0] == PARSE_CONTEXT_STUDIO)
600 context_ptr->dict = ladish_graph_get_dict(g_studio.studio_graph);
601 ASSERT(context_ptr->dict != NULL);
603 else if (context_ptr->depth > 0 &&
604 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CLIENT)
606 ASSERT(context_ptr->client != NULL);
607 context_ptr->dict = ladish_client_get_dict(context_ptr->client);
608 ASSERT(context_ptr->dict != NULL);
610 else if (context_ptr->depth > 0 &&
611 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORT)
613 ASSERT(context_ptr->port != NULL);
614 context_ptr->dict = ladish_port_get_dict(context_ptr->port);
615 ASSERT(context_ptr->dict != NULL);
617 else if (context_ptr->depth > 0 &&
618 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CONNECTION)
620 ASSERT(context_ptr->port != NULL);
621 context_ptr->dict = ladish_graph_get_connection_dict(g_studio.studio_graph, context_ptr->connection_id);
622 ASSERT(context_ptr->dict != NULL);
624 else
626 log_error("unexpected dict XML element");
627 context_ptr->error = XML_TRUE;
628 goto free;
631 goto free;
634 if (strcmp(el, "key") == 0)
636 //log_info("<key>");
637 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_KEY;
639 if (context_ptr->dict == NULL)
641 log_error("dict-less key");
642 context_ptr->error = XML_TRUE;
643 goto free;
646 name = ladish_get_string_attribute(attr, "name");
647 if (name == NULL)
649 log_error("dict/key \"name\" attribute is not available.");
650 context_ptr->error = XML_TRUE;
651 goto free;
654 context_ptr->str = strdup(name);
655 if (context_ptr->str == NULL)
657 log_error("strdup() failed");
658 context_ptr->error = XML_TRUE;
659 goto free;
662 context_ptr->data_used = 0;
664 goto free;
667 log_error("unknown element \"%s\"", el);
668 context_ptr->error = XML_TRUE;
670 free:
671 free(name_dup);
672 return;
675 static void callback_elend(void * data, const char * UNUSED(el))
677 char * src;
678 char * dst;
679 char * sep;
680 size_t src_len;
681 size_t dst_len;
682 char * address;
683 struct jack_parameter_variant parameter;
684 bool is_set;
686 if (context_ptr->error)
688 return;
691 //log_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
693 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER &&
694 context_ptr->depth == 3 &&
695 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
696 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
697 context_ptr->element[2] == PARSE_CONTEXT_CONF)
699 context_ptr->data[context_ptr->data_used] = 0;
701 //log_info("'%s' with value '%s'", context_ptr->str, context_ptr->data);
703 dst = address = strdup(context_ptr->str);
704 src = context_ptr->str + 1;
705 while (*src != 0)
707 sep = strchr(src, '/');
708 if (sep == NULL)
710 src_len = strlen(src);
712 else
714 src_len = sep - src;
717 dst_len = unescape(src, src_len, dst);
718 dst[dst_len] = 0;
719 dst += dst_len + 1;
721 src += src_len;
722 ASSERT(*src == '/' || *src == 0);
723 if (sep != NULL)
725 ASSERT(*src == '/');
726 src++; /* skip separator */
728 else
730 ASSERT(*src == 0);
733 *dst = 0; /* ASCIZZ */
735 if (!jack_proxy_get_parameter_value(address, &is_set, &parameter))
737 log_error("jack_proxy_get_parameter_value() failed");
738 goto fail_free_address;
741 if (parameter.type == jack_string)
743 free(parameter.value.string);
746 switch (parameter.type)
748 case jack_boolean:
749 log_info("%s value is %s (boolean)", context_ptr->str, context_ptr->data);
750 if (strcmp(context_ptr->data, "true") == 0)
752 parameter.value.boolean = true;
754 else if (strcmp(context_ptr->data, "false") == 0)
756 parameter.value.boolean = false;
758 else
760 log_error("bad value for a bool jack param");
761 goto fail_free_address;
763 break;
764 case jack_string:
765 log_info("%s value is %s (string)", context_ptr->str, context_ptr->data);
766 parameter.value.string = context_ptr->data;
767 break;
768 case jack_byte:
769 log_debug("%s value is %u/%c (byte/char)", context_ptr->str, *context_ptr->data, *context_ptr->data);
770 if (context_ptr->data[0] == 0 ||
771 context_ptr->data[1] != 0)
773 log_error("bad value for a char jack param");
774 goto fail_free_address;
776 parameter.value.byte = context_ptr->data[0];
777 break;
778 case jack_uint32:
779 log_info("%s value is %s (uint32)", context_ptr->str, context_ptr->data);
780 if (sscanf(context_ptr->data, "%" PRIu32, &parameter.value.uint32) != 1)
782 log_error("bad value for an uint32 jack param");
783 goto fail_free_address;
785 break;
786 case jack_int32:
787 log_info("%s value is %s (int32)", context_ptr->str, context_ptr->data);
788 if (sscanf(context_ptr->data, "%" PRIi32, &parameter.value.int32) != 1)
790 log_error("bad value for an int32 jack param");
791 goto fail_free_address;
793 break;
794 default:
795 log_error("unknown jack parameter type %d of %s", (int)parameter.type, context_ptr->str);
796 goto fail_free_address;
799 if (!jack_proxy_set_parameter_value(address, &parameter))
801 log_error("jack_proxy_set_parameter_value() failed");
802 goto fail_free_address;
805 free(address);
807 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY &&
808 context_ptr->depth > 0 &&
809 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_DICT)
811 ASSERT(context_ptr->dict != NULL);
812 context_ptr->data[context_ptr->data_used] = 0;
813 log_info("dict key '%s' with value '%s'", context_ptr->str, context_ptr->data);
814 if (!ladish_dict_set(context_ptr->dict, context_ptr->str, context_ptr->data))
816 log_error("ladish_dict_set() failed");
817 context_ptr->error = XML_TRUE;
818 return;
821 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_ROOM)
823 //log_info("</room>");
824 ASSERT(context_ptr->room != NULL);
825 context_ptr->room = NULL;
827 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_DICT)
829 //log_info("</dict>");
830 ASSERT(context_ptr->dict != NULL);
831 context_ptr->dict = NULL;
833 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_CLIENT)
835 //log_info("</client>");
836 ASSERT(context_ptr->client != NULL);
837 context_ptr->client = NULL;
839 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PORT)
841 //log_info("</port>");
842 ASSERT(context_ptr->port != NULL);
843 context_ptr->port = NULL;
845 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
847 context_ptr->data[unescape(context_ptr->data, context_ptr->data_used, context_ptr->data)] = 0;
848 unescape_simple(context_ptr->str);
850 log_info("application '%s' (%s, %s, level '%s') with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", context_ptr->level, context_ptr->data);
852 if (ladish_app_supervisor_add(
853 g_studio.app_supervisor,
854 context_ptr->str,
855 context_ptr->uuid,
856 context_ptr->autorun,
857 context_ptr->data,
858 context_ptr->terminal,
859 context_ptr->level) == NULL)
861 log_error("ladish_app_supervisor_add() failed.");
862 context_ptr->error = XML_TRUE;
866 context_ptr->depth--;
868 if (context_ptr->str != NULL)
870 free(context_ptr->str);
871 context_ptr->str = NULL;
874 return;
876 fail_free_address:
877 free(address);
878 context_ptr->error = XML_TRUE;
879 return;
882 #undef context_ptr
884 struct ladish_command_load_studio
886 struct ladish_command command;
887 char * studio_name;
890 #define cmd_ptr ((struct ladish_command_load_studio *)command_context)
892 static bool run(void * command_context)
894 char * path;
895 struct stat st;
896 XML_Parser parser;
897 int bytes_read;
898 void * buffer;
899 int fd;
900 enum XML_Status xmls;
901 struct ladish_parse_context parse_context;
903 ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING);
905 if (!ladish_studio_compose_filename(cmd_ptr->studio_name, &path, NULL))
907 log_error("failed to compose path of studio \%s\" file", cmd_ptr->studio_name);
908 return false;
911 log_info("Loading studio... ('%s')", path);
913 if (stat(path, &st) != 0)
915 log_error("failed to stat '%s': %d (%s)", path, errno, strerror(errno));
916 free(path);
917 return false;
920 g_studio.name = cmd_ptr->studio_name;
921 cmd_ptr->studio_name = NULL;
923 g_studio.filename = path;
925 if (!jack_reset_all_params())
927 log_error("jack_reset_all_params() failed");
928 return false;
931 fd = open(path, O_RDONLY);
932 if (fd == -1)
934 log_error("failed to open '%s': %d (%s)", path, errno, strerror(errno));
935 return false;
938 parser = XML_ParserCreate(NULL);
939 if (parser == NULL)
941 log_error("XML_ParserCreate() failed to create parser object.");
942 close(fd);
943 return false;
946 //log_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
948 /* we are expecting that conf file has small enough size to fit in memory */
950 buffer = XML_GetBuffer(parser, st.st_size);
951 if (buffer == NULL)
953 log_error("XML_GetBuffer() failed.");
954 XML_ParserFree(parser);
955 close(fd);
956 return false;
959 bytes_read = read(fd, buffer, st.st_size);
960 if (bytes_read != st.st_size)
962 log_error("read() returned unexpected result.");
963 XML_ParserFree(parser);
964 close(fd);
965 return false;
968 parse_context.error = XML_FALSE;
969 parse_context.depth = -1;
970 parse_context.str = NULL;
971 parse_context.client = NULL;
972 parse_context.port = NULL;
973 parse_context.dict = NULL;
974 parse_context.room = NULL;
976 XML_SetElementHandler(parser, callback_elstart, callback_elend);
977 XML_SetCharacterDataHandler(parser, callback_chrdata);
978 XML_SetUserData(parser, &parse_context);
980 if (!ladish_studio_show())
982 log_error("ladish_studio_show() failed.");
983 XML_ParserFree(parser);
984 close(fd);
985 return false;
988 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
989 if (xmls == XML_STATUS_ERROR)
991 if (!parse_context.error)
993 log_error("XML_ParseBuffer() failed.");
996 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Studio load failed", LADISH_CHECK_LOG_TEXT);
997 ladish_studio_clear();
998 XML_ParserFree(parser);
999 close(fd);
1000 return false;
1003 XML_ParserFree(parser);
1004 close(fd);
1006 if (parse_context.error)
1008 ladish_studio_clear();
1009 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Studio load failed", LADISH_CHECK_LOG_TEXT);
1010 return false;
1013 ladish_interlink(ladish_studio_get_studio_graph(), ladish_studio_get_studio_app_supervisor());
1015 g_studio.persisted = true;
1016 log_info("Studio loaded. ('%s')", path);
1018 ladish_graph_dump(g_studio.jack_graph);
1019 ladish_graph_dump(g_studio.studio_graph);
1020 ladish_app_supervisor_dump(g_studio.app_supervisor);
1022 ladish_recent_store_use_item(g_studios_recent_store, g_studio.name);
1024 if (!ladish_app_supervisor_set_project_name(ladish_studio_get_studio_app_supervisor(), g_studio.name))
1026 ladish_app_supervisor_set_project_name(ladish_studio_get_studio_app_supervisor(), NULL);
1029 ladish_studio_announce();
1031 cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE;
1032 return true;
1035 static void destructor(void * command_context)
1037 log_info("load studio command destructor");
1038 if (cmd_ptr->studio_name != NULL)
1040 free(cmd_ptr->studio_name);
1044 #undef cmd_ptr
1046 bool ladish_command_load_studio(void * call_ptr, struct ladish_cqueue * queue_ptr, const char * studio_name, bool autostart)
1048 struct ladish_command_load_studio * cmd_ptr;
1049 char * studio_name_dup;
1051 studio_name_dup = strdup(studio_name);
1052 if (studio_name_dup == NULL)
1054 cdbus_error(call_ptr, DBUS_ERROR_FAILED, "strdup('%s') failed.", studio_name);
1055 goto fail;
1058 if (!ladish_command_unload_studio(call_ptr, queue_ptr))
1060 goto fail_free_name;
1063 cmd_ptr = ladish_command_new(sizeof(struct ladish_command_load_studio));
1064 if (cmd_ptr == NULL)
1066 log_error("ladish_command_new() failed.");
1067 goto fail_drop_unload_command;
1070 cmd_ptr->command.run = run;
1071 cmd_ptr->command.destructor = destructor;
1072 cmd_ptr->studio_name = studio_name_dup;
1074 if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command))
1076 cdbus_error(call_ptr, DBUS_ERROR_FAILED, "ladish_cqueue_add_command() failed.");
1077 goto fail_destroy_command;
1080 if (autostart)
1082 if (!ladish_command_start_studio(call_ptr, queue_ptr))
1084 goto fail_drop_load_command;
1088 return true;
1090 fail_drop_load_command:
1091 ladish_cqueue_drop_command(queue_ptr);
1093 fail_destroy_command:
1094 free(cmd_ptr);
1096 fail_drop_unload_command:
1097 ladish_cqueue_drop_command(queue_ptr);
1099 fail_free_name:
1100 free(studio_name_dup);
1102 fail:
1103 return false;