Clear studio if load was not successful
[ladish.git] / daemon / studio.c
blobb37a6a4a4107d2b71ed40563431a555f3b28f67c
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the studio singleton object
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <dirent.h>
34 #include <expat.h>
36 #include "../jack_proxy.h"
37 #include "patchbay.h"
38 #include "../dbus_constants.h"
39 #include "control.h"
40 #include "../catdup.h"
41 #include "../dbus/error.h"
42 #include "dirhelpers.h"
44 #define STUDIOS_DIR "/studios/"
45 char * g_studios_dir;
47 #define STUDIO_HEADER_TEXT BASE_NAME " Studio configuration.\n"
49 extern const interface_t g_interface_studio;
51 struct studio
53 /* this must be first member of struct studio because object_path_new() assumes all interfaces have same context */
54 struct patchbay_implementator patchbay_impl;
56 struct list_head all_connections; /* All connections (studio guts and all rooms). Including superconnections. */
57 struct list_head all_ports; /* All ports (studio guts and all rooms) */
58 struct list_head all_clients; /* All clients (studio guts and all rooms) */
59 struct list_head jack_connections; /* JACK connections (studio guts and all rooms). Including superconnections, excluding virtual connections. */
60 struct list_head jack_ports; /* JACK ports (studio guts and all rooms). Excluding virtual ports. */
61 struct list_head jack_clients; /* JACK clients (studio guts and all rooms). Excluding virtual clients. */
62 struct list_head rooms; /* Rooms connected to the studio */
63 struct list_head clients; /* studio clients (studio guts and room links) */
64 struct list_head ports; /* studio ports (studio guts and room links) */
66 bool persisted:1; /* Studio has on-disk representation, i.e. can be reloaded from disk */
67 bool modified:1; /* Studio needs saving */
68 bool jack_conf_valid:1; /* JACK server configuration obtained successfully */
69 bool jack_running:1; /* JACK server is running */
71 struct list_head jack_conf; /* root of the conf tree */
72 struct list_head jack_params; /* list of conf tree leaves */
74 object_path_t * dbus_object;
76 struct list_head event_queue;
78 char * name;
79 char * filename;
80 } g_studio;
82 #define EVENT_JACK_START 0
83 #define EVENT_JACK_STOP 1
85 struct event
87 struct list_head siblings;
88 unsigned int type;
91 #define JACK_CONF_MAX_ADDRESS_SIZE 1024
93 struct jack_conf_parameter
95 struct list_head siblings; /* siblings in container children list */
96 struct list_head leaves; /* studio::jack_param siblings */
97 char * name;
98 struct jack_conf_container * parent_ptr;
99 char address[JACK_CONF_MAX_ADDRESS_SIZE];
100 struct jack_parameter_variant parameter;
103 struct jack_conf_container
105 struct list_head siblings;
106 char * name;
107 struct jack_conf_container * parent_ptr;
108 bool children_leafs; /* if true, children are "jack_conf_parameter"s, if false, children are "jack_conf_container"s */
109 struct list_head children;
112 struct conf_callback_context
114 char address[JACK_CONF_MAX_ADDRESS_SIZE];
115 struct list_head * container_ptr;
116 struct jack_conf_container * parent_ptr;
119 #define PARSE_CONTEXT_ROOT 0
120 #define PARSE_CONTEXT_STUDIO 1
121 #define PARSE_CONTEXT_JACK 2
122 #define PARSE_CONTEXT_CONF 3
123 #define PARSE_CONTEXT_PARAMETER 4
125 #define MAX_STACK_DEPTH 10
126 #define MAX_DATA_SIZE 1024
128 struct parse_context
130 void * call_ptr;
131 XML_Bool error;
132 unsigned int element[MAX_STACK_DEPTH];
133 signed int depth;
134 char data[MAX_DATA_SIZE];
135 int data_used;
136 char * path;
139 bool
140 jack_conf_container_create(
141 struct jack_conf_container ** container_ptr_ptr,
142 const char * name)
144 struct jack_conf_container * container_ptr;
146 container_ptr = malloc(sizeof(struct jack_conf_container));
147 if (container_ptr == NULL)
149 lash_error("malloc() failed to allocate struct jack_conf_container");
150 goto fail;
153 container_ptr->name = strdup(name);
154 if (container_ptr->name == NULL)
156 lash_error("strdup() failed to duplicate \"%s\"", name);
157 goto fail_free;
160 INIT_LIST_HEAD(&container_ptr->children);
161 container_ptr->children_leafs = false;
163 *container_ptr_ptr = container_ptr;
164 return true;
166 fail_free:
167 free(container_ptr);
169 fail:
170 return false;
173 bool
174 jack_conf_parameter_create(
175 struct jack_conf_parameter ** parameter_ptr_ptr,
176 const char * name)
178 struct jack_conf_parameter * parameter_ptr;
180 parameter_ptr = malloc(sizeof(struct jack_conf_parameter));
181 if (parameter_ptr == NULL)
183 lash_error("malloc() failed to allocate struct jack_conf_parameter");
184 goto fail;
187 parameter_ptr->name = strdup(name);
188 if (parameter_ptr->name == NULL)
190 lash_error("strdup() failed to duplicate \"%s\"", name);
191 goto fail_free;
194 *parameter_ptr_ptr = parameter_ptr;
195 return true;
197 fail_free:
198 free(parameter_ptr);
200 fail:
201 return false;
204 void
205 jack_conf_parameter_destroy(
206 struct jack_conf_parameter * parameter_ptr)
208 #if 0
209 lash_info("jack_conf_parameter destroy");
211 switch (parameter_ptr->parameter.type)
213 case jack_boolean:
214 lash_info("%s value is %s (boolean)", parameter_ptr->name, parameter_ptr->parameter.value.boolean ? "true" : "false");
215 break;
216 case jack_string:
217 lash_info("%s value is %s (string)", parameter_ptr->name, parameter_ptr->parameter.value.string);
218 break;
219 case jack_byte:
220 lash_info("%s value is %u/%c (byte/char)", parameter_ptr->name, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
221 break;
222 case jack_uint32:
223 lash_info("%s value is %u (uint32)", parameter_ptr->name, (unsigned int)parameter_ptr->parameter.value.uint32);
224 break;
225 case jack_int32:
226 lash_info("%s value is %u (int32)", parameter_ptr->name, (signed int)parameter_ptr->parameter.value.int32);
227 break;
228 default:
229 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, parameter_ptr->name);
230 break;
232 #endif
234 if (parameter_ptr->parameter.type == jack_string)
236 free(parameter_ptr->parameter.value.string);
239 free(parameter_ptr->name);
240 free(parameter_ptr);
243 void
244 jack_conf_container_destroy(
245 struct jack_conf_container * container_ptr)
247 struct list_head * node_ptr;
249 //lash_info("\"%s\" jack_conf_parameter destroy", container_ptr->name);
251 if (!container_ptr->children_leafs)
253 while (!list_empty(&container_ptr->children))
255 node_ptr = container_ptr->children.next;
256 list_del(node_ptr);
257 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
260 else
262 while (!list_empty(&container_ptr->children))
264 node_ptr = container_ptr->children.next;
265 list_del(node_ptr);
266 jack_conf_parameter_destroy(list_entry(node_ptr, struct jack_conf_parameter, siblings));
270 free(container_ptr->name);
271 free(container_ptr);
274 #define context_ptr ((struct conf_callback_context *)context)
276 static
277 bool
278 conf_callback(
279 void * context,
280 bool leaf,
281 const char * address,
282 char * child)
284 char path[JACK_CONF_MAX_ADDRESS_SIZE];
285 const char * component;
286 char * dst;
287 size_t len;
288 bool is_set;
289 struct jack_conf_container * parent_ptr;
290 struct jack_conf_container * container_ptr;
291 struct jack_conf_parameter * parameter_ptr;
293 parent_ptr = context_ptr->parent_ptr;
295 if (parent_ptr == NULL && strcmp(child, "drivers") == 0)
297 lash_debug("ignoring drivers branch");
298 return true;
301 dst = path;
302 component = address;
303 while (*component != 0)
305 len = strlen(component);
306 memcpy(dst, component, len);
307 dst[len] = ':';
308 component += len + 1;
309 dst += len + 1;
312 strcpy(dst, child);
314 /* address always is same buffer as the one supplied through context pointer */
315 assert(context_ptr->address == address);
316 dst = (char *)component;
318 len = strlen(child) + 1;
319 memcpy(dst, child, len);
320 dst[len] = 0;
322 if (leaf)
324 lash_debug("%s (leaf)", path);
326 if (parent_ptr == NULL)
328 lash_error("jack conf parameters can't appear in root container");
329 return false;
332 if (!parent_ptr->children_leafs)
334 if (!list_empty(&parent_ptr->children))
336 lash_error("jack conf parameters cant be mixed with containers at same hierarchy level");
337 return false;
340 parent_ptr->children_leafs = true;
343 if (!jack_conf_parameter_create(&parameter_ptr, child))
345 lash_error("jack_conf_parameter_create() failed");
346 return false;
349 if (!jack_proxy_get_parameter_value(context_ptr->address, &is_set, &parameter_ptr->parameter))
351 lash_error("cannot get value of %s", path);
352 return false;
355 if (is_set)
357 #if 0
358 switch (parameter_ptr->parameter.type)
360 case jack_boolean:
361 lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false");
362 break;
363 case jack_string:
364 lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string);
365 break;
366 case jack_byte:
367 lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
368 break;
369 case jack_uint32:
370 lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32);
371 break;
372 case jack_int32:
373 lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32);
374 break;
375 default:
376 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
377 jack_conf_parameter_destroy(parameter_ptr);
378 return false;
380 #endif
382 parameter_ptr->parent_ptr = parent_ptr;
383 memcpy(parameter_ptr->address, context_ptr->address, JACK_CONF_MAX_ADDRESS_SIZE);
384 list_add_tail(&parameter_ptr->siblings, &parent_ptr->children);
385 list_add_tail(&parameter_ptr->leaves, &g_studio.jack_params);
387 else
389 jack_conf_parameter_destroy(parameter_ptr);
392 else
394 lash_debug("%s (container)", path);
396 if (parent_ptr != NULL && parent_ptr->children_leafs)
398 lash_error("jack conf containers cant be mixed with parameters at same hierarchy level");
399 return false;
402 if (!jack_conf_container_create(&container_ptr, child))
404 lash_error("jack_conf_container_create() failed");
405 return false;
408 container_ptr->parent_ptr = parent_ptr;
410 if (parent_ptr == NULL)
412 list_add_tail(&container_ptr->siblings, &g_studio.jack_conf);
414 else
416 list_add_tail(&container_ptr->siblings, &parent_ptr->children);
419 context_ptr->parent_ptr = container_ptr;
421 if (!jack_proxy_read_conf_container(context_ptr->address, context, conf_callback))
423 lash_error("cannot read container %s", path);
424 return false;
427 context_ptr->parent_ptr = parent_ptr;
430 *dst = 0;
432 return true;
435 #undef context_ptr
437 bool studio_fetch_jack_settings()
439 struct conf_callback_context context;
441 context.address[0] = 0;
442 context.container_ptr = &g_studio.jack_conf;
443 context.parent_ptr = NULL;
445 if (!jack_proxy_read_conf_container(context.address, &context, conf_callback))
447 lash_error("jack_proxy_read_conf_container() failed.");
448 return false;
451 return true;
454 bool studio_name_generate(char ** name_ptr)
456 time_t now;
457 char timestamp_str[26];
458 char * name;
460 time(&now);
461 //ctime_r(&now, timestamp_str);
462 //timestamp_str[24] = 0;
463 snprintf(timestamp_str, sizeof(timestamp_str), "%llu", (unsigned long long)now);
465 name = catdup("Studio ", timestamp_str);
466 if (name == NULL)
468 lash_error("catdup failed to create studio name");
469 return false;
472 *name_ptr = name;
473 return true;
476 bool
477 studio_activate(void)
479 object_path_t * object;
481 assert(g_studio.name != NULL);
483 object = object_path_new(STUDIO_OBJECT_PATH, &g_studio, 2, &g_interface_studio, &g_interface_patchbay);
484 if (object == NULL)
486 lash_error("object_path_new() failed");
487 return false;
490 if (!object_path_register(g_dbus_connection, object))
492 lash_error("object_path_register() failed");
493 object_path_destroy(g_dbus_connection, object);
494 return false;
497 lash_info("Studio D-Bus object created. \"%s\"", g_studio.name);
499 g_studio.dbus_object = object;
501 emit_studio_appeared();
503 return true;
506 void
507 studio_clear(void)
509 struct list_head * node_ptr;
511 g_studio.modified = false;
512 g_studio.persisted = false;
514 INIT_LIST_HEAD(&g_studio.jack_params); /* we will destroy the leaves as part of tree destroy traversal */
515 while (!list_empty(&g_studio.jack_conf))
517 node_ptr = g_studio.jack_conf.next;
518 list_del(node_ptr);
519 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
522 g_studio.jack_conf_valid = false;
524 if (g_studio.jack_running)
526 lash_info("Stopping JACK server...");
528 if (jack_proxy_stop_server())
530 g_studio.jack_running = false;
532 else
534 lash_error("Stopping JACK server failed.");
538 if (g_studio.dbus_object != NULL)
540 object_path_destroy(g_dbus_connection, g_studio.dbus_object);
541 g_studio.dbus_object = NULL;
542 emit_studio_disappeared();
545 if (g_studio.name != NULL)
547 free(g_studio.name);
548 g_studio.name = NULL;
551 if (g_studio.filename != NULL)
553 free(g_studio.filename);
554 g_studio.filename = NULL;
558 void
559 studio_clear_if_not_persisted(void)
561 if (!g_studio.persisted)
563 studio_clear();
564 return;
568 void on_event_jack_started(void)
570 if (g_studio.dbus_object == NULL)
572 assert(g_studio.name == NULL);
573 if (!studio_name_generate(&g_studio.name))
575 lash_error("studio_name_generate() failed.");
576 return;
579 studio_activate();
582 if (!studio_fetch_jack_settings(g_studio))
584 lash_error("studio_fetch_jack_settings() failed.");
586 studio_clear_if_not_persisted();
587 return;
590 lash_info("jack conf successfully retrieved");
591 g_studio.jack_conf_valid = true;
592 g_studio.jack_running = true;
595 void on_event_jack_stopped(void)
597 studio_clear_if_not_persisted();
599 g_studio.jack_running = false;
601 /* TODO: if user wants, restart jack server and reconnect all jack apps to it */
604 void studio_run(void)
606 struct event * event_ptr;
608 while (!list_empty(&g_studio.event_queue))
610 event_ptr = list_entry(g_studio.event_queue.next, struct event, siblings);
611 list_del(g_studio.event_queue.next);
613 switch (event_ptr->type)
615 case EVENT_JACK_START:
616 on_event_jack_started();
617 break;
618 case EVENT_JACK_STOP:
619 on_event_jack_stopped();
620 break;
623 free(event_ptr);
627 static void on_jack_server_started(void)
629 struct event * event_ptr;
631 lash_info("JACK server start detected.");
633 event_ptr = malloc(sizeof(struct event));
634 if (event_ptr == NULL)
636 lash_error("malloc() failed to allocate struct event. Ignoring JACK start.");
637 return;
640 event_ptr->type = EVENT_JACK_START;
641 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
644 static void on_jack_server_stopped(void)
646 struct event * event_ptr;
648 lash_info("JACK server stop detected.");
650 event_ptr = malloc(sizeof(struct event));
651 if (event_ptr == NULL)
653 lash_error("malloc() failed to allocate struct event. Ignoring JACK stop.");
654 return;
657 event_ptr->type = EVENT_JACK_STOP;
658 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
661 static void on_jack_server_appeared(void)
663 lash_info("JACK controller appeared.");
666 static void on_jack_server_disappeared(void)
668 lash_info("JACK controller disappeared.");
671 #define studio_ptr ((struct studio *)this)
673 uint64_t
674 studio_get_graph_version(
675 void * this)
677 //lash_info("studio_get_graph_version() called");
678 return 1;
681 #undef studio_ptr
683 bool studio_init(void)
685 lash_info("studio object construct");
687 g_studios_dir = catdup(g_base_dir, STUDIOS_DIR);
688 if (g_studios_dir == NULL)
690 lash_error("catdup failed for '%s' and '%s'", g_base_dir, STUDIOS_DIR);
691 return false;
694 if (!ensure_dir_exist(g_studios_dir, 0700))
696 free(g_studios_dir);
697 return false;
700 g_studio.patchbay_impl.this = &g_studio;
701 g_studio.patchbay_impl.get_graph_version = studio_get_graph_version;
703 INIT_LIST_HEAD(&g_studio.all_connections);
704 INIT_LIST_HEAD(&g_studio.all_ports);
705 INIT_LIST_HEAD(&g_studio.all_clients);
706 INIT_LIST_HEAD(&g_studio.jack_connections);
707 INIT_LIST_HEAD(&g_studio.jack_ports);
708 INIT_LIST_HEAD(&g_studio.jack_clients);
709 INIT_LIST_HEAD(&g_studio.rooms);
710 INIT_LIST_HEAD(&g_studio.clients);
711 INIT_LIST_HEAD(&g_studio.ports);
713 INIT_LIST_HEAD(&g_studio.jack_conf);
714 INIT_LIST_HEAD(&g_studio.jack_params);
716 INIT_LIST_HEAD(&g_studio.event_queue);
718 g_studio.dbus_object = NULL;
719 g_studio.name = NULL;
720 g_studio.filename = NULL;
721 g_studio.jack_running = false;
722 studio_clear();
724 if (!jack_proxy_init(
725 on_jack_server_started,
726 on_jack_server_stopped,
727 on_jack_server_appeared,
728 on_jack_server_disappeared))
730 return false;
733 return true;
736 void studio_uninit(void)
738 jack_proxy_uninit();
740 studio_clear();
742 lash_info("studio object destroy");
745 bool studio_is_loaded(void)
747 return g_studio.dbus_object != NULL;
750 void escape(const char ** src_ptr, char ** dst_ptr)
752 const char * src;
753 char * dst;
754 static char hex_digits[] = "0123456789ABCDEF";
756 src = *src_ptr;
757 dst = *dst_ptr;
759 while (*src != 0)
761 switch (*src)
763 case '/': /* used as separator for address components */
764 case '<': /* invalid attribute value char (XML spec) */
765 case '&': /* invalid attribute value char (XML spec) */
766 case '"': /* we store attribute values in double quotes - invalid attribute value char (XML spec) */
767 case '%':
768 dst[0] = '%';
769 dst[1] = hex_digits[*src >> 4];
770 dst[2] = hex_digits[*src & 0x0F];
771 dst += 3;
772 src++;
773 break;
774 default:
775 *dst++ = *src++;
779 *src_ptr = src;
780 *dst_ptr = dst;
783 static bool compose_filename(const char * name, char ** filename_ptr_ptr, char ** backup_filename_ptr_ptr)
785 size_t len_dir;
786 char * p;
787 const char * src;
788 char * filename_ptr;
789 char * backup_filename_ptr;
791 len_dir = strlen(g_studios_dir);
793 filename_ptr = malloc(len_dir + 1 + strlen(name) * 3 + 4 + 1);
794 if (filename_ptr == NULL)
796 lash_error("malloc failed to allocate memory for studio file path");
797 return false;
800 backup_filename_ptr = malloc(len_dir + 1 + strlen(name) * 3 + 4 + 4 + 1);
801 if (backup_filename_ptr == NULL)
803 lash_error("malloc failed to allocate memory for studio backup file path");
804 free(filename_ptr);
805 return false;
808 p = filename_ptr;
809 memcpy(p, g_studios_dir, len_dir);
810 p += len_dir;
812 *p++ = '/';
814 src = name;
815 escape(&src, &p);
816 strcpy(p, ".xml");
818 strcpy(backup_filename_ptr, filename_ptr);
819 strcat(backup_filename_ptr, ".bak");
821 *filename_ptr_ptr = filename_ptr;
822 *backup_filename_ptr_ptr = backup_filename_ptr;
824 return true;
827 bool
828 write_string(int fd, const char * string, void * call_ptr)
830 size_t len;
832 len = strlen(string);
834 if (write(fd, string, len) != len)
836 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "write() failed to write config file.");
837 return false;
840 return true;
843 bool
844 write_jack_parameter(
845 int fd,
846 const char * indent,
847 struct jack_conf_parameter * parameter_ptr,
848 void * call_ptr)
850 const char * src;
851 char * dst;
852 char path[JACK_CONF_MAX_ADDRESS_SIZE * 3]; /* encode each char in three bytes (percent encoding) */
853 const char * content;
854 char valbuf[100];
856 /* compose the parameter path, percent-encode "bad" chars */
857 src = parameter_ptr->address;
858 dst = path;
861 *dst++ = '/';
862 escape(&src, &dst);
863 src++;
865 while (*src != 0);
866 *dst = 0;
868 if (!write_string(fd, indent, call_ptr))
870 return false;
873 if (!write_string(fd, "<parameter path=\"", call_ptr))
875 return false;
878 if (!write_string(fd, path, call_ptr))
880 return false;
883 if (!write_string(fd, "\">", call_ptr))
885 return false;
888 switch (parameter_ptr->parameter.type)
890 case jack_boolean:
891 content = parameter_ptr->parameter.value.boolean ? "true" : "false";
892 lash_debug("%s value is %s (boolean)", path, content);
893 break;
894 case jack_string:
895 content = parameter_ptr->parameter.value.string;
896 lash_debug("%s value is %s (string)", path, content);
897 break;
898 case jack_byte:
899 valbuf[0] = (char)parameter_ptr->parameter.value.byte;
900 valbuf[1] = 0;
901 content = valbuf;
902 lash_debug("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
903 break;
904 case jack_uint32:
905 snprintf(valbuf, sizeof(valbuf), "%" PRIu32, parameter_ptr->parameter.value.uint32);
906 content = valbuf;
907 lash_debug("%s value is %s (uint32)", path, content);
908 break;
909 case jack_int32:
910 snprintf(valbuf, sizeof(valbuf), "%" PRIi32, parameter_ptr->parameter.value.int32);
911 content = valbuf;
912 lash_debug("%s value is %s (int32)", path, content);
913 break;
914 default:
915 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
916 return false;
919 if (!write_string(fd, content, call_ptr))
921 return false;
924 if (!write_string(fd, "</parameter>\n", call_ptr))
926 return false;
929 return true;
932 bool studio_save(void * call_ptr)
934 struct list_head * node_ptr;
935 struct jack_conf_parameter * parameter_ptr;
936 int fd;
937 time_t timestamp;
938 char timestamp_str[26];
939 bool ret;
940 char * filename; /* filename */
941 char * bak_filename; /* filename of the backup file */
942 char * old_filename; /* filename where studio was persisted before save */
943 struct stat st;
945 time(&timestamp);
946 ctime_r(&timestamp, timestamp_str);
947 timestamp_str[24] = 0;
949 ret = false;
951 if (!compose_filename(g_studio.name, &filename, &bak_filename))
953 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename");
954 goto exit;
957 if (g_studio.filename == NULL)
959 /* saving studio for first time */
960 g_studio.filename = filename;
961 free(bak_filename);
962 bak_filename = NULL;
963 old_filename = NULL;
965 else if (strcmp(g_studio.filename, filename) == 0)
967 /* saving already persisted studio that was not renamed */
968 old_filename = filename;
970 else
972 /* saving renamed studio */
973 old_filename = g_studio.filename;
974 g_studio.filename = filename;
977 filename = NULL;
978 assert(g_studio.filename != NULL);
979 assert(g_studio.filename != old_filename);
980 assert(g_studio.filename != bak_filename);
982 if (bak_filename != NULL)
984 assert(old_filename != NULL);
986 if (stat(old_filename, &st) == 0) /* if old filename does not exist, rename with fail */
988 if (rename(old_filename, bak_filename) != 0)
990 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "rename(%s, %s) failed: %d (%s)", old_filename, bak_filename, errno, strerror(errno));
991 goto free_filenames;
994 else
996 /* mark that there is no backup file */
997 free(bak_filename);
998 bak_filename = NULL;
1002 lash_info("saving studio... (%s)", g_studio.filename);
1004 fd = open(g_studio.filename, O_WRONLY | O_TRUNC | O_CREAT, 0700);
1005 if (fd == -1)
1007 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "open(%s) failed: %d (%s)", g_studio.filename, errno, strerror(errno));
1008 goto rename_back;
1011 if (!write_string(fd, "<?xml version=\"1.0\"?>\n", call_ptr))
1013 goto close;
1016 if (!write_string(fd, "<!--\n", call_ptr))
1018 goto close;
1021 if (!write_string(fd, STUDIO_HEADER_TEXT, call_ptr))
1023 goto close;
1026 if (!write_string(fd, "-->\n", call_ptr))
1028 goto close;
1031 if (!write_string(fd, "<!-- ", call_ptr))
1033 goto close;
1036 if (!write_string(fd, timestamp_str, call_ptr))
1038 goto close;
1041 if (!write_string(fd, " -->\n", call_ptr))
1043 goto close;
1046 if (!write_string(fd, "<studio>\n", call_ptr))
1048 goto close;
1051 if (!write_string(fd, " <jack>\n", call_ptr))
1053 goto close;
1056 if (!write_string(fd, " <conf>\n", call_ptr))
1058 goto close;
1061 list_for_each(node_ptr, &g_studio.jack_params)
1063 parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves);
1065 if (!write_jack_parameter(fd, " ", parameter_ptr, call_ptr))
1067 goto close;
1071 if (!write_string(fd, " </conf>\n", call_ptr))
1073 goto close;
1076 if (!write_string(fd, " </jack>\n", call_ptr))
1078 goto close;
1081 if (!write_string(fd, "</studio>\n", call_ptr))
1083 goto close;
1086 lash_info("studio saved. (%s)", g_studio.filename);
1087 g_studio.persisted = true;
1088 ret = true;
1090 close:
1091 close(fd);
1093 rename_back:
1094 if (!ret && bak_filename != NULL)
1096 /* save failed - try to rename the backup file back */
1097 if (rename(bak_filename, g_studio.filename) != 0)
1099 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "rename(%s, %s) failed: %d (%s)", bak_filename, g_studio.filename, errno, strerror(errno));
1103 free_filenames:
1104 if (bak_filename != NULL)
1106 free(bak_filename);
1109 if (old_filename != NULL)
1111 free(old_filename);
1114 assert(filename == NULL);
1115 assert(g_studio.filename != NULL);
1117 exit:
1118 return ret;
1121 bool studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime))
1123 DIR * dir;
1124 struct dirent * dentry;
1125 size_t len;
1126 struct stat st;
1127 char * path;
1129 dir = opendir(g_studios_dir);
1130 if (dir == NULL)
1132 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Cannot open directory '%s': %d (%s)", g_studios_dir, errno, strerror(errno));
1133 return false;
1136 while ((dentry = readdir(dir)) != NULL)
1138 if (dentry->d_type != DT_REG)
1139 continue;
1141 len = strlen(dentry->d_name);
1142 if (len < 4 || strcmp(dentry->d_name + (len - 4), ".xml"))
1143 continue;
1145 path = catdup(g_studios_dir, dentry->d_name);
1146 if (path == NULL)
1148 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup() failed");
1149 return false;
1152 /* TODO: unescape */
1153 dentry->d_name[len - 4] = 0;
1155 if (stat(path, &st) != 0)
1157 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
1158 free(path);
1159 return false;
1162 free(path);
1164 if (!callback(call_ptr, context, dentry->d_name, st.st_mtime))
1166 closedir(dir);
1167 return false;
1171 closedir(dir);
1172 return true;
1175 #define context_ptr ((struct parse_context *)data)
1177 static void callback_chrdata(void * data, const XML_Char * s, int len)
1179 if (context_ptr->error)
1181 return;
1184 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER)
1186 if (context_ptr->data_used + len >= sizeof(context_ptr->data))
1188 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "xml parse max char data length reached");
1189 context_ptr->error = XML_TRUE;
1190 return;
1193 memcpy(context_ptr->data + context_ptr->data_used, s, len);
1194 context_ptr->data_used += len;
1198 static void callback_elstart(void * data, const char * el, const char ** attr)
1200 if (context_ptr->error)
1202 return;
1205 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
1207 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "xml parse max stack depth reached");
1208 context_ptr->error = XML_TRUE;
1209 return;
1212 if (strcmp(el, "studio") == 0)
1214 //lash_info("<studio>");
1215 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_STUDIO;
1216 return;
1219 if (strcmp(el, "jack") == 0)
1221 //lash_info("<jack>");
1222 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
1223 return;
1226 if (strcmp(el, "conf") == 0)
1228 //lash_info("<conf>");
1229 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONF;
1230 return;
1233 if (strcmp(el, "parameter") == 0)
1235 //lash_info("<parameter>");
1236 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "path") != 0)
1238 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "<parameter> XML element must contain exactly one attribute, named \"path\"");
1239 context_ptr->error = XML_TRUE;
1240 return;
1243 context_ptr->path = strdup(attr[1]);
1244 if (context_ptr->path == NULL)
1246 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed");
1247 context_ptr->error = XML_TRUE;
1248 return;
1251 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PARAMETER;
1252 context_ptr->data_used = 0;
1253 return;
1256 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown element \"%s\"", el);
1257 context_ptr->error = XML_TRUE;
1260 static void callback_elend(void * data, const char * el)
1262 char * src;
1263 char * dst;
1264 char * address;
1265 struct jack_parameter_variant parameter;
1266 bool is_set;
1268 if (context_ptr->error)
1270 return;
1273 //lash_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
1275 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER &&
1276 context_ptr->depth == 3 &&
1277 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
1278 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
1279 context_ptr->element[2] == PARSE_CONTEXT_CONF)
1281 context_ptr->data[context_ptr->data_used] = 0;
1283 //lash_info("'%s' with value '%s'", context_ptr->path, context_ptr->data);
1285 /* TODO: unescape */
1286 dst = address = strdup(context_ptr->path);
1287 src = context_ptr->path + 1;
1288 while (*src != 0)
1290 if (*src == '/')
1292 *dst = 0;
1294 else
1296 *dst = *src;
1299 src++;
1300 dst++;
1302 dst[0] = 0;
1303 dst[1] = 0; /* ASCIZZ */
1305 if (!jack_proxy_get_parameter_value(address, &is_set, &parameter))
1307 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_proxy_get_parameter_value() failed");
1308 goto fail_free_address;
1311 if (parameter.type == jack_string)
1313 free(parameter.value.string);
1316 switch (parameter.type)
1318 case jack_boolean:
1319 lash_info("%s value is %s (boolean)", context_ptr->path, context_ptr->data);
1320 if (strcmp(context_ptr->data, "true") == 0)
1322 parameter.value.boolean = true;
1324 else if (strcmp(context_ptr->data, "false") == 0)
1326 parameter.value.boolean = false;
1328 else
1330 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for a bool jack param");
1331 goto fail_free_address;
1333 break;
1334 case jack_string:
1335 lash_info("%s value is %s (string)", context_ptr->path, context_ptr->data);
1336 parameter.value.string = context_ptr->data;
1337 break;
1338 case jack_byte:
1339 lash_debug("%s value is %u/%c (byte/char)", context_ptr->path, *context_ptr->data, *context_ptr->data);
1340 if (context_ptr->data[0] == 0 ||
1341 context_ptr->data[1] != 0)
1343 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for a char jack param");
1344 goto fail_free_address;
1346 parameter.value.byte = context_ptr->data[0];
1347 break;
1348 case jack_uint32:
1349 lash_info("%s value is %s (uint32)", context_ptr->path, context_ptr->data);
1350 if (sscanf(context_ptr->data, "%" PRIu32, &parameter.value.uint32) != 1)
1352 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for an uint32 jack param");
1353 goto fail_free_address;
1355 break;
1356 case jack_int32:
1357 lash_info("%s value is %s (int32)", context_ptr->path, context_ptr->data);
1358 if (sscanf(context_ptr->data, "%" PRIi32, &parameter.value.int32) != 1)
1360 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for an int32 jack param");
1361 goto fail_free_address;
1363 break;
1364 default:
1365 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown jack parameter type %d of %s", (int)parameter.type, context_ptr->path);
1366 goto fail_free_address;
1369 if (!jack_proxy_set_parameter_value(address, &parameter))
1371 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_proxy_set_parameter_value() failed");
1372 goto fail_free_address;
1375 free(address);
1378 context_ptr->depth--;
1380 if (context_ptr->path != NULL)
1382 free(context_ptr->path);
1383 context_ptr->path = NULL;
1386 return;
1388 fail_free_address:
1389 free(address);
1390 context_ptr->error = XML_TRUE;
1391 return;
1394 #undef context_ptr
1396 bool studio_delete(void * call_ptr, const char * studio_name)
1398 char * filename;
1399 char * bak_filename;
1400 struct stat st;
1401 bool ret;
1403 ret = false;
1405 if (!compose_filename(studio_name, &filename, &bak_filename))
1407 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename");
1408 goto exit;
1411 lash_info("Loading studio ('%s')", filename);
1413 if (unlink(filename) != 0)
1415 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unlink(%s) failed: %d (%s)", filename, errno, strerror(errno));
1416 goto free;
1419 /* try to delete the backup file */
1420 if (stat(bak_filename, &st) == 0)
1422 if (unlink(bak_filename) != 0)
1424 /* failing to delete backup file will not case delete command failure */
1425 lash_error("unlink(%s) failed: %d (%s)", bak_filename, errno, strerror(errno));
1429 ret = true;
1431 free:
1432 free(filename);
1433 free(bak_filename);
1434 exit:
1435 return ret;
1438 bool studio_load(void * call_ptr, const char * studio_name)
1440 char * path;
1441 struct stat st;
1442 XML_Parser parser;
1443 int bytes_read;
1444 void * buffer;
1445 int fd;
1446 enum XML_Status xmls;
1447 struct parse_context context;
1449 /* TODO: unescape */
1450 path = catdup3(g_studios_dir, studio_name, ".xml");
1451 if (path == NULL)
1453 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup3() failed to compose path of studio \%s\" file", studio_name);
1454 return false;
1457 lash_info("Loading studio... ('%s')", path);
1459 if (stat(path, &st) != 0)
1461 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
1462 free(path);
1463 return false;
1466 studio_clear();
1468 g_studio.name = strdup(studio_name);
1469 if (g_studio.name == NULL)
1471 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup(\"%s\") failed", studio_name);
1472 free(path);
1473 return false;
1476 g_studio.filename = path;
1478 if (!jack_reset_all_params())
1480 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_reset_all_params() failed");
1481 return false;
1484 fd = open(path, O_RDONLY);
1485 if (fd == -1)
1487 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to open '%s': %d (%s)", path, errno, strerror(errno));
1488 return false;
1491 parser = XML_ParserCreate(NULL);
1492 if (parser == NULL)
1494 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_ParserCreate() failed to create parser object.");
1495 close(fd);
1496 return false;
1499 //lash_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
1501 /* we are expecting that conf file has small enough size to fit in memory */
1503 buffer = XML_GetBuffer(parser, st.st_size);
1504 if (buffer == NULL)
1506 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_GetBuffer() failed.");
1507 XML_ParserFree(parser);
1508 close(fd);
1509 return false;
1512 bytes_read = read(fd, buffer, st.st_size);
1513 if (bytes_read != st.st_size)
1515 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "read() returned unexpected result.");
1516 XML_ParserFree(parser);
1517 close(fd);
1518 return false;
1521 context.error = XML_FALSE;
1522 context.depth = -1;
1523 context.path = NULL;
1524 context.call_ptr = call_ptr;
1526 XML_SetElementHandler(parser, callback_elstart, callback_elend);
1527 XML_SetCharacterDataHandler(parser, callback_chrdata);
1528 XML_SetUserData(parser, &context);
1530 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
1531 if (xmls == XML_STATUS_ERROR)
1533 if (!context.error) /* if we have initiated the fail, dbus error is already set to better message */
1535 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_ParseBuffer() failed.");
1537 XML_ParserFree(parser);
1538 close(fd);
1539 return false;
1542 XML_ParserFree(parser);
1543 close(fd);
1545 g_studio.persisted = true;
1546 lash_info("Studio loaded. ('%s')", path);
1548 if (!studio_activate())
1550 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "studio_activate() failed.");
1551 studio_clear();
1552 return false;
1555 lash_info("Starting JACK server.");
1556 if (!jack_proxy_start_server())
1558 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Failed to start JACK server() failed.");
1559 studio_clear();
1560 return false;
1563 return true;
1566 void emit_studio_renamed()
1568 signal_new_valist(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioRenamed", DBUS_TYPE_STRING, &g_studio.name, DBUS_TYPE_INVALID);
1571 static void ladish_get_studio_name(method_call_t * call_ptr)
1573 method_return_new_single(call_ptr, DBUS_TYPE_STRING, &g_studio.name);
1576 static void ladish_rename_studio(method_call_t * call_ptr)
1578 const char * new_name;
1579 char * new_name_dup;
1581 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &new_name, DBUS_TYPE_INVALID))
1583 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
1584 dbus_error_free(&g_dbus_error);
1585 return;
1588 new_name_dup = strdup(new_name);
1589 if (new_name_dup == NULL)
1591 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed to allocate new name.");
1592 return;
1595 free(g_studio.name);
1596 g_studio.name = new_name_dup;
1598 method_return_new_void(call_ptr);
1599 emit_studio_renamed();
1602 static void ladish_save_studio(method_call_t * call_ptr)
1604 if (studio_save(call_ptr))
1606 method_return_new_void(call_ptr);
1610 METHOD_ARGS_BEGIN(GetName, "Get studio name")
1611 METHOD_ARG_DESCRIBE_OUT("studio_name", "s", "Name of studio")
1612 METHOD_ARGS_END
1614 METHOD_ARGS_BEGIN(Rename, "Rename studio")
1615 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1616 METHOD_ARGS_END
1618 METHOD_ARGS_BEGIN(Save, "Save studio")
1619 METHOD_ARGS_END
1621 METHODS_BEGIN
1622 METHOD_DESCRIBE(GetName, ladish_get_studio_name)
1623 METHOD_DESCRIBE(Rename, ladish_rename_studio)
1624 METHOD_DESCRIBE(Save, ladish_save_studio)
1625 METHODS_END
1627 SIGNAL_ARGS_BEGIN(StudioRenamed, "Studio name changed")
1628 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1629 SIGNAL_ARGS_END
1631 SIGNAL_ARGS_BEGIN(RoomAppeared, "Room D-Bus object appeared")
1632 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1633 SIGNAL_ARGS_END
1635 SIGNAL_ARGS_BEGIN(RoomDisappeared, "Room D-Bus object disappeared")
1636 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1637 SIGNAL_ARGS_END
1639 SIGNALS_BEGIN
1640 SIGNAL_DESCRIBE(StudioRenamed)
1641 SIGNAL_DESCRIBE(RoomAppeared)
1642 SIGNAL_DESCRIBE(RoomDisappeared)
1643 SIGNALS_END
1645 INTERFACE_BEGIN(g_interface_studio, IFACE_STUDIO)
1646 INTERFACE_DEFAULT_HANDLER
1647 INTERFACE_EXPOSE_METHODS
1648 INTERFACE_EXPOSE_SIGNALS
1649 INTERFACE_END