1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 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 #define context_ptr ((struct parse_context *)data)
78 static void callback_chrdata(void * data
, const XML_Char
* s
, int len
)
80 if (context_ptr
->error
)
85 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_PARAMETER
||
86 context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_KEY
||
87 context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_APPLICATION
)
89 if (context_ptr
->data_used
+ len
>= sizeof(context_ptr
->data
))
91 log_error("xml parse max char data length reached");
92 context_ptr
->error
= XML_TRUE
;
96 memcpy(context_ptr
->data
+ context_ptr
->data_used
, s
, len
);
97 context_ptr
->data_used
+= len
;
101 static void callback_elstart(void * data
, const char * el
, const char ** attr
)
105 ladish_port_handle port1
;
106 ladish_port_handle port2
;
110 if (context_ptr
->error
)
115 if (context_ptr
->depth
+ 1 >= MAX_STACK_DEPTH
)
117 log_error("xml parse max stack depth reached");
118 context_ptr
->error
= XML_TRUE
;
122 if (strcmp(el
, "studio") == 0)
124 //log_info("<studio>");
125 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_STUDIO
;
129 if (strcmp(el
, "jack") == 0)
131 //log_info("<jack>");
132 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_JACK
;
136 if (strcmp(el
, "conf") == 0)
138 //log_info("<conf>");
139 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONF
;
143 if (strcmp(el
, "parameter") == 0)
145 //log_info("<parameter>");
146 if ((attr
[0] == NULL
|| attr
[2] != NULL
) || strcmp(attr
[0], "path") != 0)
148 log_error("<parameter> XML element must contain exactly one attribute, named \"path\"");
149 context_ptr
->error
= XML_TRUE
;
153 context_ptr
->str
= strdup(attr
[1]);
154 if (context_ptr
->str
== NULL
)
156 log_error("strdup() failed");
157 context_ptr
->error
= XML_TRUE
;
161 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PARAMETER
;
162 context_ptr
->data_used
= 0;
166 if (strcmp(el
, "clients") == 0)
168 //log_info("<clients>");
169 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CLIENTS
;
173 if (strcmp(el
, "client") == 0)
175 //log_info("<client>");
176 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CLIENT
;
178 if (context_ptr
->client
!= NULL
)
180 log_error("nested clients");
181 context_ptr
->error
= XML_TRUE
;
185 if (context_ptr
->depth
== 3 &&
186 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
187 context_ptr
->element
[1] == PARSE_CONTEXT_JACK
&&
188 context_ptr
->element
[2] == PARSE_CONTEXT_CLIENTS
)
190 if (attr
[0] == NULL
||
195 strcmp(attr
[0], "name") != 0 ||
196 strcmp(attr
[2], "uuid") != 0)
198 log_error("studio/jack/clients/client XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
199 context_ptr
->error
= XML_TRUE
;
203 if (uuid_parse(attr
[3], uuid
) != 0)
205 log_error("cannot parse uuid \"%s\"", attr
[3]);
206 context_ptr
->error
= XML_TRUE
;
210 log_info("jack client \"%s\" with uuid %s", attr
[1], attr
[3]);
212 if (!ladish_client_create(uuid
, false, false, false, &context_ptr
->client
))
214 log_error("ladish_client_create() failed.");
215 context_ptr
->error
= XML_TRUE
;
216 ASSERT(context_ptr
->client
== NULL
);
220 if (!ladish_graph_add_client(g_studio
.jack_graph
, context_ptr
->client
, attr
[1], true))
222 log_error("ladish_graph_add_client() failed to add client '%s' to JACK graph", attr
[1]);
223 context_ptr
->error
= XML_TRUE
;
224 ladish_client_destroy(context_ptr
->client
);
225 context_ptr
->client
= NULL
;
229 else if (context_ptr
->depth
== 2 &&
230 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
231 context_ptr
->element
[1] == PARSE_CONTEXT_CLIENTS
)
233 if (attr
[0] == NULL
||
238 strcmp(attr
[0], "name") != 0 ||
239 strcmp(attr
[2], "uuid") != 0)
241 log_error("studio/clients/client XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
242 context_ptr
->error
= XML_TRUE
;
246 if (uuid_parse(attr
[3], uuid
) != 0)
248 log_error("cannot parse uuid \"%s\"", attr
[3]);
249 context_ptr
->error
= XML_TRUE
;
253 log_info("studio client \"%s\" with uuid %s", attr
[1], attr
[3]);
255 if (!ladish_client_create(uuid
, true, false, false, &context_ptr
->client
))
257 log_error("ladish_client_create() failed.");
258 context_ptr
->error
= XML_TRUE
;
259 ASSERT(context_ptr
->client
== NULL
);
263 if (!ladish_graph_add_client(g_studio
.studio_graph
, context_ptr
->client
, attr
[1], true))
265 log_error("ladish_graph_add_client() failed to add client '%s' to studio graph", attr
[1]);
266 context_ptr
->error
= XML_TRUE
;
267 ladish_client_destroy(context_ptr
->client
);
268 context_ptr
->client
= NULL
;
276 if (strcmp(el
, "ports") == 0)
278 //log_info("<ports>");
279 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PORTS
;
283 if (strcmp(el
, "port") == 0)
285 //log_info("<port>");
286 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PORT
;
288 if (context_ptr
->port
!= NULL
)
290 log_error("nested ports");
291 context_ptr
->error
= XML_TRUE
;
295 if (context_ptr
->client
== NULL
)
297 log_error("client-less port");
298 context_ptr
->error
= XML_TRUE
;
302 if (context_ptr
->depth
== 5 &&
303 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
304 context_ptr
->element
[1] == PARSE_CONTEXT_JACK
&&
305 context_ptr
->element
[2] == PARSE_CONTEXT_CLIENTS
&&
306 context_ptr
->element
[3] == PARSE_CONTEXT_CLIENT
&&
307 context_ptr
->element
[4] == PARSE_CONTEXT_PORTS
)
309 if (attr
[0] == NULL
||
314 strcmp(attr
[0], "name") != 0 ||
315 strcmp(attr
[2], "uuid") != 0)
317 log_error("studio/jack/clients/client/ports/port XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
318 context_ptr
->error
= XML_TRUE
;
322 if (uuid_parse(attr
[3], uuid
) != 0)
324 log_error("cannot parse uuid \"%s\"", attr
[3]);
325 context_ptr
->error
= XML_TRUE
;
329 log_info("jack port \"%s\" with uuid %s", attr
[1], attr
[3]);
331 if (!ladish_port_create(uuid
, &context_ptr
->port
))
333 log_error("ladish_port_create() failed.");
337 if (!ladish_graph_add_port(g_studio
.jack_graph
, context_ptr
->client
, context_ptr
->port
, attr
[1], 0, 0, true))
339 log_error("ladish_graph_add_port() failed.");
340 ladish_port_destroy(context_ptr
->port
);
341 context_ptr
->port
= NULL
;
345 else if (context_ptr
->depth
== 4 &&
346 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
347 context_ptr
->element
[1] == PARSE_CONTEXT_CLIENTS
&&
348 context_ptr
->element
[2] == PARSE_CONTEXT_CLIENT
&&
349 context_ptr
->element
[3] == PARSE_CONTEXT_PORTS
)
351 if (attr
[0] == NULL
||
356 strcmp(attr
[0], "name") != 0 ||
357 strcmp(attr
[2], "uuid") != 0)
359 log_error("studio/clients/client/ports/port XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
360 context_ptr
->error
= XML_TRUE
;
364 if (uuid_parse(attr
[3], uuid
) != 0)
366 log_error("cannot parse uuid \"%s\"", attr
[3]);
367 context_ptr
->error
= XML_TRUE
;
371 log_info("studio port \"%s\" with uuid %s", attr
[1], attr
[3]);
373 context_ptr
->port
= ladish_graph_find_port_by_uuid(g_studio
.jack_graph
, uuid
);
374 if (context_ptr
->port
== NULL
)
376 log_error("studio client with non-jack port %s", attr
[3]);
377 context_ptr
->error
= XML_TRUE
;
381 if (!ladish_graph_add_port(g_studio
.studio_graph
, context_ptr
->client
, context_ptr
->port
, attr
[1], 0, 0, true))
383 log_error("ladish_graph_add_port() failed.");
384 ladish_port_destroy(context_ptr
->port
);
385 context_ptr
->port
= NULL
;
393 if (strcmp(el
, "connections") == 0)
395 //log_info("<connections>");
396 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONNECTIONS
;
400 if (strcmp(el
, "connection") == 0)
402 //log_info("<connection>");
403 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONNECTION
;
405 if (attr
[0] == NULL
||
410 strcmp(attr
[0], "port1") != 0 ||
411 strcmp(attr
[2], "port2") != 0)
413 log_error("studio/connections/connection XML element must contain exactly two attributes, named \"port1\" and \"port2\", in this order");
414 context_ptr
->error
= XML_TRUE
;
418 if (uuid_parse(attr
[1], uuid
) != 0)
420 log_error("cannot parse uuid \"%s\"", attr
[1]);
421 context_ptr
->error
= XML_TRUE
;
425 if (uuid_parse(attr
[3], uuid2
) != 0)
427 log_error("cannot parse uuid \"%s\"", attr
[3]);
428 context_ptr
->error
= XML_TRUE
;
432 log_info("studio connection between port %s and port %s", attr
[1], attr
[3]);
434 port1
= ladish_graph_find_port_by_uuid(g_studio
.studio_graph
, uuid
);
437 log_error("studio client with unknown port %s", attr
[1]);
438 context_ptr
->error
= XML_TRUE
;
442 port2
= ladish_graph_find_port_by_uuid(g_studio
.studio_graph
, uuid2
);
445 log_error("studio client with unknown port %s", attr
[3]);
446 context_ptr
->error
= XML_TRUE
;
450 context_ptr
->connection_id
= ladish_graph_add_connection(g_studio
.studio_graph
, port1
, port2
, true);
451 if (context_ptr
->connection_id
== 0)
453 log_error("ladish_graph_add_connection() failed.");
460 if (strcmp(el
, "applications") == 0)
462 //log_info("<applications>");
463 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_APPLICATIONS
;
467 if (strcmp(el
, "application") == 0)
469 //log_info("<application>");
470 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_APPLICATION
;
472 if (attr
[0] == NULL
||
481 strcmp(attr
[0], "name") != 0 ||
482 strcmp(attr
[2], "terminal") != 0 ||
483 strcmp(attr
[4], "level") != 0 ||
484 strcmp(attr
[6], "autorun") != 0)
486 log_error("'application' XML element must contain exactly four attributes, named \"name\", \"terminal\", \"level\" and \"autorun\", in this order");
487 context_ptr
->error
= XML_TRUE
;
491 if (strcmp(attr
[3], "true") != 0 && strcmp(attr
[3], "false") != 0)
493 log_error("'application@terminal' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
494 context_ptr
->error
= XML_TRUE
;
498 if (strcmp(attr
[7], "true") != 0 && strcmp(attr
[7], "false") != 0)
500 log_error("'application@autorun' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
501 context_ptr
->error
= XML_TRUE
;
505 errno
= 0; /* To distinguish success/failure after call */
506 li_value
= strtol(attr
[5], &end_ptr
, 10);
507 if ((errno
== ERANGE
&& (li_value
== LONG_MAX
|| li_value
== LONG_MIN
)) || (errno
!= 0 && li_value
== 0) || end_ptr
== attr
[5])
509 log_error("'application@level' XML attribute '%s' is not valid integer.", attr
[5]);
510 context_ptr
->error
= XML_TRUE
;
514 if (li_value
< 0 || li_value
> 255)
516 log_error("'application@level' XML attribute '%s' is not valid uint8.", attr
[5]);
517 context_ptr
->error
= XML_TRUE
;
521 context_ptr
->str
= strdup(attr
[1]);
522 if (context_ptr
->str
== NULL
)
524 log_error("strdup() failed");
525 context_ptr
->error
= XML_TRUE
;
529 context_ptr
->terminal
= strcmp(attr
[3], "true") == 0;
530 context_ptr
->autorun
= strcmp(attr
[7], "true") == 0;
531 context_ptr
->level
= (uint8_t)li_value
;
533 context_ptr
->data_used
= 0;
537 if (strcmp(el
, "dict") == 0)
539 //log_info("<dict>");
540 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_DICT
;
542 if (context_ptr
->dict
!= NULL
)
544 log_error("nested dicts");
545 context_ptr
->error
= XML_TRUE
;
549 if (context_ptr
->depth
== 1 &&
550 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
)
552 context_ptr
->dict
= ladish_graph_get_dict(g_studio
.studio_graph
);
553 ASSERT(context_ptr
->dict
!= NULL
);
555 else if (context_ptr
->depth
> 0 &&
556 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_CLIENT
)
558 ASSERT(context_ptr
->client
!= NULL
);
559 context_ptr
->dict
= ladish_client_get_dict(context_ptr
->client
);
560 ASSERT(context_ptr
->dict
!= NULL
);
562 else if (context_ptr
->depth
> 0 &&
563 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_PORT
)
565 ASSERT(context_ptr
->port
!= NULL
);
566 context_ptr
->dict
= ladish_port_get_dict(context_ptr
->port
);
567 ASSERT(context_ptr
->dict
!= NULL
);
569 else if (context_ptr
->depth
> 0 &&
570 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_CONNECTION
)
572 ASSERT(context_ptr
->port
!= NULL
);
573 context_ptr
->dict
= ladish_graph_get_connection_dict(g_studio
.studio_graph
, context_ptr
->connection_id
);
574 ASSERT(context_ptr
->dict
!= NULL
);
578 log_error("unexpected dict XML element");
579 context_ptr
->error
= XML_TRUE
;
586 if (strcmp(el
, "key") == 0)
589 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_KEY
;
591 if (context_ptr
->dict
== NULL
)
593 log_error("dict-less key");
594 context_ptr
->error
= XML_TRUE
;
598 if (attr
[0] == NULL
||
601 strcmp(attr
[0], "name") != 0)
603 log_error("dict/key XML element must contain exactly one attributes, named \"name\".");
604 context_ptr
->error
= XML_TRUE
;
608 context_ptr
->str
= strdup(attr
[1]);
609 if (context_ptr
->str
== NULL
)
611 log_error("strdup() failed");
612 context_ptr
->error
= XML_TRUE
;
616 context_ptr
->data_used
= 0;
621 log_error("unknown element \"%s\"", el
);
622 context_ptr
->error
= XML_TRUE
;
625 static void callback_elend(void * data
, const char * el
)
633 struct jack_parameter_variant parameter
;
636 if (context_ptr
->error
)
641 //log_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
643 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_PARAMETER
&&
644 context_ptr
->depth
== 3 &&
645 context_ptr
->element
[0] == PARSE_CONTEXT_STUDIO
&&
646 context_ptr
->element
[1] == PARSE_CONTEXT_JACK
&&
647 context_ptr
->element
[2] == PARSE_CONTEXT_CONF
)
649 context_ptr
->data
[context_ptr
->data_used
] = 0;
651 //log_info("'%s' with value '%s'", context_ptr->str, context_ptr->data);
653 dst
= address
= strdup(context_ptr
->str
);
654 src
= context_ptr
->str
+ 1;
657 sep
= strchr(src
, '/');
660 src_len
= strlen(src
);
667 dst_len
= unescape(src
, src_len
, dst
);
672 ASSERT(*src
== '/' || *src
== 0);
676 src
++; /* skip separator */
683 *dst
= 0; /* ASCIZZ */
685 if (!jack_proxy_get_parameter_value(address
, &is_set
, ¶meter
))
687 log_error("jack_proxy_get_parameter_value() failed");
688 goto fail_free_address
;
691 if (parameter
.type
== jack_string
)
693 free(parameter
.value
.string
);
696 switch (parameter
.type
)
699 log_info("%s value is %s (boolean)", context_ptr
->str
, context_ptr
->data
);
700 if (strcmp(context_ptr
->data
, "true") == 0)
702 parameter
.value
.boolean
= true;
704 else if (strcmp(context_ptr
->data
, "false") == 0)
706 parameter
.value
.boolean
= false;
710 log_error("bad value for a bool jack param");
711 goto fail_free_address
;
715 log_info("%s value is %s (string)", context_ptr
->str
, context_ptr
->data
);
716 parameter
.value
.string
= context_ptr
->data
;
719 log_debug("%s value is %u/%c (byte/char)", context_ptr
->str
, *context_ptr
->data
, *context_ptr
->data
);
720 if (context_ptr
->data
[0] == 0 ||
721 context_ptr
->data
[1] != 0)
723 log_error("bad value for a char jack param");
724 goto fail_free_address
;
726 parameter
.value
.byte
= context_ptr
->data
[0];
729 log_info("%s value is %s (uint32)", context_ptr
->str
, context_ptr
->data
);
730 if (sscanf(context_ptr
->data
, "%" PRIu32
, ¶meter
.value
.uint32
) != 1)
732 log_error("bad value for an uint32 jack param");
733 goto fail_free_address
;
737 log_info("%s value is %s (int32)", context_ptr
->str
, context_ptr
->data
);
738 if (sscanf(context_ptr
->data
, "%" PRIi32
, ¶meter
.value
.int32
) != 1)
740 log_error("bad value for an int32 jack param");
741 goto fail_free_address
;
745 log_error("unknown jack parameter type %d of %s", (int)parameter
.type
, context_ptr
->str
);
746 goto fail_free_address
;
749 if (!jack_proxy_set_parameter_value(address
, ¶meter
))
751 log_error("jack_proxy_set_parameter_value() failed");
752 goto fail_free_address
;
757 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_KEY
&&
758 context_ptr
->depth
> 0 &&
759 context_ptr
->element
[context_ptr
->depth
- 1] == PARSE_CONTEXT_DICT
)
761 ASSERT(context_ptr
->dict
!= NULL
);
762 context_ptr
->data
[context_ptr
->data_used
] = 0;
763 log_info("dict key '%s' with value '%s'", context_ptr
->str
, context_ptr
->data
);
764 if (!ladish_dict_set(context_ptr
->dict
, context_ptr
->str
, context_ptr
->data
))
766 log_error("ladish_dict_set() failed");
767 context_ptr
->error
= XML_TRUE
;
771 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_DICT
)
773 //log_info("</dict>");
774 ASSERT(context_ptr
->dict
!= NULL
);
775 context_ptr
->dict
= NULL
;
777 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_CLIENT
)
779 //log_info("</client>");
780 ASSERT(context_ptr
->client
!= NULL
);
781 context_ptr
->client
= NULL
;
783 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_PORT
)
785 //log_info("</port>");
786 ASSERT(context_ptr
->port
!= NULL
);
787 context_ptr
->port
= NULL
;
789 else if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_APPLICATION
)
791 context_ptr
->data
[context_ptr
->data_used
] = 0;
792 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
);
794 if (!ladish_app_supervisor_add(g_studio
.app_supervisor
, context_ptr
->str
, context_ptr
->autorun
, context_ptr
->data
, context_ptr
->terminal
, context_ptr
->level
))
796 log_error("ladish_app_supervisor_add() failed.");
797 context_ptr
->error
= XML_TRUE
;
801 context_ptr
->depth
--;
803 if (context_ptr
->str
!= NULL
)
805 free(context_ptr
->str
);
806 context_ptr
->str
= NULL
;
813 context_ptr
->error
= XML_TRUE
;
819 struct ladish_command_load_studio
821 struct ladish_command command
;
825 #define cmd_ptr ((struct ladish_command_load_studio *)command_context)
827 static bool run(void * command_context
)
835 enum XML_Status xmls
;
836 struct parse_context parse_context
;
838 ASSERT(cmd_ptr
->command
.state
== LADISH_COMMAND_STATE_PENDING
);
840 if (!studio_compose_filename(cmd_ptr
->studio_name
, &path
, NULL
))
842 log_error("failed to compose path of studio \%s\" file", cmd_ptr
->studio_name
);
846 log_info("Loading studio... ('%s')", path
);
848 if (stat(path
, &st
) != 0)
850 log_error("failed to stat '%s': %d (%s)", path
, errno
, strerror(errno
));
855 g_studio
.name
= cmd_ptr
->studio_name
;
856 cmd_ptr
->studio_name
= NULL
;
858 g_studio
.filename
= path
;
860 if (!jack_reset_all_params())
862 log_error("jack_reset_all_params() failed");
866 fd
= open(path
, O_RDONLY
);
869 log_error("failed to open '%s': %d (%s)", path
, errno
, strerror(errno
));
873 parser
= XML_ParserCreate(NULL
);
876 log_error("XML_ParserCreate() failed to create parser object.");
881 //log_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
883 /* we are expecting that conf file has small enough size to fit in memory */
885 buffer
= XML_GetBuffer(parser
, st
.st_size
);
888 log_error("XML_GetBuffer() failed.");
889 XML_ParserFree(parser
);
894 bytes_read
= read(fd
, buffer
, st
.st_size
);
895 if (bytes_read
!= st
.st_size
)
897 log_error("read() returned unexpected result.");
898 XML_ParserFree(parser
);
903 parse_context
.error
= XML_FALSE
;
904 parse_context
.depth
= -1;
905 parse_context
.str
= NULL
;
906 parse_context
.client
= NULL
;
907 parse_context
.port
= NULL
;
908 parse_context
.dict
= NULL
;
910 XML_SetElementHandler(parser
, callback_elstart
, callback_elend
);
911 XML_SetCharacterDataHandler(parser
, callback_chrdata
);
912 XML_SetUserData(parser
, &parse_context
);
914 xmls
= XML_ParseBuffer(parser
, bytes_read
, XML_TRUE
);
915 if (xmls
== XML_STATUS_ERROR
)
917 if (!parse_context
.error
)
919 log_error("XML_ParseBuffer() failed.");
921 XML_ParserFree(parser
);
926 XML_ParserFree(parser
);
929 if (parse_context
.error
)
934 g_studio
.persisted
= true;
935 log_info("Studio loaded. ('%s')", path
);
937 ladish_graph_dump(g_studio
.jack_graph
);
938 ladish_graph_dump(g_studio
.studio_graph
);
940 if (!studio_publish())
942 log_error("studio_publish() failed.");
946 cmd_ptr
->command
.state
= LADISH_COMMAND_STATE_DONE
;
950 static void destructor(void * command_context
)
952 log_info("load studio command destructor");
953 if (cmd_ptr
->studio_name
!= NULL
)
955 free(cmd_ptr
->studio_name
);
961 bool ladish_command_load_studio(void * call_ptr
, struct ladish_cqueue
* queue_ptr
, const char * studio_name
)
963 struct ladish_command_load_studio
* cmd_ptr
;
964 char * studio_name_dup
;
966 studio_name_dup
= strdup(studio_name
);
967 if (studio_name_dup
== NULL
)
969 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup('%s') failed.", studio_name
);
973 if (!ladish_command_unload_studio(call_ptr
, queue_ptr
))
978 cmd_ptr
= ladish_command_new(sizeof(struct ladish_command
));
981 log_error("ladish_command_new() failed.");
982 goto fail_drop_unload_command
;
985 cmd_ptr
->command
.run
= run
;
986 cmd_ptr
->command
.destructor
= destructor
;
987 cmd_ptr
->studio_name
= studio_name_dup
;
989 if (!ladish_cqueue_add_command(queue_ptr
, &cmd_ptr
->command
))
991 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "ladish_cqueue_add_command() failed.");
992 goto fail_destroy_command
;
995 if (!ladish_command_start_studio(call_ptr
, queue_ptr
))
997 goto fail_drop_load_command
;
1002 fail_drop_load_command
:
1003 ladish_cqueue_drop_command(queue_ptr
);
1005 fail_destroy_command
:
1008 fail_drop_unload_command
:
1009 ladish_cqueue_drop_command(queue_ptr
);
1012 free(studio_name_dup
);