fix conf_set()
[ladish.git] / daemon / cmd_load_studio.c
blobb270952d8b23af7b0878c0bf66191b9c9ffdb0bc
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 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 (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 * path;
69 const char * uuid_str;
70 uuid_t uuid;
71 const char * uuid2_str;
72 uuid_t uuid2;
73 ladish_port_handle port1;
74 ladish_port_handle port2;
75 uint32_t port_type;
76 uint32_t port_flags;
78 if (context_ptr->error)
80 return;
83 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
85 log_error("xml parse max stack depth reached");
86 context_ptr->error = XML_TRUE;
87 return;
90 if (strcmp(el, "studio") == 0)
92 //log_info("<studio>");
93 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_STUDIO;
94 return;
97 if (strcmp(el, "jack") == 0)
99 //log_info("<jack>");
100 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
101 return;
104 if (strcmp(el, "conf") == 0)
106 //log_info("<conf>");
107 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONF;
108 return;
111 if (strcmp(el, "parameter") == 0)
113 //log_info("<parameter>");
114 path = ladish_get_string_attribute(attr, "path");
115 if (path == NULL)
117 log_error("<parameter> XML element without \"path\" attribute");
118 context_ptr->error = XML_TRUE;
119 return;
122 context_ptr->str = strdup(path);
123 if (context_ptr->str == NULL)
125 log_error("strdup() failed");
126 context_ptr->error = XML_TRUE;
127 return;
130 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PARAMETER;
131 context_ptr->data_used = 0;
132 return;
135 if (strcmp(el, "clients") == 0)
137 //log_info("<clients>");
138 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENTS;
139 return;
142 if (strcmp(el, "rooms") == 0)
144 //log_info("<rooms>");
145 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ROOMS;
146 return;
149 if (strcmp(el, "room") == 0)
151 //log_info("<room>");
152 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ROOM;
154 if (context_ptr->room != NULL)
156 log_error("nested rooms");
157 context_ptr->error = XML_TRUE;
158 return;
161 if (context_ptr->depth == 2 &&
162 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
163 context_ptr->element[1] == PARSE_CONTEXT_ROOMS)
165 if (!ladish_get_name_and_uuid_attributes("/studio/rooms/room", attr, &name, &uuid_str, uuid))
167 context_ptr->error = XML_TRUE;
168 return;
171 if (!ladish_room_create(uuid, name, NULL, g_studio.studio_graph, &context_ptr->room))
173 log_error("ladish_room_create() failed.");
174 context_ptr->error = XML_TRUE;
175 ASSERT(context_ptr->room == NULL);
176 return;
179 return;
182 log_error("ignoring <room> element in wrong context");
183 return;
186 if (strcmp(el, "client") == 0)
188 //log_info("<client>");
189 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENT;
191 if (context_ptr->client != NULL)
193 log_error("nested clients");
194 context_ptr->error = XML_TRUE;
195 return;
198 if (context_ptr->depth == 3 &&
199 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
200 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
201 context_ptr->element[2] == PARSE_CONTEXT_CLIENTS)
203 if (!ladish_get_name_and_uuid_attributes("/studio/jack/clients/client", attr, &name, &uuid_str, uuid))
205 context_ptr->error = XML_TRUE;
206 return;
209 log_info("jack client \"%s\" with uuid %s", name, uuid_str);
211 if (!ladish_client_create(uuid, &context_ptr->client))
213 log_error("ladish_client_create() failed.");
214 context_ptr->error = XML_TRUE;
215 ASSERT(context_ptr->client == NULL);
216 return;
219 if (!ladish_graph_add_client(g_studio.jack_graph, context_ptr->client, name, true))
221 log_error("ladish_graph_add_client() failed to add client '%s' to JACK graph", name);
222 context_ptr->error = XML_TRUE;
223 ladish_client_destroy(context_ptr->client);
224 context_ptr->client = NULL;
225 return;
228 else if (context_ptr->depth == 2 &&
229 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
230 context_ptr->element[1] == PARSE_CONTEXT_CLIENTS)
232 if (!ladish_get_name_and_uuid_attributes("/studio/clients/client", attr, &name, &uuid_str, uuid))
234 context_ptr->error = XML_TRUE;
235 return;
238 log_info("studio client \"%s\" with uuid %s", name, uuid_str);
240 context_ptr->client = ladish_graph_find_client_by_uuid(g_studio.studio_graph, uuid);
241 if (context_ptr->client != NULL)
243 log_info("Found existing client");
244 return;
247 if (!ladish_client_create(uuid, &context_ptr->client))
249 log_error("ladish_client_create() failed.");
250 context_ptr->error = XML_TRUE;
251 ASSERT(context_ptr->client == NULL);
252 return;
255 if (!ladish_graph_add_client(g_studio.studio_graph, context_ptr->client, name, true))
257 log_error("ladish_graph_add_client() failed to add client '%s' to studio graph", name);
258 context_ptr->error = XML_TRUE;
259 ladish_client_destroy(context_ptr->client);
260 context_ptr->client = NULL;
261 return;
265 return;
268 if (strcmp(el, "ports") == 0)
270 //log_info("<ports>");
271 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORTS;
272 return;
275 if (strcmp(el, "port") == 0)
277 //log_info("<port>");
278 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORT;
280 if (context_ptr->port != NULL)
282 log_error("nested ports");
283 context_ptr->error = XML_TRUE;
284 return;
287 if (context_ptr->depth >= 3 &&
288 context_ptr->element[context_ptr->depth - 3] == PARSE_CONTEXT_CLIENTS &&
289 context_ptr->element[context_ptr->depth - 2] == PARSE_CONTEXT_CLIENT &&
290 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORTS)
292 //log_info("client port");
293 if (context_ptr->client == NULL)
295 log_error("client-less port");
296 context_ptr->error = XML_TRUE;
297 return;
300 if (context_ptr->depth == 5 && context_ptr->element[0] == PARSE_CONTEXT_STUDIO && context_ptr->element[1] == PARSE_CONTEXT_JACK)
302 if (!ladish_get_name_and_uuid_attributes("/studio/jack/clients/client/ports/port", attr, &name, &uuid_str, uuid))
304 context_ptr->error = XML_TRUE;
305 return;
308 log_info("jack port \"%s\" with uuid %s", name, uuid_str);
310 if (!ladish_port_create(uuid, false, &context_ptr->port))
312 log_error("ladish_port_create() failed.");
313 return;
316 if (!ladish_graph_add_port(g_studio.jack_graph, context_ptr->client, context_ptr->port, name, 0, 0, true))
318 log_error("ladish_graph_add_port() failed.");
319 ladish_port_destroy(context_ptr->port);
320 context_ptr->port = NULL;
323 return;
325 else if (context_ptr->depth == 4 && context_ptr->element[0] == PARSE_CONTEXT_STUDIO)
327 if (!ladish_get_name_and_uuid_attributes("/studio/clients/client/ports/port", attr, &name, &uuid_str, uuid))
329 context_ptr->error = XML_TRUE;
330 return;
333 uuid2_str = ladish_get_uuid_attribute(attr, "link_uuid", uuid2, true);
335 log_info("studio port \"%s\" with uuid %s (%s)", name, uuid_str, uuid2_str == NULL ? "normal" : "room link");
337 if (uuid2_str == NULL)
338 { /* normal studio port */
339 context_ptr->port = ladish_graph_find_port_by_uuid(g_studio.jack_graph, uuid, false);
340 if (context_ptr->port == NULL)
342 log_error("studio client with non-jack port %s", uuid_str);
343 context_ptr->error = XML_TRUE;
344 return;
347 if (!ladish_graph_add_port(g_studio.studio_graph, context_ptr->client, context_ptr->port, name, 0, 0, true))
349 log_error("ladish_graph_add_port() failed.");
350 ladish_port_destroy(context_ptr->port);
351 context_ptr->port = NULL;
352 return;
355 return;
358 /* room link port */
359 context_ptr->port = ladish_graph_find_client_port_by_uuid(g_studio.studio_graph, context_ptr->client, uuid2, false);
360 if (context_ptr->port == NULL)
362 log_error("room link port not found");
363 context_ptr->error = XML_TRUE;
364 return;
367 ladish_graph_set_link_port_override_uuid(g_studio.studio_graph, context_ptr->port, uuid);
368 return;
371 else if (context_ptr->depth == 3 &&
372 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
373 context_ptr->element[1] == PARSE_CONTEXT_ROOMS &&
374 context_ptr->element[2] == PARSE_CONTEXT_ROOM)
376 ASSERT(context_ptr->room != NULL);
377 //log_info("room port");
379 if (!ladish_get_name_and_uuid_attributes("/studio/rooms/room/port", attr, &name, &uuid_str, uuid))
381 context_ptr->error = XML_TRUE;
382 return;
385 log_info("room port \"%s\" with uuid %s", name, uuid_str);
387 if (!ladish_parse_port_type_and_direction_attributes("/studio/rooms/room/port", attr, &port_type, &port_flags))
389 context_ptr->error = XML_TRUE;
390 return;
393 context_ptr->port = ladish_room_add_port(context_ptr->room, uuid, name, port_type, port_flags);
394 if (context_ptr->port == NULL)
396 log_error("ladish_room_add_port() failed.");
397 context_ptr->port = NULL;
400 return;
403 log_error("port element in wrong place");
404 ladish_dump_element_stack(context_ptr);
405 context_ptr->error = XML_TRUE;
406 return;
409 if (strcmp(el, "connections") == 0)
411 //log_info("<connections>");
412 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTIONS;
413 return;
416 if (strcmp(el, "connection") == 0)
418 //log_info("<connection>");
419 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTION;
421 uuid_str = ladish_get_uuid_attribute(attr, "port1", uuid, false);
422 if (uuid_str == NULL)
424 log_error("/studio/connections/connection \"port1\" attribute is not available.");
425 context_ptr->error = XML_TRUE;
426 return;
429 uuid2_str = ladish_get_uuid_attribute(attr, "port2", uuid2, false);
430 if (uuid2_str == NULL)
432 log_error("/studio/connections/connection \"port2\" attribute is not available.");
433 context_ptr->error = XML_TRUE;
434 return;
437 log_info("studio connection between port %s and port %s", uuid_str, uuid2_str);
439 port1 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid, true);
440 if (port1 == NULL)
442 log_error("studio client with unknown port %s", uuid_str);
443 context_ptr->error = XML_TRUE;
444 return;
447 port2 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid2, true);
448 if (port2 == NULL)
450 log_error("studio client with unknown port %s", uuid2_str);
451 context_ptr->error = XML_TRUE;
452 return;
455 context_ptr->connection_id = ladish_graph_add_connection(g_studio.studio_graph, port1, port2, true);
456 if (context_ptr->connection_id == 0)
458 log_error("ladish_graph_add_connection() failed.");
459 return;
462 return;
465 if (strcmp(el, "applications") == 0)
467 //log_info("<applications>");
468 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATIONS;
469 return;
472 if (strcmp(el, "application") == 0)
474 //log_info("<application>");
475 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATION;
477 name = ladish_get_string_attribute(attr, "name");
478 if (name == NULL)
480 log_error("application \"name\" attribute is not available.");
481 context_ptr->error = XML_TRUE;
482 return;
485 if (ladish_get_bool_attribute(attr, "terminal", &context_ptr->terminal) == NULL)
487 log_error("application \"terminal\" attribute is not available. name=\"%s\"", name);
488 context_ptr->error = XML_TRUE;
489 return;
492 if (ladish_get_bool_attribute(attr, "autorun", &context_ptr->autorun) == NULL)
494 log_error("application \"autorun\" attribute is not available. name=\"%s\"", name);
495 context_ptr->error = XML_TRUE;
496 return;
499 if (ladish_get_byte_attribute(attr, "level", &context_ptr->level) == NULL)
501 log_error("application \"level\" attribute is not available. name=\"%s\"", name);
502 context_ptr->error = XML_TRUE;
503 return;
506 context_ptr->str = strdup(name);
507 if (context_ptr->str == NULL)
509 log_error("strdup() failed");
510 context_ptr->error = XML_TRUE;
511 return;
514 context_ptr->data_used = 0;
515 return;
518 if (strcmp(el, "dict") == 0)
520 //log_info("<dict>");
521 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DICT;
523 if (context_ptr->dict != NULL)
525 log_error("nested dicts");
526 context_ptr->error = XML_TRUE;
527 return;
530 if (context_ptr->depth == 1 &&
531 context_ptr->element[0] == PARSE_CONTEXT_STUDIO)
533 context_ptr->dict = ladish_graph_get_dict(g_studio.studio_graph);
534 ASSERT(context_ptr->dict != NULL);
536 else if (context_ptr->depth > 0 &&
537 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CLIENT)
539 ASSERT(context_ptr->client != NULL);
540 context_ptr->dict = ladish_client_get_dict(context_ptr->client);
541 ASSERT(context_ptr->dict != NULL);
543 else if (context_ptr->depth > 0 &&
544 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORT)
546 ASSERT(context_ptr->port != NULL);
547 context_ptr->dict = ladish_port_get_dict(context_ptr->port);
548 ASSERT(context_ptr->dict != NULL);
550 else if (context_ptr->depth > 0 &&
551 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CONNECTION)
553 ASSERT(context_ptr->port != NULL);
554 context_ptr->dict = ladish_graph_get_connection_dict(g_studio.studio_graph, context_ptr->connection_id);
555 ASSERT(context_ptr->dict != NULL);
557 else
559 log_error("unexpected dict XML element");
560 context_ptr->error = XML_TRUE;
561 return;
564 return;
567 if (strcmp(el, "key") == 0)
569 //log_info("<key>");
570 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_KEY;
572 if (context_ptr->dict == NULL)
574 log_error("dict-less key");
575 context_ptr->error = XML_TRUE;
576 return;
579 name = ladish_get_string_attribute(attr, "name");
580 if (name == NULL)
582 log_error("dict/key \"name\" attribute is not available.");
583 context_ptr->error = XML_TRUE;
584 return;
587 context_ptr->str = strdup(name);
588 if (context_ptr->str == NULL)
590 log_error("strdup() failed");
591 context_ptr->error = XML_TRUE;
592 return;
595 context_ptr->data_used = 0;
597 return;
600 log_error("unknown element \"%s\"", el);
601 context_ptr->error = XML_TRUE;
604 static void callback_elend(void * data, const char * el)
606 char * src;
607 char * dst;
608 char * sep;
609 size_t src_len;
610 size_t dst_len;
611 char * address;
612 struct jack_parameter_variant parameter;
613 bool is_set;
615 if (context_ptr->error)
617 return;
620 //log_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
622 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER &&
623 context_ptr->depth == 3 &&
624 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
625 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
626 context_ptr->element[2] == PARSE_CONTEXT_CONF)
628 context_ptr->data[context_ptr->data_used] = 0;
630 //log_info("'%s' with value '%s'", context_ptr->str, context_ptr->data);
632 dst = address = strdup(context_ptr->str);
633 src = context_ptr->str + 1;
634 while (*src != 0)
636 sep = strchr(src, '/');
637 if (sep == NULL)
639 src_len = strlen(src);
641 else
643 src_len = sep - src;
646 dst_len = unescape(src, src_len, dst);
647 dst[dst_len] = 0;
648 dst += dst_len + 1;
650 src += src_len;
651 ASSERT(*src == '/' || *src == 0);
652 if (sep != NULL)
654 ASSERT(*src == '/');
655 src++; /* skip separator */
657 else
659 ASSERT(*src == 0);
662 *dst = 0; /* ASCIZZ */
664 if (!jack_proxy_get_parameter_value(address, &is_set, &parameter))
666 log_error("jack_proxy_get_parameter_value() failed");
667 goto fail_free_address;
670 if (parameter.type == jack_string)
672 free(parameter.value.string);
675 switch (parameter.type)
677 case jack_boolean:
678 log_info("%s value is %s (boolean)", context_ptr->str, context_ptr->data);
679 if (strcmp(context_ptr->data, "true") == 0)
681 parameter.value.boolean = true;
683 else if (strcmp(context_ptr->data, "false") == 0)
685 parameter.value.boolean = false;
687 else
689 log_error("bad value for a bool jack param");
690 goto fail_free_address;
692 break;
693 case jack_string:
694 log_info("%s value is %s (string)", context_ptr->str, context_ptr->data);
695 parameter.value.string = context_ptr->data;
696 break;
697 case jack_byte:
698 log_debug("%s value is %u/%c (byte/char)", context_ptr->str, *context_ptr->data, *context_ptr->data);
699 if (context_ptr->data[0] == 0 ||
700 context_ptr->data[1] != 0)
702 log_error("bad value for a char jack param");
703 goto fail_free_address;
705 parameter.value.byte = context_ptr->data[0];
706 break;
707 case jack_uint32:
708 log_info("%s value is %s (uint32)", context_ptr->str, context_ptr->data);
709 if (sscanf(context_ptr->data, "%" PRIu32, &parameter.value.uint32) != 1)
711 log_error("bad value for an uint32 jack param");
712 goto fail_free_address;
714 break;
715 case jack_int32:
716 log_info("%s value is %s (int32)", context_ptr->str, context_ptr->data);
717 if (sscanf(context_ptr->data, "%" PRIi32, &parameter.value.int32) != 1)
719 log_error("bad value for an int32 jack param");
720 goto fail_free_address;
722 break;
723 default:
724 log_error("unknown jack parameter type %d of %s", (int)parameter.type, context_ptr->str);
725 goto fail_free_address;
728 if (!jack_proxy_set_parameter_value(address, &parameter))
730 log_error("jack_proxy_set_parameter_value() failed");
731 goto fail_free_address;
734 free(address);
736 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY &&
737 context_ptr->depth > 0 &&
738 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_DICT)
740 ASSERT(context_ptr->dict != NULL);
741 context_ptr->data[context_ptr->data_used] = 0;
742 log_info("dict key '%s' with value '%s'", context_ptr->str, context_ptr->data);
743 if (!ladish_dict_set(context_ptr->dict, context_ptr->str, context_ptr->data))
745 log_error("ladish_dict_set() failed");
746 context_ptr->error = XML_TRUE;
747 return;
750 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_ROOM)
752 //log_info("</room>");
753 ASSERT(context_ptr->room != NULL);
754 context_ptr->room = NULL;
756 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_DICT)
758 //log_info("</dict>");
759 ASSERT(context_ptr->dict != NULL);
760 context_ptr->dict = NULL;
762 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_CLIENT)
764 //log_info("</client>");
765 ASSERT(context_ptr->client != NULL);
766 context_ptr->client = NULL;
768 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PORT)
770 //log_info("</port>");
771 ASSERT(context_ptr->port != NULL);
772 context_ptr->port = NULL;
774 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
776 context_ptr->data[unescape(context_ptr->data, context_ptr->data_used, context_ptr->data)] = 0;
777 unescape(context_ptr->str, strlen(context_ptr->str) + 1, context_ptr->str);
779 log_info("application '%s' (%s, %s, level %u) with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", (unsigned int)context_ptr->level, context_ptr->data);
781 if (ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level) == NULL)
783 log_error("ladish_app_supervisor_add() failed.");
784 context_ptr->error = XML_TRUE;
788 context_ptr->depth--;
790 if (context_ptr->str != NULL)
792 free(context_ptr->str);
793 context_ptr->str = NULL;
796 return;
798 fail_free_address:
799 free(address);
800 context_ptr->error = XML_TRUE;
801 return;
804 #undef context_ptr
806 struct ladish_command_load_studio
808 struct ladish_command command;
809 char * studio_name;
812 #define cmd_ptr ((struct ladish_command_load_studio *)command_context)
814 static bool run(void * command_context)
816 char * path;
817 struct stat st;
818 XML_Parser parser;
819 int bytes_read;
820 void * buffer;
821 int fd;
822 enum XML_Status xmls;
823 struct ladish_parse_context parse_context;
825 ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING);
827 if (!ladish_studio_compose_filename(cmd_ptr->studio_name, &path, NULL))
829 log_error("failed to compose path of studio \%s\" file", cmd_ptr->studio_name);
830 return false;
833 log_info("Loading studio... ('%s')", path);
835 if (stat(path, &st) != 0)
837 log_error("failed to stat '%s': %d (%s)", path, errno, strerror(errno));
838 free(path);
839 return false;
842 g_studio.name = cmd_ptr->studio_name;
843 cmd_ptr->studio_name = NULL;
845 g_studio.filename = path;
847 if (!jack_reset_all_params())
849 log_error("jack_reset_all_params() failed");
850 return false;
853 fd = open(path, O_RDONLY);
854 if (fd == -1)
856 log_error("failed to open '%s': %d (%s)", path, errno, strerror(errno));
857 return false;
860 parser = XML_ParserCreate(NULL);
861 if (parser == NULL)
863 log_error("XML_ParserCreate() failed to create parser object.");
864 close(fd);
865 return false;
868 //log_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
870 /* we are expecting that conf file has small enough size to fit in memory */
872 buffer = XML_GetBuffer(parser, st.st_size);
873 if (buffer == NULL)
875 log_error("XML_GetBuffer() failed.");
876 XML_ParserFree(parser);
877 close(fd);
878 return false;
881 bytes_read = read(fd, buffer, st.st_size);
882 if (bytes_read != st.st_size)
884 log_error("read() returned unexpected result.");
885 XML_ParserFree(parser);
886 close(fd);
887 return false;
890 parse_context.error = XML_FALSE;
891 parse_context.depth = -1;
892 parse_context.str = NULL;
893 parse_context.client = NULL;
894 parse_context.port = NULL;
895 parse_context.dict = NULL;
896 parse_context.room = NULL;
898 XML_SetElementHandler(parser, callback_elstart, callback_elend);
899 XML_SetCharacterDataHandler(parser, callback_chrdata);
900 XML_SetUserData(parser, &parse_context);
902 if (!ladish_studio_show())
904 log_error("ladish_studio_show() failed.");
905 XML_ParserFree(parser);
906 close(fd);
907 return false;
910 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
911 if (xmls == XML_STATUS_ERROR)
913 if (!parse_context.error)
915 log_error("XML_ParseBuffer() failed.");
918 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Studio load failed", "Please inspect the ladishd log (~/.ladish/ladish.log) for more info");
919 ladish_studio_clear();
920 XML_ParserFree(parser);
921 close(fd);
922 return false;
925 XML_ParserFree(parser);
926 close(fd);
928 if (parse_context.error)
930 ladish_studio_clear();
931 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Studio load failed", "Please inspect the ladishd log (~/.ladish/ladish.log) for more info");
932 return false;
935 ladish_interlink_clients(ladish_studio_get_studio_graph(), ladish_studio_get_studio_app_supervisor());
937 g_studio.persisted = true;
938 log_info("Studio loaded. ('%s')", path);
940 ladish_graph_dump(g_studio.jack_graph);
941 ladish_graph_dump(g_studio.studio_graph);
943 ladish_studio_announce();
945 cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE;
946 return true;
949 static void destructor(void * command_context)
951 log_info("load studio command destructor");
952 if (cmd_ptr->studio_name != NULL)
954 free(cmd_ptr->studio_name);
958 #undef cmd_ptr
960 bool ladish_command_load_studio(void * call_ptr, struct ladish_cqueue * queue_ptr, const char * studio_name, bool autostart)
962 struct ladish_command_load_studio * cmd_ptr;
963 char * studio_name_dup;
965 studio_name_dup = strdup(studio_name);
966 if (studio_name_dup == NULL)
968 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", studio_name);
969 goto fail;
972 if (!ladish_command_unload_studio(call_ptr, queue_ptr))
974 goto fail_free_name;
977 cmd_ptr = ladish_command_new(sizeof(struct ladish_command_load_studio));
978 if (cmd_ptr == NULL)
980 log_error("ladish_command_new() failed.");
981 goto fail_drop_unload_command;
984 cmd_ptr->command.run = run;
985 cmd_ptr->command.destructor = destructor;
986 cmd_ptr->studio_name = studio_name_dup;
988 if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command))
990 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed.");
991 goto fail_destroy_command;
994 if (autostart)
996 if (!ladish_command_start_studio(call_ptr, queue_ptr))
998 goto fail_drop_load_command;
1002 return true;
1004 fail_drop_load_command:
1005 ladish_cqueue_drop_command(queue_ptr);
1007 fail_destroy_command:
1008 free(cmd_ptr);
1010 fail_drop_unload_command:
1011 ladish_cqueue_drop_command(queue_ptr);
1013 fail_free_name:
1014 free(studio_name_dup);
1016 fail:
1017 return false;