Restore JACK parameters during studio load. Closes #2
[ladish.git] / daemon / studio.c
blobad5337d2a7f40b2ade71453ee764281c064a5f00
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 while (!list_empty(&g_studio.jack_conf))
516 node_ptr = g_studio.jack_conf.next;
517 list_del(node_ptr);
518 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
521 g_studio.jack_conf_valid = false;
523 if (g_studio.jack_running)
525 lash_info("Stopping JACK server...");
527 if (jack_proxy_stop_server())
529 g_studio.jack_running = false;
531 else
533 lash_error("Stopping JACK server failed.");
537 if (g_studio.dbus_object != NULL)
539 object_path_destroy(g_dbus_connection, g_studio.dbus_object);
540 g_studio.dbus_object = NULL;
541 emit_studio_disappeared();
544 if (g_studio.name != NULL)
546 free(g_studio.name);
547 g_studio.name = NULL;
550 if (g_studio.filename != NULL)
552 free(g_studio.filename);
553 g_studio.filename = NULL;
557 void
558 studio_clear_if_not_persisted(void)
560 if (!g_studio.persisted)
562 studio_clear();
563 return;
567 void on_event_jack_started(void)
569 if (g_studio.dbus_object == NULL)
571 assert(g_studio.name == NULL);
572 if (!studio_name_generate(&g_studio.name))
574 lash_error("studio_name_generate() failed.");
575 return;
578 studio_activate();
581 if (!studio_fetch_jack_settings(g_studio))
583 lash_error("studio_fetch_jack_settings() failed.");
585 studio_clear_if_not_persisted();
586 return;
589 lash_info("jack conf successfully retrieved");
590 g_studio.jack_conf_valid = true;
591 g_studio.jack_running = true;
594 void on_event_jack_stopped(void)
596 studio_clear_if_not_persisted();
598 g_studio.jack_running = false;
600 /* TODO: if user wants, restart jack server and reconnect all jack apps to it */
603 void studio_run(void)
605 struct event * event_ptr;
607 while (!list_empty(&g_studio.event_queue))
609 event_ptr = list_entry(g_studio.event_queue.next, struct event, siblings);
610 list_del(g_studio.event_queue.next);
612 switch (event_ptr->type)
614 case EVENT_JACK_START:
615 on_event_jack_started();
616 break;
617 case EVENT_JACK_STOP:
618 on_event_jack_stopped();
619 break;
622 free(event_ptr);
626 static void on_jack_server_started(void)
628 struct event * event_ptr;
630 lash_info("JACK server start detected.");
632 event_ptr = malloc(sizeof(struct event));
633 if (event_ptr == NULL)
635 lash_error("malloc() failed to allocate struct event. Ignoring JACK start.");
636 return;
639 event_ptr->type = EVENT_JACK_START;
640 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
643 static void on_jack_server_stopped(void)
645 struct event * event_ptr;
647 lash_info("JACK server stop detected.");
649 event_ptr = malloc(sizeof(struct event));
650 if (event_ptr == NULL)
652 lash_error("malloc() failed to allocate struct event. Ignoring JACK stop.");
653 return;
656 event_ptr->type = EVENT_JACK_STOP;
657 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
660 static void on_jack_server_appeared(void)
662 lash_info("JACK controller appeared.");
665 static void on_jack_server_disappeared(void)
667 lash_info("JACK controller disappeared.");
670 #define studio_ptr ((struct studio *)this)
672 uint64_t
673 studio_get_graph_version(
674 void * this)
676 //lash_info("studio_get_graph_version() called");
677 return 1;
680 #undef studio_ptr
682 bool studio_init(void)
684 lash_info("studio object construct");
686 g_studios_dir = catdup(g_base_dir, STUDIOS_DIR);
687 if (g_studios_dir == NULL)
689 lash_error("catdup failed for '%s' and '%s'", g_base_dir, STUDIOS_DIR);
690 return false;
693 if (!ensure_dir_exist(g_studios_dir, 0700))
695 free(g_studios_dir);
696 return false;
699 g_studio.patchbay_impl.this = &g_studio;
700 g_studio.patchbay_impl.get_graph_version = studio_get_graph_version;
702 INIT_LIST_HEAD(&g_studio.all_connections);
703 INIT_LIST_HEAD(&g_studio.all_ports);
704 INIT_LIST_HEAD(&g_studio.all_clients);
705 INIT_LIST_HEAD(&g_studio.jack_connections);
706 INIT_LIST_HEAD(&g_studio.jack_ports);
707 INIT_LIST_HEAD(&g_studio.jack_clients);
708 INIT_LIST_HEAD(&g_studio.rooms);
709 INIT_LIST_HEAD(&g_studio.clients);
710 INIT_LIST_HEAD(&g_studio.ports);
712 INIT_LIST_HEAD(&g_studio.jack_conf);
713 INIT_LIST_HEAD(&g_studio.jack_params);
715 INIT_LIST_HEAD(&g_studio.event_queue);
717 g_studio.dbus_object = NULL;
718 g_studio.name = NULL;
719 g_studio.filename = NULL;
720 g_studio.jack_running = false;
721 studio_clear();
723 if (!jack_proxy_init(
724 on_jack_server_started,
725 on_jack_server_stopped,
726 on_jack_server_appeared,
727 on_jack_server_disappeared))
729 return false;
732 return true;
735 void studio_uninit(void)
737 jack_proxy_uninit();
739 studio_clear();
741 lash_info("studio object destroy");
744 bool studio_is_loaded(void)
746 return g_studio.dbus_object != NULL;
749 void escape(const char ** src_ptr, char ** dst_ptr)
751 const char * src;
752 char * dst;
753 static char hex_digits[] = "0123456789ABCDEF";
755 src = *src_ptr;
756 dst = *dst_ptr;
758 while (*src != 0)
760 switch (*src)
762 case '/': /* used as separator for address components */
763 case '<': /* invalid attribute value char (XML spec) */
764 case '&': /* invalid attribute value char (XML spec) */
765 case '"': /* we store attribute values in double quotes - invalid attribute value char (XML spec) */
766 case '%':
767 dst[0] = '%';
768 dst[1] = hex_digits[*src >> 4];
769 dst[2] = hex_digits[*src & 0x0F];
770 dst += 3;
771 src++;
772 break;
773 default:
774 *dst++ = *src++;
778 *src_ptr = src;
779 *dst_ptr = dst;
782 bool maybe_compose_filename(void)
784 size_t len_dir;
785 char * p;
786 const char * src;
788 if (g_studio.filename != NULL)
790 return true;
793 len_dir = strlen(g_studios_dir);
795 g_studio.filename = malloc(len_dir + 1 + strlen(g_studio.name) * 3 + 4);
796 if (g_studio.filename == NULL)
798 lash_error("malloc failed to allocate memory for studio file path");
799 return false;
802 p = g_studio.filename;
803 memcpy(p, g_studios_dir, len_dir);
804 p += len_dir;
806 *p++ = '/';
808 src = g_studio.name;
809 escape(&src, &p);
810 strcpy(p, ".xml");
812 return true;
815 bool
816 write_string(int fd, const char * string, void * call_ptr)
818 size_t len;
820 len = strlen(string);
822 if (write(fd, string, len) != len)
824 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "write() failed to write config file.");
825 return false;
828 return true;
831 bool
832 write_jack_parameter(
833 int fd,
834 const char * indent,
835 struct jack_conf_parameter * parameter_ptr,
836 void * call_ptr)
838 const char * src;
839 char * dst;
840 char path[JACK_CONF_MAX_ADDRESS_SIZE * 3]; /* encode each char in three bytes (percent encoding) */
841 const char * content;
842 char valbuf[100];
844 /* compose the parameter path, percent-encode "bad" chars */
845 src = parameter_ptr->address;
846 dst = path;
849 *dst++ = '/';
850 escape(&src, &dst);
851 src++;
853 while (*src != 0);
854 *dst = 0;
856 if (!write_string(fd, indent, call_ptr))
858 return false;
861 if (!write_string(fd, "<parameter path=\"", call_ptr))
863 return false;
866 if (!write_string(fd, path, call_ptr))
868 return false;
871 if (!write_string(fd, "\">", call_ptr))
873 return false;
876 switch (parameter_ptr->parameter.type)
878 case jack_boolean:
879 content = parameter_ptr->parameter.value.boolean ? "true" : "false";
880 lash_debug("%s value is %s (boolean)", path, content);
881 break;
882 case jack_string:
883 content = parameter_ptr->parameter.value.string;
884 lash_debug("%s value is %s (string)", path, content);
885 break;
886 case jack_byte:
887 valbuf[0] = (char)parameter_ptr->parameter.value.byte;
888 valbuf[1] = 0;
889 content = valbuf;
890 lash_debug("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
891 break;
892 case jack_uint32:
893 snprintf(valbuf, sizeof(valbuf), "%" PRIu32, parameter_ptr->parameter.value.uint32);
894 content = valbuf;
895 lash_debug("%s value is %s (uint32)", path, content);
896 break;
897 case jack_int32:
898 snprintf(valbuf, sizeof(valbuf), "%" PRIi32, parameter_ptr->parameter.value.int32);
899 content = valbuf;
900 lash_debug("%s value is %s (int32)", path, content);
901 break;
902 default:
903 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
904 return false;
907 if (!write_string(fd, content, call_ptr))
909 return false;
912 if (!write_string(fd, "</parameter>\n", call_ptr))
914 return false;
917 return true;
920 bool studio_save(void * call_ptr)
922 struct list_head * node_ptr;
923 struct jack_conf_parameter * parameter_ptr;
924 int fd;
925 time_t timestamp;
926 char timestamp_str[26];
927 bool ret;
929 time(&timestamp);
930 ctime_r(&timestamp, timestamp_str);
931 timestamp_str[24] = 0;
933 ret = false;
935 if (!maybe_compose_filename())
937 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename");
938 goto exit;
941 lash_info("saving studio... (%s)", g_studio.filename);
943 fd = open(g_studio.filename, O_WRONLY | O_TRUNC | O_CREAT, 0700);
944 if (fd == -1)
946 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "open(\"%s\") failed: %d (%s)", g_studio.filename, errno, strerror(errno));
947 goto exit;
950 if (!write_string(fd, "<?xml version=\"1.0\"?>\n", call_ptr))
952 goto close;
955 if (!write_string(fd, "<!--\n", call_ptr))
957 goto close;
960 if (!write_string(fd, STUDIO_HEADER_TEXT, call_ptr))
962 goto close;
965 if (!write_string(fd, "-->\n", call_ptr))
967 goto close;
970 if (!write_string(fd, "<!-- ", call_ptr))
972 goto close;
975 if (!write_string(fd, timestamp_str, call_ptr))
977 goto close;
980 if (!write_string(fd, " -->\n", call_ptr))
982 goto close;
985 if (!write_string(fd, "<studio>\n", call_ptr))
987 goto close;
990 if (!write_string(fd, " <jack>\n", call_ptr))
992 goto close;
995 if (!write_string(fd, " <conf>\n", call_ptr))
997 goto close;
1000 list_for_each(node_ptr, &g_studio.jack_params)
1002 parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves);
1004 if (!write_jack_parameter(fd, " ", parameter_ptr, call_ptr))
1006 goto close;
1010 if (!write_string(fd, " </conf>\n", call_ptr))
1012 goto close;
1015 if (!write_string(fd, " </jack>\n", call_ptr))
1017 goto close;
1020 if (!write_string(fd, "</studio>\n", call_ptr))
1022 goto close;
1025 lash_info("studio saved. (%s)", g_studio.filename);
1026 ret = true;
1028 close:
1029 close(fd);
1031 exit:
1032 return ret;
1035 bool studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime))
1037 DIR * dir;
1038 struct dirent * dentry;
1039 size_t len;
1040 struct stat st;
1041 char * path;
1043 dir = opendir(g_studios_dir);
1044 if (dir == NULL)
1046 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Cannot open directory '%s': %d (%s)", g_studios_dir, errno, strerror(errno));
1047 return false;
1050 while ((dentry = readdir(dir)) != NULL)
1052 if (dentry->d_type != DT_REG)
1053 continue;
1055 len = strlen(dentry->d_name);
1056 if (len < 4 || strcmp(dentry->d_name + (len - 4), ".xml"))
1057 continue;
1059 path = catdup(g_studios_dir, dentry->d_name);
1060 if (path == NULL)
1062 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup() failed");
1063 return false;
1066 /* TODO: unescape */
1067 dentry->d_name[len - 4] = 0;
1069 if (stat(path, &st) != 0)
1071 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
1072 free(path);
1073 return false;
1076 free(path);
1078 if (!callback(call_ptr, context, dentry->d_name, st.st_mtime))
1080 closedir(dir);
1081 return false;
1085 closedir(dir);
1086 return true;
1089 #define context_ptr ((struct parse_context *)data)
1091 static void callback_chrdata(void * data, const XML_Char * s, int len)
1093 if (context_ptr->error)
1095 return;
1098 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER)
1100 if (context_ptr->data_used + len >= sizeof(context_ptr->data))
1102 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "xml parse max char data length reached");
1103 context_ptr->error = XML_TRUE;
1104 return;
1107 memcpy(context_ptr->data + context_ptr->data_used, s, len);
1108 context_ptr->data_used += len;
1112 static void callback_elstart(void * data, const char * el, const char ** attr)
1114 if (context_ptr->error)
1116 return;
1119 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
1121 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "xml parse max stack depth reached");
1122 context_ptr->error = XML_TRUE;
1123 return;
1126 if (strcmp(el, "studio") == 0)
1128 //lash_info("<studio>");
1129 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_STUDIO;
1130 return;
1133 if (strcmp(el, "jack") == 0)
1135 //lash_info("<jack>");
1136 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
1137 return;
1140 if (strcmp(el, "conf") == 0)
1142 //lash_info("<conf>");
1143 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONF;
1144 return;
1147 if (strcmp(el, "parameter") == 0)
1149 //lash_info("<parameter>");
1150 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "path") != 0)
1152 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "<parameter> XML element must contain exactly one attribute, named \"path\"");
1153 context_ptr->error = XML_TRUE;
1154 return;
1157 context_ptr->path = strdup(attr[1]);
1158 if (context_ptr->path == NULL)
1160 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed");
1161 context_ptr->error = XML_TRUE;
1162 return;
1165 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PARAMETER;
1166 context_ptr->data_used = 0;
1167 return;
1170 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown element \"%s\"", el);
1171 context_ptr->error = XML_TRUE;
1174 static void callback_elend(void * data, const char * el)
1176 char * src;
1177 char * dst;
1178 char * address;
1179 struct jack_parameter_variant parameter;
1180 bool is_set;
1182 if (context_ptr->error)
1184 return;
1187 //lash_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
1189 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER &&
1190 context_ptr->depth == 3 &&
1191 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
1192 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
1193 context_ptr->element[2] == PARSE_CONTEXT_CONF)
1195 context_ptr->data[context_ptr->data_used] = 0;
1197 //lash_info("'%s' with value '%s'", context_ptr->path, context_ptr->data);
1199 /* TODO: unescape */
1200 dst = address = strdup(context_ptr->path);
1201 src = context_ptr->path + 1;
1202 while (*src != 0)
1204 if (*src == '/')
1206 *dst = 0;
1208 else
1210 *dst = *src;
1213 src++;
1214 dst++;
1216 dst[0] = 0;
1217 dst[1] = 0; /* ASCIZZ */
1219 if (!jack_proxy_get_parameter_value(address, &is_set, &parameter))
1221 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_proxy_get_parameter_value() failed");
1222 goto fail_free_address;
1225 switch (parameter.type)
1227 case jack_boolean:
1228 lash_info("%s value is %s (boolean)", context_ptr->path, context_ptr->data);
1229 if (strcmp(context_ptr->data, "true") == 0)
1231 parameter.value.boolean = true;
1233 else if (strcmp(context_ptr->data, "false") == 0)
1235 parameter.value.boolean = false;
1237 else
1239 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for a bool jack param");
1240 goto fail_free_address;
1242 break;
1243 case jack_string:
1244 lash_info("%s value is %s (string)", context_ptr->path, context_ptr->data);
1245 parameter.value.string = context_ptr->data;
1246 break;
1247 case jack_byte:
1248 lash_debug("%s value is %u/%c (byte/char)", context_ptr->path, *context_ptr->data, *context_ptr->data);
1249 if (context_ptr->data[0] == 0 ||
1250 context_ptr->data[1] != 0)
1252 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for a char jack param");
1253 goto fail_free_address;
1255 parameter.value.byte = context_ptr->data[0];
1256 break;
1257 case jack_uint32:
1258 lash_info("%s value is %s (uint32)", context_ptr->path, context_ptr->data);
1259 if (sscanf(context_ptr->data, "%" PRIu32, &parameter.value.uint32) != 1)
1261 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for an uint32 jack param");
1262 goto fail_free_address;
1264 break;
1265 case jack_int32:
1266 lash_info("%s value is %s (int32)", context_ptr->path, context_ptr->data);
1267 if (sscanf(context_ptr->data, "%" PRIi32, &parameter.value.int32) != 1)
1269 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for an int32 jack param");
1270 goto fail_free_address;
1272 break;
1273 default:
1274 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown jack parameter type %d of %s", (int)parameter.type, context_ptr->path);
1275 goto fail_free_address;
1278 if (!jack_proxy_set_parameter_value(address, &parameter))
1280 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_proxy_set_parameter_value() failed");
1281 goto fail_free_address;
1284 free(address);
1287 context_ptr->depth--;
1289 if (context_ptr->path != NULL)
1291 free(context_ptr->path);
1292 context_ptr->path = NULL;
1295 return;
1297 fail_free_address:
1298 free(address);
1299 context_ptr->error = XML_TRUE;
1300 return;
1303 #undef context_ptr
1305 bool studio_load(void * call_ptr, const char * studio_name)
1307 char * path;
1308 struct stat st;
1309 XML_Parser parser;
1310 int bytes_read;
1311 void * buffer;
1312 int fd;
1313 enum XML_Status xmls;
1314 struct parse_context context;
1316 /* TODO: unescape */
1317 path = catdup3(g_studios_dir, studio_name, ".xml");
1318 if (path == NULL)
1320 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup3() failed to compose path of studio \%s\" file", studio_name);
1321 return false;
1324 lash_info("Loading studio... ('%s')", path);
1326 if (stat(path, &st) != 0)
1328 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
1329 free(path);
1330 return false;
1333 studio_clear();
1335 g_studio.name = strdup(studio_name);
1336 if (g_studio.name == NULL)
1338 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup(\"%s\") failed", studio_name);
1339 free(path);
1340 return false;
1343 g_studio.filename = path;
1345 if (!jack_reset_all_params())
1347 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_reset_all_params() failed");
1348 return false;
1351 fd = open(path, O_RDONLY);
1352 if (fd == -1)
1354 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to open '%s': %d (%s)", path, errno, strerror(errno));
1355 return false;
1358 parser = XML_ParserCreate(NULL);
1359 if (parser == NULL)
1361 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_ParserCreate() failed to create parser object.");
1362 close(fd);
1363 return false;
1366 //lash_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
1368 /* we are expecting that conf file has small enough size to fit in memory */
1370 buffer = XML_GetBuffer(parser, st.st_size);
1371 if (buffer == NULL)
1373 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_GetBuffer() failed.");
1374 XML_ParserFree(parser);
1375 close(fd);
1376 return false;
1379 bytes_read = read(fd, buffer, st.st_size);
1380 if (bytes_read != st.st_size)
1382 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "read() returned unexpected result.");
1383 XML_ParserFree(parser);
1384 close(fd);
1385 return false;
1388 context.error = XML_FALSE;
1389 context.depth = -1;
1390 context.path = NULL;
1391 context.call_ptr = call_ptr;
1393 XML_SetElementHandler(parser, callback_elstart, callback_elend);
1394 XML_SetCharacterDataHandler(parser, callback_chrdata);
1395 XML_SetUserData(parser, &context);
1397 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
1398 if (xmls == XML_STATUS_ERROR)
1400 if (!context.error) /* if we have initiated the fail, dbus error is already set to better message */
1402 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_ParseBuffer() failed.");
1404 XML_ParserFree(parser);
1405 close(fd);
1406 return false;
1409 XML_ParserFree(parser);
1410 close(fd);
1412 lash_info("Studio loaded. ('%s')", path);
1414 studio_activate();
1416 lash_info("Starting JACK server.");
1417 if (!jack_proxy_start_server())
1419 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Failed to start JACK server() failed.");
1420 return false;
1423 return true;
1426 void emit_studio_renamed()
1428 signal_new_valist(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioRenamed", DBUS_TYPE_STRING, &g_studio.name, DBUS_TYPE_INVALID);
1431 static void ladish_get_studio_name(method_call_t * call_ptr)
1433 method_return_new_single(call_ptr, DBUS_TYPE_STRING, &g_studio.name);
1436 static void ladish_rename_studio(method_call_t * call_ptr)
1438 const char * new_name;
1439 char * new_name_dup;
1441 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &new_name, DBUS_TYPE_INVALID))
1443 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
1444 dbus_error_free(&g_dbus_error);
1445 return;
1448 new_name_dup = strdup(new_name);
1449 if (new_name_dup == NULL)
1451 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed to allocate new name.");
1452 return;
1455 free(g_studio.name);
1456 g_studio.name = new_name_dup;
1458 method_return_new_void(call_ptr);
1459 emit_studio_renamed();
1462 static void ladish_save_studio(method_call_t * call_ptr)
1464 if (studio_save(call_ptr))
1466 method_return_new_void(call_ptr);
1470 METHOD_ARGS_BEGIN(GetName, "Get studio name")
1471 METHOD_ARG_DESCRIBE_OUT("studio_name", "s", "Name of studio")
1472 METHOD_ARGS_END
1474 METHOD_ARGS_BEGIN(Rename, "Rename studio")
1475 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1476 METHOD_ARGS_END
1478 METHOD_ARGS_BEGIN(Save, "Save studio")
1479 METHOD_ARGS_END
1481 METHODS_BEGIN
1482 METHOD_DESCRIBE(GetName, ladish_get_studio_name)
1483 METHOD_DESCRIBE(Rename, ladish_rename_studio)
1484 METHOD_DESCRIBE(Save, ladish_save_studio)
1485 METHODS_END
1487 SIGNAL_ARGS_BEGIN(StudioRenamed, "Studio name changed")
1488 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1489 SIGNAL_ARGS_END
1491 SIGNAL_ARGS_BEGIN(RoomAppeared, "Room D-Bus object appeared")
1492 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1493 SIGNAL_ARGS_END
1495 SIGNAL_ARGS_BEGIN(RoomDisappeared, "Room D-Bus object disappeared")
1496 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1497 SIGNAL_ARGS_END
1499 SIGNALS_BEGIN
1500 SIGNAL_DESCRIBE(StudioRenamed)
1501 SIGNAL_DESCRIBE(RoomAppeared)
1502 SIGNAL_DESCRIBE(RoomDisappeared)
1503 SIGNALS_END
1505 INTERFACE_BEGIN(g_interface_studio, IFACE_STUDIO)
1506 INTERFACE_DEFAULT_HANDLER
1507 INTERFACE_EXPOSE_METHODS
1508 INTERFACE_EXPOSE_SIGNALS
1509 INTERFACE_END