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 "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.
29 #include <sys/types.h>
38 #include "studio_internal.h"
40 #define PARSE_CONTEXT_ROOT 0
41 #define PARSE_CONTEXT_STUDIO 1
42 #define PARSE_CONTEXT_JACK 2
43 #define PARSE_CONTEXT_CONF 3
44 #define PARSE_CONTEXT_PARAMETER 4
45 #define PARSE_CONTEXT_CLIENTS 5
46 #define PARSE_CONTEXT_CLIENT 6
47 #define PARSE_CONTEXT_PORTS 7
48 #define PARSE_CONTEXT_PORT 8
49 #define PARSE_CONTEXT_DICT 9
50 #define PARSE_CONTEXT_KEY 10
51 #define PARSE_CONTEXT_CONNECTIONS 11
52 #define PARSE_CONTEXT_CONNECTION 12
53 #define PARSE_CONTEXT_APPLICATIONS 13
54 #define PARSE_CONTEXT_APPLICATION 14
56 #define MAX_STACK_DEPTH 10
57 #define MAX_DATA_SIZE 10240
62 unsigned int element
[MAX_STACK_DEPTH
];
64 char data
[MAX_DATA_SIZE
];
67 ladish_client_handle client
;
68 ladish_port_handle port
;
69 ladish_dict_handle dict
;
70 uint64_t connection_id
;
76 static const char * get_string_attribute(const char * const * attr
, const char * key
)
78 while (attr
[0] != NULL
)
80 ASSERT(attr
[1] != NULL
);
81 if (strcmp(attr
[0], key
) == 0)
88 log_error("attribute \"%s\" is missing");
92 static const char * get_uuid_attribute(const char * const * attr
, const char * key
, uuid_t uuid
)
96 value
= get_string_attribute(attr
, key
);
102 if (uuid_parse(value
, uuid
) != 0)
104 log_error("cannot parse uuid \"%s\"", value
);
111 static const char * get_bool_attribute(const char * const * attr
, const char * key
, bool * bool_value_ptr
)
113 const char * value_str
;
115 value_str
= get_string_attribute(attr
, key
);
116 if (value_str
== NULL
)
121 if (strcmp(value_str
, "true") == 0)
123 *bool_value_ptr
= true;
127 if (strcmp(value_str
, "false") == 0)
129 *bool_value_ptr
= false;
133 log_error("boolean XML attribute has value of \"%s\" but only \"true\" and \"false\" are valid", value_str
);
137 static const char * get_byte_attribute(const char * const * attr
, const char * key
, uint8_t * byte_value_ptr
)
139 const char * value_str
;
143 value_str
= get_string_attribute(attr
, key
);
144 if (value_str
== NULL
)
149 errno
= 0; /* To distinguish success/failure after call */
150 li_value
= strtol(value_str
, &end_ptr
, 10);
151 if ((errno
== ERANGE
&& (li_value
== LONG_MAX
|| li_value
== LONG_MIN
)) || (errno
!= 0 && li_value
== 0) || end_ptr
== value_str
)
153 log_error("value '%s' of attribute '%s' is not valid integer.", value_str
, key
);
157 if (li_value
< 0 || li_value
> 255)
159 log_error("value '%s' of attribute '%s' is not valid uint8.", value_str
, key
);
163 *byte_value_ptr
= (uint8_t)li_value
;
169 get_name_and_uuid_attributes(
170 const char * element_description
,
171 const char * const * attr
,
172 const char ** name_str_ptr
,
173 const char ** uuid_str_ptr
,
176 const char * name_str
;
177 const char * uuid_str
;
179 name_str
= get_string_attribute(attr
, "name");
180 if (name_str
== NULL
)
182 log_error("%s \"name\" attribute is not available", element_description
);
186 uuid_str
= get_uuid_attribute(attr
, "uuid", uuid
);
187 if (uuid_str
== NULL
)
189 log_error("%s \"uuid\" attribute is not available. name=\"%s\"", element_description
, name_str
);
193 *name_str_ptr
= name_str
;
194 *uuid_str_ptr
= uuid_str
;
198 #define context_ptr ((struct parse_context *)data)
200 static void callback_chrdata(void * data
, const XML_Char
* s
, int len
)
202 if (context_ptr
->error
)
207 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_PARAMETER
||
208 context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_KEY
||
209 context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_APPLICATION
)
211 if (context_ptr
->data_used
+ len
>= sizeof(context_ptr
->data
))
213 log_error("xml parse max char data length reached");
214 context_ptr
->error
= XML_TRUE
;
218 memcpy(context_ptr
->data
+ context_ptr
->data_used
, s
, len
);
219 context_ptr
->data_used
+= len
;
223 static void callback_elstart(void * data
, const char * el
, const char ** attr
)
227 const char * uuid_str
;
229 const char * uuid2_str
;
231 ladish_port_handle port1
;
232 ladish_port_handle port2
;
234 if (context_ptr
->error
)
239 if (context_ptr
->depth
+ 1 >= MAX_STACK_DEPTH
)
241 log_error("xml parse max stack depth reached");
242 context_ptr
->error
= XML_TRUE
;
246 if (strcmp(el
, "studio") == 0)
248 //log_info("<studio>");
249 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_STUDIO
;
253 if (strcmp(el
, "jack") == 0)
255 //log_info("<jack>");
256 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_JACK
;
260 if (strcmp(el
, "conf") == 0)
262 //log_info("<conf>");
263 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONF
;
267 if (strcmp(el
, "parameter") == 0)
269 //log_info("<parameter>");
270 path
= get_string_attribute(attr
, "path");
273 log_error("<parameter> XML element without \"path\" attribute");
274 context_ptr
->error
= XML_TRUE
;
278 context_ptr
->str
= strdup(path
);
279 if (context_ptr
->str
== NULL
)
281 log_error("strdup() failed");
282 context_ptr
->error
= XML_TRUE
;
286 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PARAMETER
;
287 context_ptr
->data_used
= 0;
291 if (strcmp(el
, "clients") == 0)
293 //log_info("<clients>");
294 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CLIENTS
;
298 if (strcmp(el
, "client") == 0)
300 //log_info("<client>");
301 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CLIENT
;
303 if (context_ptr
->client
!= NULL
)
305 log_error("nested clients");
306 context_ptr
->error
= XML_TRUE
;
310 if (context_ptr
->depth
== 3 &&
311 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
312 context_ptr
->element
[1] == PARSE_CONTEXT_JACK
&&
313 context_ptr
->element
[2] == PARSE_CONTEXT_CLIENTS
)
315 if (!get_name_and_uuid_attributes("/studio/jack/clients/client", attr
, &name
, &uuid_str
, uuid
))
317 context_ptr
->error
= XML_TRUE
;
321 log_info("jack client \"%s\" with uuid %s", name
, uuid_str
);
323 if (!ladish_client_create(uuid
, &context_ptr
->client
))
325 log_error("ladish_client_create() failed.");
326 context_ptr
->error
= XML_TRUE
;
327 ASSERT(context_ptr
->client
== NULL
);
331 if (!ladish_graph_add_client(g_studio
.jack_graph
, context_ptr
->client
, name
, true))
333 log_error("ladish_graph_add_client() failed to add client '%s' to JACK graph", name
);
334 context_ptr
->error
= XML_TRUE
;
335 ladish_client_destroy(context_ptr
->client
);
336 context_ptr
->client
= NULL
;
340 else if (context_ptr
->depth
== 2 &&
341 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
342 context_ptr
->element
[1] == PARSE_CONTEXT_CLIENTS
)
344 if (!get_name_and_uuid_attributes("/studio/clients/client", attr
, &name
, &uuid_str
, uuid
))
346 context_ptr
->error
= XML_TRUE
;
350 log_info("studio client \"%s\" with uuid %s", name
, uuid_str
);
352 if (!ladish_client_create(uuid
, &context_ptr
->client
))
354 log_error("ladish_client_create() failed.");
355 context_ptr
->error
= XML_TRUE
;
356 ASSERT(context_ptr
->client
== NULL
);
360 if (!ladish_graph_add_client(g_studio
.studio_graph
, context_ptr
->client
, name
, true))
362 log_error("ladish_graph_add_client() failed to add client '%s' to studio graph", name
);
363 context_ptr
->error
= XML_TRUE
;
364 ladish_client_destroy(context_ptr
->client
);
365 context_ptr
->client
= NULL
;
373 if (strcmp(el
, "ports") == 0)
375 //log_info("<ports>");
376 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PORTS
;
380 if (strcmp(el
, "port") == 0)
382 //log_info("<port>");
383 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PORT
;
385 if (context_ptr
->port
!= NULL
)
387 log_error("nested ports");
388 context_ptr
->error
= XML_TRUE
;
392 if (context_ptr
->client
== NULL
)
394 log_error("client-less port");
395 context_ptr
->error
= XML_TRUE
;
399 if (context_ptr
->depth
== 5 &&
400 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
401 context_ptr
->element
[1] == PARSE_CONTEXT_JACK
&&
402 context_ptr
->element
[2] == PARSE_CONTEXT_CLIENTS
&&
403 context_ptr
->element
[3] == PARSE_CONTEXT_CLIENT
&&
404 context_ptr
->element
[4] == PARSE_CONTEXT_PORTS
)
406 if (!get_name_and_uuid_attributes("/studio/jack/clients/client/ports/port", attr
, &name
, &uuid_str
, uuid
))
408 context_ptr
->error
= XML_TRUE
;
412 log_info("jack port \"%s\" with uuid %s", name
, uuid_str
);
414 if (!ladish_port_create(uuid
, false, &context_ptr
->port
))
416 log_error("ladish_port_create() failed.");
420 if (!ladish_graph_add_port(g_studio
.jack_graph
, context_ptr
->client
, context_ptr
->port
, name
, 0, 0, true))
422 log_error("ladish_graph_add_port() failed.");
423 ladish_port_destroy(context_ptr
->port
);
424 context_ptr
->port
= NULL
;
428 else if (context_ptr
->depth
== 4 &&
429 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
430 context_ptr
->element
[1] == PARSE_CONTEXT_CLIENTS
&&
431 context_ptr
->element
[2] == PARSE_CONTEXT_CLIENT
&&
432 context_ptr
->element
[3] == PARSE_CONTEXT_PORTS
)
434 if (!get_name_and_uuid_attributes("/studio/clients/client/ports/port", attr
, &name
, &uuid_str
, uuid
))
436 context_ptr
->error
= XML_TRUE
;
440 log_info("studio port \"%s\" with uuid %s", name
, uuid_str
);
442 context_ptr
->port
= ladish_graph_find_port_by_uuid(g_studio
.jack_graph
, uuid
, false);
443 if (context_ptr
->port
== NULL
)
445 log_error("studio client with non-jack port %s", uuid_str
);
446 context_ptr
->error
= XML_TRUE
;
450 if (!ladish_graph_add_port(g_studio
.studio_graph
, context_ptr
->client
, context_ptr
->port
, name
, 0, 0, true))
452 log_error("ladish_graph_add_port() failed.");
453 ladish_port_destroy(context_ptr
->port
);
454 context_ptr
->port
= NULL
;
462 if (strcmp(el
, "connections") == 0)
464 //log_info("<connections>");
465 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONNECTIONS
;
469 if (strcmp(el
, "connection") == 0)
471 //log_info("<connection>");
472 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONNECTION
;
474 uuid_str
= get_uuid_attribute(attr
, "port1", uuid
);
475 if (uuid_str
== NULL
)
477 log_error("/studio/connections/connection \"port1\" attribute is not available.");
478 context_ptr
->error
= XML_TRUE
;
482 uuid2_str
= get_uuid_attribute(attr
, "port2", uuid2
);
483 if (uuid2_str
== NULL
)
485 log_error("/studio/connections/connection \"port2\" attribute is not available.");
486 context_ptr
->error
= XML_TRUE
;
490 log_info("studio connection between port %s and port %s", uuid_str
, uuid2_str
);
492 port1
= ladish_graph_find_port_by_uuid(g_studio
.studio_graph
, uuid
, false);
495 log_error("studio client with unknown port %s", uuid_str
);
496 context_ptr
->error
= XML_TRUE
;
500 port2
= ladish_graph_find_port_by_uuid(g_studio
.studio_graph
, uuid2
, false);
503 log_error("studio client with unknown port %s", uuid2_str
);
504 context_ptr
->error
= XML_TRUE
;
508 context_ptr
->connection_id
= ladish_graph_add_connection(g_studio
.studio_graph
, port1
, port2
, true);
509 if (context_ptr
->connection_id
== 0)
511 log_error("ladish_graph_add_connection() failed.");
518 if (strcmp(el
, "applications") == 0)
520 //log_info("<applications>");
521 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_APPLICATIONS
;
525 if (strcmp(el
, "application") == 0)
527 //log_info("<application>");
528 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_APPLICATION
;
530 name
= get_string_attribute(attr
, "name");
533 log_error("application \"name\" attribute is not available.");
534 context_ptr
->error
= XML_TRUE
;
538 if (get_bool_attribute(attr
, "terminal", &context_ptr
->terminal
) == NULL
)
540 log_error("application \"terminal\" attribute is not available. name=\"%s\"", name
);
541 context_ptr
->error
= XML_TRUE
;
545 if (get_bool_attribute(attr
, "autorun", &context_ptr
->autorun
) == NULL
)
547 log_error("application \"autorun\" attribute is not available. name=\"%s\"", name
);
548 context_ptr
->error
= XML_TRUE
;
552 if (get_byte_attribute(attr
, "level", &context_ptr
->level
) == NULL
)
554 log_error("application \"level\" attribute is not available. name=\"%s\"", name
);
555 context_ptr
->error
= XML_TRUE
;
559 context_ptr
->str
= strdup(name
);
560 if (context_ptr
->str
== NULL
)
562 log_error("strdup() failed");
563 context_ptr
->error
= XML_TRUE
;
567 context_ptr
->data_used
= 0;
571 if (strcmp(el
, "dict") == 0)
573 //log_info("<dict>");
574 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_DICT
;
576 if (context_ptr
->dict
!= NULL
)
578 log_error("nested dicts");
579 context_ptr
->error
= XML_TRUE
;
583 if (context_ptr
->depth
== 1 &&
584 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
)
586 context_ptr
->dict
= ladish_graph_get_dict(g_studio
.studio_graph
);
587 ASSERT(context_ptr
->dict
!= NULL
);
589 else if (context_ptr
->depth
> 0 &&
590 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_CLIENT
)
592 ASSERT(context_ptr
->client
!= NULL
);
593 context_ptr
->dict
= ladish_client_get_dict(context_ptr
->client
);
594 ASSERT(context_ptr
->dict
!= NULL
);
596 else if (context_ptr
->depth
> 0 &&
597 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_PORT
)
599 ASSERT(context_ptr
->port
!= NULL
);
600 context_ptr
->dict
= ladish_port_get_dict(context_ptr
->port
);
601 ASSERT(context_ptr
->dict
!= NULL
);
603 else if (context_ptr
->depth
> 0 &&
604 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_CONNECTION
)
606 ASSERT(context_ptr
->port
!= NULL
);
607 context_ptr
->dict
= ladish_graph_get_connection_dict(g_studio
.studio_graph
, context_ptr
->connection_id
);
608 ASSERT(context_ptr
->dict
!= NULL
);
612 log_error("unexpected dict XML element");
613 context_ptr
->error
= XML_TRUE
;
620 if (strcmp(el
, "key") == 0)
623 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_KEY
;
625 if (context_ptr
->dict
== NULL
)
627 log_error("dict-less key");
628 context_ptr
->error
= XML_TRUE
;
632 name
= get_string_attribute(attr
, "name");
635 log_error("dict/key \"name\" attribute is not available.");
636 context_ptr
->error
= XML_TRUE
;
640 context_ptr
->str
= strdup(name
);
641 if (context_ptr
->str
== NULL
)
643 log_error("strdup() failed");
644 context_ptr
->error
= XML_TRUE
;
648 context_ptr
->data_used
= 0;
653 log_error("unknown element \"%s\"", el
);
654 context_ptr
->error
= XML_TRUE
;
657 static void callback_elend(void * data
, const char * el
)
665 struct jack_parameter_variant parameter
;
668 if (context_ptr
->error
)
673 //log_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
675 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_PARAMETER
&&
676 context_ptr
->depth
== 3 &&
677 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
678 context_ptr
->element
[1] == PARSE_CONTEXT_JACK
&&
679 context_ptr
->element
[2] == PARSE_CONTEXT_CONF
)
681 context_ptr
->data
[context_ptr
->data_used
] = 0;
683 //log_info("'%s' with value '%s'", context_ptr->str, context_ptr->data);
685 dst
= address
= strdup(context_ptr
->str
);
686 src
= context_ptr
->str
+ 1;
689 sep
= strchr(src
, '/');
692 src_len
= strlen(src
);
699 dst_len
= unescape(src
, src_len
, dst
);
704 ASSERT(*src
== '/' || *src
== 0);
708 src
++; /* skip separator */
715 *dst
= 0; /* ASCIZZ */
717 if (!jack_proxy_get_parameter_value(address
, &is_set
, ¶meter
))
719 log_error("jack_proxy_get_parameter_value() failed");
720 goto fail_free_address
;
723 if (parameter
.type
== jack_string
)
725 free(parameter
.value
.string
);
728 switch (parameter
.type
)
731 log_info("%s value is %s (boolean)", context_ptr
->str
, context_ptr
->data
);
732 if (strcmp(context_ptr
->data
, "true") == 0)
734 parameter
.value
.boolean
= true;
736 else if (strcmp(context_ptr
->data
, "false") == 0)
738 parameter
.value
.boolean
= false;
742 log_error("bad value for a bool jack param");
743 goto fail_free_address
;
747 log_info("%s value is %s (string)", context_ptr
->str
, context_ptr
->data
);
748 parameter
.value
.string
= context_ptr
->data
;
751 log_debug("%s value is %u/%c (byte/char)", context_ptr
->str
, *context_ptr
->data
, *context_ptr
->data
);
752 if (context_ptr
->data
[0] == 0 ||
753 context_ptr
->data
[1] != 0)
755 log_error("bad value for a char jack param");
756 goto fail_free_address
;
758 parameter
.value
.byte
= context_ptr
->data
[0];
761 log_info("%s value is %s (uint32)", context_ptr
->str
, context_ptr
->data
);
762 if (sscanf(context_ptr
->data
, "%" PRIu32
, ¶meter
.value
.uint32
) != 1)
764 log_error("bad value for an uint32 jack param");
765 goto fail_free_address
;
769 log_info("%s value is %s (int32)", context_ptr
->str
, context_ptr
->data
);
770 if (sscanf(context_ptr
->data
, "%" PRIi32
, ¶meter
.value
.int32
) != 1)
772 log_error("bad value for an int32 jack param");
773 goto fail_free_address
;
777 log_error("unknown jack parameter type %d of %s", (int)parameter
.type
, context_ptr
->str
);
778 goto fail_free_address
;
781 if (!jack_proxy_set_parameter_value(address
, ¶meter
))
783 log_error("jack_proxy_set_parameter_value() failed");
784 goto fail_free_address
;
789 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_KEY
&&
790 context_ptr
->depth
> 0 &&
791 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_DICT
)
793 ASSERT(context_ptr
->dict
!= NULL
);
794 context_ptr
->data
[context_ptr
->data_used
] = 0;
795 log_info("dict key '%s' with value '%s'", context_ptr
->str
, context_ptr
->data
);
796 if (!ladish_dict_set(context_ptr
->dict
, context_ptr
->str
, context_ptr
->data
))
798 log_error("ladish_dict_set() failed");
799 context_ptr
->error
= XML_TRUE
;
803 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_DICT
)
805 //log_info("</dict>");
806 ASSERT(context_ptr
->dict
!= NULL
);
807 context_ptr
->dict
= NULL
;
809 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_CLIENT
)
811 //log_info("</client>");
812 ASSERT(context_ptr
->client
!= NULL
);
813 context_ptr
->client
= NULL
;
815 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_PORT
)
817 //log_info("</port>");
818 ASSERT(context_ptr
->port
!= NULL
);
819 context_ptr
->port
= NULL
;
821 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_APPLICATION
)
823 context_ptr
->data
[unescape(context_ptr
->data
, context_ptr
->data_used
, context_ptr
->data
)] = 0;
824 unescape(context_ptr
->str
, strlen(context_ptr
->str
) + 1, context_ptr
->str
);
826 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
);
828 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
)
830 log_error("ladish_app_supervisor_add() failed.");
831 context_ptr
->error
= XML_TRUE
;
835 context_ptr
->depth
--;
837 if (context_ptr
->str
!= NULL
)
839 free(context_ptr
->str
);
840 context_ptr
->str
= NULL
;
847 context_ptr
->error
= XML_TRUE
;
853 struct ladish_command_load_studio
855 struct ladish_command command
;
863 ladish_client_handle jclient
,
865 void ** client_iteration_context_ptr_ptr
)
868 ladish_client_handle vclient
;
870 if (strcmp(name
, "system") == 0)
875 if (ladish_client_get_interlink(jclient
, uuid
))
877 ASSERT_NO_PASS
; /* interlinks are not stored in xml yet */
881 vclient
= ladish_graph_find_client_by_name(g_studio
.studio_graph
, name
);
884 log_error("JACK client '%s' has no vclient associated", name
);
888 log_info("Interlinking clients of app '%s'", name
);
889 ladish_client_interlink(jclient
, vclient
);
893 static void interlink_clients(void)
895 ladish_graph_iterate_nodes(g_studio
.jack_graph
, false, NULL
, NULL
, interlink_client
, NULL
, NULL
);
898 #define cmd_ptr ((struct ladish_command_load_studio *)command_context)
900 static bool run(void * command_context
)
908 enum XML_Status xmls
;
909 struct parse_context parse_context
;
911 ASSERT(cmd_ptr
->command
.state
== LADISH_COMMAND_STATE_PENDING
);
913 if (!ladish_studio_compose_filename(cmd_ptr
->studio_name
, &path
, NULL
))
915 log_error("failed to compose path of studio \%s\" file", cmd_ptr
->studio_name
);
919 log_info("Loading studio... ('%s')", path
);
921 if (stat(path
, &st
) != 0)
923 log_error("failed to stat '%s': %d (%s)", path
, errno
, strerror(errno
));
928 g_studio
.name
= cmd_ptr
->studio_name
;
929 cmd_ptr
->studio_name
= NULL
;
931 g_studio
.filename
= path
;
933 if (!jack_reset_all_params())
935 log_error("jack_reset_all_params() failed");
939 fd
= open(path
, O_RDONLY
);
942 log_error("failed to open '%s': %d (%s)", path
, errno
, strerror(errno
));
946 parser
= XML_ParserCreate(NULL
);
949 log_error("XML_ParserCreate() failed to create parser object.");
954 //log_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
956 /* we are expecting that conf file has small enough size to fit in memory */
958 buffer
= XML_GetBuffer(parser
, st
.st_size
);
961 log_error("XML_GetBuffer() failed.");
962 XML_ParserFree(parser
);
967 bytes_read
= read(fd
, buffer
, st
.st_size
);
968 if (bytes_read
!= st
.st_size
)
970 log_error("read() returned unexpected result.");
971 XML_ParserFree(parser
);
976 parse_context
.error
= XML_FALSE
;
977 parse_context
.depth
= -1;
978 parse_context
.str
= NULL
;
979 parse_context
.client
= NULL
;
980 parse_context
.port
= NULL
;
981 parse_context
.dict
= NULL
;
983 XML_SetElementHandler(parser
, callback_elstart
, callback_elend
);
984 XML_SetCharacterDataHandler(parser
, callback_chrdata
);
985 XML_SetUserData(parser
, &parse_context
);
987 xmls
= XML_ParseBuffer(parser
, bytes_read
, XML_TRUE
);
988 if (xmls
== XML_STATUS_ERROR
)
990 if (!parse_context
.error
)
992 log_error("XML_ParseBuffer() failed.");
994 XML_ParserFree(parser
);
999 XML_ParserFree(parser
);
1002 if (parse_context
.error
)
1007 interlink_clients();
1009 g_studio
.persisted
= true;
1010 log_info("Studio loaded. ('%s')", path
);
1012 ladish_graph_dump(g_studio
.jack_graph
);
1013 ladish_graph_dump(g_studio
.studio_graph
);
1015 if (!ladish_studio_publish())
1017 log_error("studio_publish() failed.");
1021 cmd_ptr
->command
.state
= LADISH_COMMAND_STATE_DONE
;
1025 static void destructor(void * command_context
)
1027 log_info("load studio command destructor");
1028 if (cmd_ptr
->studio_name
!= NULL
)
1030 free(cmd_ptr
->studio_name
);
1036 bool ladish_command_load_studio(void * call_ptr
, struct ladish_cqueue
* queue_ptr
, const char * studio_name
)
1038 struct ladish_command_load_studio
* cmd_ptr
;
1039 char * studio_name_dup
;
1041 studio_name_dup
= strdup(studio_name
);
1042 if (studio_name_dup
== NULL
)
1044 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup('%s') failed.", studio_name
);
1048 if (!ladish_command_unload_studio(call_ptr
, queue_ptr
))
1050 goto fail_free_name
;
1053 cmd_ptr
= ladish_command_new(sizeof(struct ladish_command_load_studio
));
1054 if (cmd_ptr
== NULL
)
1056 log_error("ladish_command_new() failed.");
1057 goto fail_drop_unload_command
;
1060 cmd_ptr
->command
.run
= run
;
1061 cmd_ptr
->command
.destructor
= destructor
;
1062 cmd_ptr
->studio_name
= studio_name_dup
;
1064 if (!ladish_cqueue_add_command(queue_ptr
, &cmd_ptr
->command
))
1066 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "ladish_cqueue_add_command() failed.");
1067 goto fail_destroy_command
;
1070 if (!ladish_command_start_studio(call_ptr
, queue_ptr
))
1072 goto fail_drop_load_command
;
1077 fail_drop_load_command
:
1078 ladish_cqueue_drop_command(queue_ptr
);
1080 fail_destroy_command
:
1083 fail_drop_unload_command
:
1084 ladish_cqueue_drop_command(queue_ptr
);
1087 free(studio_name_dup
);