Escaping fixes. Closes #3
[ladish.git] / daemon / studio.c
blob82c8c56827b4b9f9e9d69c6f40e513f441a4038a
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 automatic:1; /* Studio was automatically created because of external JACK start */
67 bool persisted:1; /* Studio has on-disk representation, i.e. can be reloaded from disk */
68 bool modified:1; /* Studio needs saving */
69 bool jack_conf_valid:1; /* JACK server configuration obtained successfully */
70 bool jack_running:1; /* JACK server is running */
72 struct list_head jack_conf; /* root of the conf tree */
73 struct list_head jack_params; /* list of conf tree leaves */
75 object_path_t * dbus_object;
77 struct list_head event_queue;
79 char * name;
80 char * filename;
81 } g_studio;
83 #define EVENT_JACK_START 0
84 #define EVENT_JACK_STOP 1
86 struct event
88 struct list_head siblings;
89 unsigned int type;
92 #define JACK_CONF_MAX_ADDRESS_SIZE 1024
94 struct jack_conf_parameter
96 struct list_head siblings; /* siblings in container children list */
97 struct list_head leaves; /* studio::jack_param siblings */
98 char * name;
99 struct jack_conf_container * parent_ptr;
100 char address[JACK_CONF_MAX_ADDRESS_SIZE];
101 struct jack_parameter_variant parameter;
104 struct jack_conf_container
106 struct list_head siblings;
107 char * name;
108 struct jack_conf_container * parent_ptr;
109 bool children_leafs; /* if true, children are "jack_conf_parameter"s, if false, children are "jack_conf_container"s */
110 struct list_head children;
113 struct conf_callback_context
115 char address[JACK_CONF_MAX_ADDRESS_SIZE];
116 struct list_head * container_ptr;
117 struct jack_conf_container * parent_ptr;
120 #define PARSE_CONTEXT_ROOT 0
121 #define PARSE_CONTEXT_STUDIO 1
122 #define PARSE_CONTEXT_JACK 2
123 #define PARSE_CONTEXT_CONF 3
124 #define PARSE_CONTEXT_PARAMETER 4
126 #define MAX_STACK_DEPTH 10
127 #define MAX_DATA_SIZE 1024
129 struct parse_context
131 void * call_ptr;
132 XML_Bool error;
133 unsigned int element[MAX_STACK_DEPTH];
134 signed int depth;
135 char data[MAX_DATA_SIZE];
136 int data_used;
137 char * path;
140 bool
141 jack_conf_container_create(
142 struct jack_conf_container ** container_ptr_ptr,
143 const char * name)
145 struct jack_conf_container * container_ptr;
147 container_ptr = malloc(sizeof(struct jack_conf_container));
148 if (container_ptr == NULL)
150 lash_error("malloc() failed to allocate struct jack_conf_container");
151 goto fail;
154 container_ptr->name = strdup(name);
155 if (container_ptr->name == NULL)
157 lash_error("strdup() failed to duplicate \"%s\"", name);
158 goto fail_free;
161 INIT_LIST_HEAD(&container_ptr->children);
162 container_ptr->children_leafs = false;
164 *container_ptr_ptr = container_ptr;
165 return true;
167 fail_free:
168 free(container_ptr);
170 fail:
171 return false;
174 bool
175 jack_conf_parameter_create(
176 struct jack_conf_parameter ** parameter_ptr_ptr,
177 const char * name)
179 struct jack_conf_parameter * parameter_ptr;
181 parameter_ptr = malloc(sizeof(struct jack_conf_parameter));
182 if (parameter_ptr == NULL)
184 lash_error("malloc() failed to allocate struct jack_conf_parameter");
185 goto fail;
188 parameter_ptr->name = strdup(name);
189 if (parameter_ptr->name == NULL)
191 lash_error("strdup() failed to duplicate \"%s\"", name);
192 goto fail_free;
195 *parameter_ptr_ptr = parameter_ptr;
196 return true;
198 fail_free:
199 free(parameter_ptr);
201 fail:
202 return false;
205 void
206 jack_conf_parameter_destroy(
207 struct jack_conf_parameter * parameter_ptr)
209 #if 0
210 lash_info("jack_conf_parameter destroy");
212 switch (parameter_ptr->parameter.type)
214 case jack_boolean:
215 lash_info("%s value is %s (boolean)", parameter_ptr->name, parameter_ptr->parameter.value.boolean ? "true" : "false");
216 break;
217 case jack_string:
218 lash_info("%s value is %s (string)", parameter_ptr->name, parameter_ptr->parameter.value.string);
219 break;
220 case jack_byte:
221 lash_info("%s value is %u/%c (byte/char)", parameter_ptr->name, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
222 break;
223 case jack_uint32:
224 lash_info("%s value is %u (uint32)", parameter_ptr->name, (unsigned int)parameter_ptr->parameter.value.uint32);
225 break;
226 case jack_int32:
227 lash_info("%s value is %u (int32)", parameter_ptr->name, (signed int)parameter_ptr->parameter.value.int32);
228 break;
229 default:
230 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, parameter_ptr->name);
231 break;
233 #endif
235 if (parameter_ptr->parameter.type == jack_string)
237 free(parameter_ptr->parameter.value.string);
240 free(parameter_ptr->name);
241 free(parameter_ptr);
244 void
245 jack_conf_container_destroy(
246 struct jack_conf_container * container_ptr)
248 struct list_head * node_ptr;
250 //lash_info("\"%s\" jack_conf_parameter destroy", container_ptr->name);
252 if (!container_ptr->children_leafs)
254 while (!list_empty(&container_ptr->children))
256 node_ptr = container_ptr->children.next;
257 list_del(node_ptr);
258 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
261 else
263 while (!list_empty(&container_ptr->children))
265 node_ptr = container_ptr->children.next;
266 list_del(node_ptr);
267 jack_conf_parameter_destroy(list_entry(node_ptr, struct jack_conf_parameter, siblings));
271 free(container_ptr->name);
272 free(container_ptr);
275 #define context_ptr ((struct conf_callback_context *)context)
277 static
278 bool
279 conf_callback(
280 void * context,
281 bool leaf,
282 const char * address,
283 char * child)
285 char path[JACK_CONF_MAX_ADDRESS_SIZE];
286 const char * component;
287 char * dst;
288 size_t len;
289 bool is_set;
290 struct jack_conf_container * parent_ptr;
291 struct jack_conf_container * container_ptr;
292 struct jack_conf_parameter * parameter_ptr;
294 parent_ptr = context_ptr->parent_ptr;
296 if (parent_ptr == NULL && strcmp(child, "drivers") == 0)
298 lash_debug("ignoring drivers branch");
299 return true;
302 dst = path;
303 component = address;
304 while (*component != 0)
306 len = strlen(component);
307 memcpy(dst, component, len);
308 dst[len] = ':';
309 component += len + 1;
310 dst += len + 1;
313 strcpy(dst, child);
315 /* address always is same buffer as the one supplied through context pointer */
316 assert(context_ptr->address == address);
317 dst = (char *)component;
319 len = strlen(child) + 1;
320 memcpy(dst, child, len);
321 dst[len] = 0;
323 if (leaf)
325 lash_debug("%s (leaf)", path);
327 if (parent_ptr == NULL)
329 lash_error("jack conf parameters can't appear in root container");
330 return false;
333 if (!parent_ptr->children_leafs)
335 if (!list_empty(&parent_ptr->children))
337 lash_error("jack conf parameters cant be mixed with containers at same hierarchy level");
338 return false;
341 parent_ptr->children_leafs = true;
344 if (!jack_conf_parameter_create(&parameter_ptr, child))
346 lash_error("jack_conf_parameter_create() failed");
347 return false;
350 if (!jack_proxy_get_parameter_value(context_ptr->address, &is_set, &parameter_ptr->parameter))
352 lash_error("cannot get value of %s", path);
353 return false;
356 if (is_set)
358 #if 0
359 switch (parameter_ptr->parameter.type)
361 case jack_boolean:
362 lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false");
363 break;
364 case jack_string:
365 lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string);
366 break;
367 case jack_byte:
368 lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
369 break;
370 case jack_uint32:
371 lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32);
372 break;
373 case jack_int32:
374 lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32);
375 break;
376 default:
377 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
378 jack_conf_parameter_destroy(parameter_ptr);
379 return false;
381 #endif
383 parameter_ptr->parent_ptr = parent_ptr;
384 memcpy(parameter_ptr->address, context_ptr->address, JACK_CONF_MAX_ADDRESS_SIZE);
385 list_add_tail(&parameter_ptr->siblings, &parent_ptr->children);
386 list_add_tail(&parameter_ptr->leaves, &g_studio.jack_params);
388 else
390 jack_conf_parameter_destroy(parameter_ptr);
393 else
395 lash_debug("%s (container)", path);
397 if (parent_ptr != NULL && parent_ptr->children_leafs)
399 lash_error("jack conf containers cant be mixed with parameters at same hierarchy level");
400 return false;
403 if (!jack_conf_container_create(&container_ptr, child))
405 lash_error("jack_conf_container_create() failed");
406 return false;
409 container_ptr->parent_ptr = parent_ptr;
411 if (parent_ptr == NULL)
413 list_add_tail(&container_ptr->siblings, &g_studio.jack_conf);
415 else
417 list_add_tail(&container_ptr->siblings, &parent_ptr->children);
420 context_ptr->parent_ptr = container_ptr;
422 if (!jack_proxy_read_conf_container(context_ptr->address, context, conf_callback))
424 lash_error("cannot read container %s", path);
425 return false;
428 context_ptr->parent_ptr = parent_ptr;
431 *dst = 0;
433 return true;
436 #undef context_ptr
438 static void jack_conf_clear(void)
440 struct list_head * node_ptr;
442 INIT_LIST_HEAD(&g_studio.jack_params); /* we will destroy the leaves as part of tree destroy traversal */
443 while (!list_empty(&g_studio.jack_conf))
445 node_ptr = g_studio.jack_conf.next;
446 list_del(node_ptr);
447 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
450 g_studio.jack_conf_valid = false;
453 bool studio_fetch_jack_settings()
455 struct conf_callback_context context;
457 jack_conf_clear();
459 context.address[0] = 0;
460 context.container_ptr = &g_studio.jack_conf;
461 context.parent_ptr = NULL;
463 if (!jack_proxy_read_conf_container(context.address, &context, conf_callback))
465 lash_error("jack_proxy_read_conf_container() failed.");
466 return false;
469 return true;
472 bool studio_name_generate(char ** name_ptr)
474 time_t now;
475 char timestamp_str[26];
476 char * name;
478 time(&now);
479 //ctime_r(&now, timestamp_str);
480 //timestamp_str[24] = 0;
481 snprintf(timestamp_str, sizeof(timestamp_str), "%llu", (unsigned long long)now);
483 name = catdup("Studio ", timestamp_str);
484 if (name == NULL)
486 lash_error("catdup failed to create studio name");
487 return false;
490 *name_ptr = name;
491 return true;
494 bool
495 studio_publish(void)
497 object_path_t * object;
499 assert(g_studio.name != NULL);
501 object = object_path_new(STUDIO_OBJECT_PATH, &g_studio, 2, &g_interface_studio, &g_interface_patchbay);
502 if (object == NULL)
504 lash_error("object_path_new() failed");
505 return false;
508 if (!object_path_register(g_dbus_connection, object))
510 lash_error("object_path_register() failed");
511 object_path_destroy(g_dbus_connection, object);
512 return false;
515 lash_info("Studio D-Bus object created. \"%s\"", g_studio.name);
517 g_studio.dbus_object = object;
519 emit_studio_appeared();
521 return true;
524 static void emit_studio_started()
526 signal_new_valist(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioStarted", DBUS_TYPE_INVALID);
529 static void emit_studio_stopped()
531 signal_new_valist(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioStopped", DBUS_TYPE_INVALID);
534 static bool studio_start(void)
536 if (!g_studio.jack_running)
538 lash_info("Starting JACK server.");
540 if (!jack_proxy_start_server())
542 lash_error("jack_proxy_start_server() failed.");
543 return false;
547 emit_studio_started();
549 return true;
552 static bool studio_stop(void)
554 if (g_studio.jack_running)
556 lash_info("Stopping JACK server...");
558 g_studio.automatic = false; /* even if it was automatic, it is not anymore because user knows about it */
560 if (jack_proxy_stop_server())
562 g_studio.jack_running = false;
563 emit_studio_stopped();
565 else
567 lash_error("Stopping JACK server failed.");
568 return false;
572 return true;
575 void
576 studio_clear(void)
578 g_studio.modified = false;
579 g_studio.persisted = false;
580 g_studio.automatic = false;
582 jack_conf_clear();
584 studio_stop();
586 if (g_studio.dbus_object != NULL)
588 object_path_destroy(g_dbus_connection, g_studio.dbus_object);
589 g_studio.dbus_object = NULL;
590 emit_studio_disappeared();
593 if (g_studio.name != NULL)
595 free(g_studio.name);
596 g_studio.name = NULL;
599 if (g_studio.filename != NULL)
601 free(g_studio.filename);
602 g_studio.filename = NULL;
606 void
607 studio_clear_if_automatic(void)
609 if (g_studio.automatic)
611 lash_info("Unloading automatic studio.");
612 studio_clear();
613 return;
617 void on_event_jack_started(void)
619 if (g_studio.dbus_object == NULL)
621 assert(g_studio.name == NULL);
622 if (!studio_name_generate(&g_studio.name))
624 lash_error("studio_name_generate() failed.");
625 return;
628 g_studio.automatic = true;
630 studio_publish();
633 if (!studio_fetch_jack_settings(g_studio))
635 lash_error("studio_fetch_jack_settings() failed.");
637 studio_clear_if_automatic();
638 return;
641 lash_info("jack conf successfully retrieved");
642 g_studio.jack_conf_valid = true;
643 g_studio.jack_running = true;
646 void on_event_jack_stopped(void)
648 studio_clear_if_automatic();
650 g_studio.jack_running = false;
652 /* TODO: if user wants, restart jack server and reconnect all jack apps to it */
655 void studio_run(void)
657 struct event * event_ptr;
659 while (!list_empty(&g_studio.event_queue))
661 event_ptr = list_entry(g_studio.event_queue.next, struct event, siblings);
662 list_del(g_studio.event_queue.next);
664 switch (event_ptr->type)
666 case EVENT_JACK_START:
667 on_event_jack_started();
668 break;
669 case EVENT_JACK_STOP:
670 on_event_jack_stopped();
671 break;
674 free(event_ptr);
678 static void on_jack_server_started(void)
680 struct event * event_ptr;
682 lash_info("JACK server start detected.");
684 event_ptr = malloc(sizeof(struct event));
685 if (event_ptr == NULL)
687 lash_error("malloc() failed to allocate struct event. Ignoring JACK start.");
688 return;
691 event_ptr->type = EVENT_JACK_START;
692 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
695 static void on_jack_server_stopped(void)
697 struct event * event_ptr;
699 lash_info("JACK server stop detected.");
701 event_ptr = malloc(sizeof(struct event));
702 if (event_ptr == NULL)
704 lash_error("malloc() failed to allocate struct event. Ignoring JACK stop.");
705 return;
708 event_ptr->type = EVENT_JACK_STOP;
709 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
712 static void on_jack_server_appeared(void)
714 lash_info("JACK controller appeared.");
717 static void on_jack_server_disappeared(void)
719 lash_info("JACK controller disappeared.");
722 #define studio_ptr ((struct studio *)this)
724 uint64_t
725 studio_get_graph_version(
726 void * this)
728 //lash_info("studio_get_graph_version() called");
729 return 1;
732 #undef studio_ptr
734 bool studio_init(void)
736 lash_info("studio object construct");
738 g_studios_dir = catdup(g_base_dir, STUDIOS_DIR);
739 if (g_studios_dir == NULL)
741 lash_error("catdup failed for '%s' and '%s'", g_base_dir, STUDIOS_DIR);
742 return false;
745 if (!ensure_dir_exist(g_studios_dir, 0700))
747 free(g_studios_dir);
748 return false;
751 g_studio.patchbay_impl.this = &g_studio;
752 g_studio.patchbay_impl.get_graph_version = studio_get_graph_version;
754 INIT_LIST_HEAD(&g_studio.all_connections);
755 INIT_LIST_HEAD(&g_studio.all_ports);
756 INIT_LIST_HEAD(&g_studio.all_clients);
757 INIT_LIST_HEAD(&g_studio.jack_connections);
758 INIT_LIST_HEAD(&g_studio.jack_ports);
759 INIT_LIST_HEAD(&g_studio.jack_clients);
760 INIT_LIST_HEAD(&g_studio.rooms);
761 INIT_LIST_HEAD(&g_studio.clients);
762 INIT_LIST_HEAD(&g_studio.ports);
764 INIT_LIST_HEAD(&g_studio.jack_conf);
765 INIT_LIST_HEAD(&g_studio.jack_params);
767 INIT_LIST_HEAD(&g_studio.event_queue);
769 g_studio.dbus_object = NULL;
770 g_studio.name = NULL;
771 g_studio.filename = NULL;
772 g_studio.jack_running = false;
773 studio_clear();
775 if (!jack_proxy_init(
776 on_jack_server_started,
777 on_jack_server_stopped,
778 on_jack_server_appeared,
779 on_jack_server_disappeared))
781 return false;
784 return true;
787 void studio_uninit(void)
789 jack_proxy_uninit();
791 studio_clear();
793 lash_info("studio object destroy");
796 bool studio_is_loaded(void)
798 return g_studio.dbus_object != NULL;
801 void escape(const char ** src_ptr, char ** dst_ptr)
803 const char * src;
804 char * dst;
805 static char hex_digits[] = "0123456789ABCDEF";
807 src = *src_ptr;
808 dst = *dst_ptr;
810 while (*src != 0)
812 switch (*src)
814 case '/': /* used as separator for address components */
815 case '<': /* invalid attribute value char (XML spec) */
816 case '&': /* invalid attribute value char (XML spec) */
817 case '"': /* we store attribute values in double quotes - invalid attribute value char (XML spec) */
818 case '%':
819 dst[0] = '%';
820 dst[1] = hex_digits[*src >> 4];
821 dst[2] = hex_digits[*src & 0x0F];
822 dst += 3;
823 src++;
824 break;
825 default:
826 *dst++ = *src++;
830 *src_ptr = src;
831 *dst_ptr = dst;
834 #define HEX_TO_INT(hexchar) ((hexchar) <= '9' ? hexchar - '0' : 10 + (hexchar - 'A'))
836 static size_t unescape(const char * src, size_t src_len, char * dst)
838 size_t dst_len;
840 dst_len = 0;
842 while (src_len)
844 if (src_len >= 3 &&
845 src[0] == '%' &&
846 ((src[1] >= '0' && src[1] <= '9') ||
847 (src[1] >= 'A' && src[1] <= 'F')) &&
848 ((src[2] >= '0' && src[2] <= '9') ||
849 (src[2] >= 'A' && src[2] <= 'F')))
851 *dst = (HEX_TO_INT(src[1]) << 4) | HEX_TO_INT(src[2]);
852 //lash_info("unescaping %c%c%c to '%c'", src[0], src[1], src[2], *dst);
853 src_len -= 3;
854 src += 3;
856 else
858 *dst = *src;
859 src_len--;
860 src++;
862 dst++;
863 dst_len++;
866 return dst_len;
869 static bool compose_filename(const char * name, char ** filename_ptr_ptr, char ** backup_filename_ptr_ptr)
871 size_t len_dir;
872 char * p;
873 const char * src;
874 char * filename_ptr;
875 char * backup_filename_ptr;
877 len_dir = strlen(g_studios_dir);
879 filename_ptr = malloc(len_dir + 1 + strlen(name) * 3 + 4 + 1);
880 if (filename_ptr == NULL)
882 lash_error("malloc failed to allocate memory for studio file path");
883 return false;
886 if (backup_filename_ptr_ptr != NULL)
888 backup_filename_ptr = malloc(len_dir + 1 + strlen(name) * 3 + 4 + 4 + 1);
889 if (backup_filename_ptr == NULL)
891 lash_error("malloc failed to allocate memory for studio backup file path");
892 free(filename_ptr);
893 return false;
897 p = filename_ptr;
898 memcpy(p, g_studios_dir, len_dir);
899 p += len_dir;
901 *p++ = '/';
903 src = name;
904 escape(&src, &p);
905 strcpy(p, ".xml");
907 *filename_ptr_ptr = filename_ptr;
909 if (backup_filename_ptr_ptr != NULL)
911 strcpy(backup_filename_ptr, filename_ptr);
912 strcat(backup_filename_ptr, ".bak");
913 *backup_filename_ptr_ptr = backup_filename_ptr;
916 return true;
919 bool
920 write_string(int fd, const char * string, void * call_ptr)
922 size_t len;
924 len = strlen(string);
926 if (write(fd, string, len) != len)
928 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "write() failed to write config file.");
929 return false;
932 return true;
935 bool
936 write_jack_parameter(
937 int fd,
938 const char * indent,
939 struct jack_conf_parameter * parameter_ptr,
940 void * call_ptr)
942 const char * src;
943 char * dst;
944 char path[JACK_CONF_MAX_ADDRESS_SIZE * 3]; /* encode each char in three bytes (percent encoding) */
945 const char * content;
946 char valbuf[100];
948 /* compose the parameter path, percent-encode "bad" chars */
949 src = parameter_ptr->address;
950 dst = path;
953 *dst++ = '/';
954 escape(&src, &dst);
955 src++;
957 while (*src != 0);
958 *dst = 0;
960 if (!write_string(fd, indent, call_ptr))
962 return false;
965 if (!write_string(fd, "<parameter path=\"", call_ptr))
967 return false;
970 if (!write_string(fd, path, call_ptr))
972 return false;
975 if (!write_string(fd, "\">", call_ptr))
977 return false;
980 switch (parameter_ptr->parameter.type)
982 case jack_boolean:
983 content = parameter_ptr->parameter.value.boolean ? "true" : "false";
984 lash_debug("%s value is %s (boolean)", path, content);
985 break;
986 case jack_string:
987 content = parameter_ptr->parameter.value.string;
988 lash_debug("%s value is %s (string)", path, content);
989 break;
990 case jack_byte:
991 valbuf[0] = (char)parameter_ptr->parameter.value.byte;
992 valbuf[1] = 0;
993 content = valbuf;
994 lash_debug("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
995 break;
996 case jack_uint32:
997 snprintf(valbuf, sizeof(valbuf), "%" PRIu32, parameter_ptr->parameter.value.uint32);
998 content = valbuf;
999 lash_debug("%s value is %s (uint32)", path, content);
1000 break;
1001 case jack_int32:
1002 snprintf(valbuf, sizeof(valbuf), "%" PRIi32, parameter_ptr->parameter.value.int32);
1003 content = valbuf;
1004 lash_debug("%s value is %s (int32)", path, content);
1005 break;
1006 default:
1007 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
1008 return false;
1011 if (!write_string(fd, content, call_ptr))
1013 return false;
1016 if (!write_string(fd, "</parameter>\n", call_ptr))
1018 return false;
1021 return true;
1024 bool studio_save(void * call_ptr)
1026 struct list_head * node_ptr;
1027 struct jack_conf_parameter * parameter_ptr;
1028 int fd;
1029 time_t timestamp;
1030 char timestamp_str[26];
1031 bool ret;
1032 char * filename; /* filename */
1033 char * bak_filename; /* filename of the backup file */
1034 char * old_filename; /* filename where studio was persisted before save */
1035 struct stat st;
1037 time(&timestamp);
1038 ctime_r(&timestamp, timestamp_str);
1039 timestamp_str[24] = 0;
1041 ret = false;
1043 if (!compose_filename(g_studio.name, &filename, &bak_filename))
1045 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename");
1046 goto exit;
1049 if (g_studio.filename == NULL)
1051 /* saving studio for first time */
1052 g_studio.filename = filename;
1053 free(bak_filename);
1054 bak_filename = NULL;
1055 old_filename = NULL;
1057 else if (strcmp(g_studio.filename, filename) == 0)
1059 /* saving already persisted studio that was not renamed */
1060 old_filename = filename;
1062 else
1064 /* saving renamed studio */
1065 old_filename = g_studio.filename;
1066 g_studio.filename = filename;
1069 filename = NULL;
1070 assert(g_studio.filename != NULL);
1071 assert(g_studio.filename != old_filename);
1072 assert(g_studio.filename != bak_filename);
1074 if (bak_filename != NULL)
1076 assert(old_filename != NULL);
1078 if (stat(old_filename, &st) == 0) /* if old filename does not exist, rename with fail */
1080 if (rename(old_filename, bak_filename) != 0)
1082 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "rename(%s, %s) failed: %d (%s)", old_filename, bak_filename, errno, strerror(errno));
1083 goto free_filenames;
1086 else
1088 /* mark that there is no backup file */
1089 free(bak_filename);
1090 bak_filename = NULL;
1094 lash_info("saving studio... (%s)", g_studio.filename);
1096 fd = open(g_studio.filename, O_WRONLY | O_TRUNC | O_CREAT, 0700);
1097 if (fd == -1)
1099 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "open(%s) failed: %d (%s)", g_studio.filename, errno, strerror(errno));
1100 goto rename_back;
1103 if (!write_string(fd, "<?xml version=\"1.0\"?>\n", call_ptr))
1105 goto close;
1108 if (!write_string(fd, "<!--\n", call_ptr))
1110 goto close;
1113 if (!write_string(fd, STUDIO_HEADER_TEXT, call_ptr))
1115 goto close;
1118 if (!write_string(fd, "-->\n", call_ptr))
1120 goto close;
1123 if (!write_string(fd, "<!-- ", call_ptr))
1125 goto close;
1128 if (!write_string(fd, timestamp_str, call_ptr))
1130 goto close;
1133 if (!write_string(fd, " -->\n", call_ptr))
1135 goto close;
1138 if (!write_string(fd, "<studio>\n", call_ptr))
1140 goto close;
1143 if (!write_string(fd, " <jack>\n", call_ptr))
1145 goto close;
1148 if (!write_string(fd, " <conf>\n", call_ptr))
1150 goto close;
1153 list_for_each(node_ptr, &g_studio.jack_params)
1155 parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves);
1157 if (!write_jack_parameter(fd, " ", parameter_ptr, call_ptr))
1159 goto close;
1163 if (!write_string(fd, " </conf>\n", call_ptr))
1165 goto close;
1168 if (!write_string(fd, " </jack>\n", call_ptr))
1170 goto close;
1173 if (!write_string(fd, "</studio>\n", call_ptr))
1175 goto close;
1178 lash_info("studio saved. (%s)", g_studio.filename);
1179 g_studio.persisted = true;
1180 g_studio.automatic = false; /* even if it was automatic, it is not anymore because it is saved */
1181 ret = true;
1183 close:
1184 close(fd);
1186 rename_back:
1187 if (!ret && bak_filename != NULL)
1189 /* save failed - try to rename the backup file back */
1190 if (rename(bak_filename, g_studio.filename) != 0)
1192 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "rename(%s, %s) failed: %d (%s)", bak_filename, g_studio.filename, errno, strerror(errno));
1196 free_filenames:
1197 if (bak_filename != NULL)
1199 free(bak_filename);
1202 if (old_filename != NULL)
1204 free(old_filename);
1207 assert(filename == NULL);
1208 assert(g_studio.filename != NULL);
1210 exit:
1211 return ret;
1214 bool studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime))
1216 DIR * dir;
1217 struct dirent * dentry;
1218 size_t len;
1219 struct stat st;
1220 char * path;
1221 char * name;
1223 dir = opendir(g_studios_dir);
1224 if (dir == NULL)
1226 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Cannot open directory '%s': %d (%s)", g_studios_dir, errno, strerror(errno));
1227 return false;
1230 while ((dentry = readdir(dir)) != NULL)
1232 if (dentry->d_type != DT_REG)
1233 continue;
1235 len = strlen(dentry->d_name);
1236 if (len <= 4 || strcmp(dentry->d_name + (len - 4), ".xml") != 0)
1237 continue;
1239 path = catdup(g_studios_dir, dentry->d_name);
1240 if (path == NULL)
1242 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup() failed");
1243 return false;
1246 if (stat(path, &st) != 0)
1248 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
1249 free(path);
1250 return false;
1253 free(path);
1255 name = malloc(len - 4 + 1);
1256 name[unescape(dentry->d_name, len - 4, name)] = 0;
1257 //lash_info("name = '%s'", name);
1259 if (!callback(call_ptr, context, name, st.st_mtime))
1261 free(name);
1262 closedir(dir);
1263 return false;
1266 free(name);
1269 closedir(dir);
1270 return true;
1273 #define context_ptr ((struct parse_context *)data)
1275 static void callback_chrdata(void * data, const XML_Char * s, int len)
1277 if (context_ptr->error)
1279 return;
1282 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER)
1284 if (context_ptr->data_used + len >= sizeof(context_ptr->data))
1286 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "xml parse max char data length reached");
1287 context_ptr->error = XML_TRUE;
1288 return;
1291 memcpy(context_ptr->data + context_ptr->data_used, s, len);
1292 context_ptr->data_used += len;
1296 static void callback_elstart(void * data, const char * el, const char ** attr)
1298 if (context_ptr->error)
1300 return;
1303 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
1305 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "xml parse max stack depth reached");
1306 context_ptr->error = XML_TRUE;
1307 return;
1310 if (strcmp(el, "studio") == 0)
1312 //lash_info("<studio>");
1313 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_STUDIO;
1314 return;
1317 if (strcmp(el, "jack") == 0)
1319 //lash_info("<jack>");
1320 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
1321 return;
1324 if (strcmp(el, "conf") == 0)
1326 //lash_info("<conf>");
1327 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONF;
1328 return;
1331 if (strcmp(el, "parameter") == 0)
1333 //lash_info("<parameter>");
1334 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "path") != 0)
1336 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "<parameter> XML element must contain exactly one attribute, named \"path\"");
1337 context_ptr->error = XML_TRUE;
1338 return;
1341 context_ptr->path = strdup(attr[1]);
1342 if (context_ptr->path == NULL)
1344 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed");
1345 context_ptr->error = XML_TRUE;
1346 return;
1349 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PARAMETER;
1350 context_ptr->data_used = 0;
1351 return;
1354 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown element \"%s\"", el);
1355 context_ptr->error = XML_TRUE;
1358 static void callback_elend(void * data, const char * el)
1360 char * src;
1361 char * dst;
1362 char * sep;
1363 size_t src_len;
1364 size_t dst_len;
1365 char * address;
1366 struct jack_parameter_variant parameter;
1367 bool is_set;
1369 if (context_ptr->error)
1371 return;
1374 //lash_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
1376 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER &&
1377 context_ptr->depth == 3 &&
1378 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
1379 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
1380 context_ptr->element[2] == PARSE_CONTEXT_CONF)
1382 context_ptr->data[context_ptr->data_used] = 0;
1384 //lash_info("'%s' with value '%s'", context_ptr->path, context_ptr->data);
1386 dst = address = strdup(context_ptr->path);
1387 src = context_ptr->path + 1;
1388 while (*src != 0)
1390 sep = strchr(src, '/');
1391 if (sep == NULL)
1393 src_len = strlen(src);
1395 else
1397 src_len = sep - src;
1400 dst_len = unescape(src, src_len, dst);
1401 dst[dst_len] = 0;
1402 dst += dst_len + 1;
1404 src += src_len;
1405 assert(*src == '/' || *src == 0);
1406 if (sep != NULL)
1408 assert(*src == '/');
1409 src++; /* skip separator */
1411 else
1413 assert(*src == 0);
1416 *dst = 0; /* ASCIZZ */
1418 if (!jack_proxy_get_parameter_value(address, &is_set, &parameter))
1420 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_proxy_get_parameter_value() failed");
1421 goto fail_free_address;
1424 if (parameter.type == jack_string)
1426 free(parameter.value.string);
1429 switch (parameter.type)
1431 case jack_boolean:
1432 lash_info("%s value is %s (boolean)", context_ptr->path, context_ptr->data);
1433 if (strcmp(context_ptr->data, "true") == 0)
1435 parameter.value.boolean = true;
1437 else if (strcmp(context_ptr->data, "false") == 0)
1439 parameter.value.boolean = false;
1441 else
1443 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for a bool jack param");
1444 goto fail_free_address;
1446 break;
1447 case jack_string:
1448 lash_info("%s value is %s (string)", context_ptr->path, context_ptr->data);
1449 parameter.value.string = context_ptr->data;
1450 break;
1451 case jack_byte:
1452 lash_debug("%s value is %u/%c (byte/char)", context_ptr->path, *context_ptr->data, *context_ptr->data);
1453 if (context_ptr->data[0] == 0 ||
1454 context_ptr->data[1] != 0)
1456 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for a char jack param");
1457 goto fail_free_address;
1459 parameter.value.byte = context_ptr->data[0];
1460 break;
1461 case jack_uint32:
1462 lash_info("%s value is %s (uint32)", context_ptr->path, context_ptr->data);
1463 if (sscanf(context_ptr->data, "%" PRIu32, &parameter.value.uint32) != 1)
1465 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for an uint32 jack param");
1466 goto fail_free_address;
1468 break;
1469 case jack_int32:
1470 lash_info("%s value is %s (int32)", context_ptr->path, context_ptr->data);
1471 if (sscanf(context_ptr->data, "%" PRIi32, &parameter.value.int32) != 1)
1473 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "bad value for an int32 jack param");
1474 goto fail_free_address;
1476 break;
1477 default:
1478 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown jack parameter type %d of %s", (int)parameter.type, context_ptr->path);
1479 goto fail_free_address;
1482 if (!jack_proxy_set_parameter_value(address, &parameter))
1484 lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_proxy_set_parameter_value() failed");
1485 goto fail_free_address;
1488 free(address);
1491 context_ptr->depth--;
1493 if (context_ptr->path != NULL)
1495 free(context_ptr->path);
1496 context_ptr->path = NULL;
1499 return;
1501 fail_free_address:
1502 free(address);
1503 context_ptr->error = XML_TRUE;
1504 return;
1507 #undef context_ptr
1509 bool studio_delete(void * call_ptr, const char * studio_name)
1511 char * filename;
1512 char * bak_filename;
1513 struct stat st;
1514 bool ret;
1516 ret = false;
1518 if (!compose_filename(studio_name, &filename, &bak_filename))
1520 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename");
1521 goto exit;
1524 lash_info("Deleting studio ('%s')", filename);
1526 if (unlink(filename) != 0)
1528 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unlink(%s) failed: %d (%s)", filename, errno, strerror(errno));
1529 goto free;
1532 /* try to delete the backup file */
1533 if (stat(bak_filename, &st) == 0)
1535 if (unlink(bak_filename) != 0)
1537 /* failing to delete backup file will not case delete command failure */
1538 lash_error("unlink(%s) failed: %d (%s)", bak_filename, errno, strerror(errno));
1542 ret = true;
1544 free:
1545 free(filename);
1546 free(bak_filename);
1547 exit:
1548 return ret;
1551 bool studio_load(void * call_ptr, const char * studio_name)
1553 char * path;
1554 struct stat st;
1555 XML_Parser parser;
1556 int bytes_read;
1557 void * buffer;
1558 int fd;
1559 enum XML_Status xmls;
1560 struct parse_context context;
1562 if (!compose_filename(studio_name, &path, NULL))
1564 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup3() failed to compose path of studio \%s\" file", studio_name);
1565 return false;
1568 lash_info("Loading studio... ('%s')", path);
1570 if (stat(path, &st) != 0)
1572 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
1573 free(path);
1574 return false;
1577 studio_clear();
1579 g_studio.name = strdup(studio_name);
1580 if (g_studio.name == NULL)
1582 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup(\"%s\") failed", studio_name);
1583 free(path);
1584 return false;
1587 g_studio.filename = path;
1589 if (!jack_reset_all_params())
1591 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "jack_reset_all_params() failed");
1592 return false;
1595 fd = open(path, O_RDONLY);
1596 if (fd == -1)
1598 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to open '%s': %d (%s)", path, errno, strerror(errno));
1599 return false;
1602 parser = XML_ParserCreate(NULL);
1603 if (parser == NULL)
1605 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_ParserCreate() failed to create parser object.");
1606 close(fd);
1607 return false;
1610 //lash_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
1612 /* we are expecting that conf file has small enough size to fit in memory */
1614 buffer = XML_GetBuffer(parser, st.st_size);
1615 if (buffer == NULL)
1617 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_GetBuffer() failed.");
1618 XML_ParserFree(parser);
1619 close(fd);
1620 return false;
1623 bytes_read = read(fd, buffer, st.st_size);
1624 if (bytes_read != st.st_size)
1626 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "read() returned unexpected result.");
1627 XML_ParserFree(parser);
1628 close(fd);
1629 return false;
1632 context.error = XML_FALSE;
1633 context.depth = -1;
1634 context.path = NULL;
1635 context.call_ptr = call_ptr;
1637 XML_SetElementHandler(parser, callback_elstart, callback_elend);
1638 XML_SetCharacterDataHandler(parser, callback_chrdata);
1639 XML_SetUserData(parser, &context);
1641 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
1642 if (xmls == XML_STATUS_ERROR)
1644 if (!context.error) /* if we have initiated the fail, dbus error is already set to better message */
1646 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "XML_ParseBuffer() failed.");
1648 XML_ParserFree(parser);
1649 close(fd);
1650 return false;
1653 XML_ParserFree(parser);
1654 close(fd);
1656 g_studio.persisted = true;
1657 lash_info("Studio loaded. ('%s')", path);
1659 if (!studio_publish())
1661 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "studio_publish() failed.");
1662 studio_clear();
1663 return false;
1666 if (!studio_start())
1668 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Failed to start JACK server.");
1669 studio_clear();
1670 return false;
1673 return true;
1676 void emit_studio_renamed()
1678 signal_new_valist(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioRenamed", DBUS_TYPE_STRING, &g_studio.name, DBUS_TYPE_INVALID);
1681 static void ladish_get_studio_name(method_call_t * call_ptr)
1683 method_return_new_single(call_ptr, DBUS_TYPE_STRING, &g_studio.name);
1686 static void ladish_rename_studio(method_call_t * call_ptr)
1688 const char * new_name;
1689 char * new_name_dup;
1691 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &new_name, DBUS_TYPE_INVALID))
1693 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
1694 dbus_error_free(&g_dbus_error);
1695 return;
1698 lash_info("Rename studio request (%s)", new_name);
1700 new_name_dup = strdup(new_name);
1701 if (new_name_dup == NULL)
1703 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed to allocate new name.");
1704 return;
1707 free(g_studio.name);
1708 g_studio.name = new_name_dup;
1710 method_return_new_void(call_ptr);
1711 emit_studio_renamed();
1714 static void ladish_save_studio(method_call_t * call_ptr)
1716 if (studio_save(call_ptr))
1718 method_return_new_void(call_ptr);
1722 static void ladish_unload_studio(method_call_t * call_ptr)
1724 lash_info("Unload studio request");
1725 studio_clear();
1726 method_return_new_void(call_ptr);
1729 bool studio_new(void * call_ptr, const char * studio_name)
1731 lash_info("New studio request (%s)", studio_name);
1732 studio_clear();
1734 assert(g_studio.name == NULL);
1735 if (*studio_name != 0)
1737 g_studio.name = strdup(studio_name);
1738 if (g_studio.name == NULL)
1740 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed to allocate studio name.");
1741 return false;
1744 else if (!studio_name_generate(&g_studio.name))
1746 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "studio_name_generate() failed.");
1747 return false;
1750 if (!studio_publish())
1752 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "studio_publish() failed.");
1753 studio_clear();
1754 return false;
1757 return true;
1760 static void ladish_stop_studio(method_call_t * call_ptr)
1762 lash_info("Studio stop requested");
1764 if (!studio_stop())
1766 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Failed to stop studio.");
1768 else
1770 method_return_new_void(call_ptr);
1774 static void ladish_start_studio(method_call_t * call_ptr)
1776 lash_info("Studio start requested");
1778 if (!studio_start())
1780 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Failed to start studio.");
1782 else
1784 method_return_new_void(call_ptr);
1788 METHOD_ARGS_BEGIN(GetName, "Get studio name")
1789 METHOD_ARG_DESCRIBE_OUT("studio_name", "s", "Name of studio")
1790 METHOD_ARGS_END
1792 METHOD_ARGS_BEGIN(Rename, "Rename studio")
1793 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1794 METHOD_ARGS_END
1796 METHOD_ARGS_BEGIN(Save, "Save studio")
1797 METHOD_ARGS_END
1799 METHOD_ARGS_BEGIN(Unload, "Unload studio")
1800 METHOD_ARGS_END
1802 METHOD_ARGS_BEGIN(Start, "Start studio")
1803 METHOD_ARGS_END
1805 METHOD_ARGS_BEGIN(Stop, "Stop studio")
1806 METHOD_ARGS_END
1808 METHODS_BEGIN
1809 METHOD_DESCRIBE(GetName, ladish_get_studio_name)
1810 METHOD_DESCRIBE(Rename, ladish_rename_studio)
1811 METHOD_DESCRIBE(Save, ladish_save_studio)
1812 METHOD_DESCRIBE(Unload, ladish_unload_studio)
1813 METHOD_DESCRIBE(Start, ladish_start_studio)
1814 METHOD_DESCRIBE(Stop, ladish_stop_studio)
1815 METHODS_END
1817 SIGNAL_ARGS_BEGIN(StudioRenamed, "Studio name changed")
1818 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1819 SIGNAL_ARGS_END
1821 SIGNAL_ARGS_BEGIN(StudioStarted, "Studio started")
1822 SIGNAL_ARGS_END
1824 SIGNAL_ARGS_BEGIN(StudioStopped, "Studio stopped")
1825 SIGNAL_ARGS_END
1827 SIGNAL_ARGS_BEGIN(RoomAppeared, "Room D-Bus object appeared")
1828 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1829 SIGNAL_ARGS_END
1831 SIGNAL_ARGS_BEGIN(RoomDisappeared, "Room D-Bus object disappeared")
1832 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1833 SIGNAL_ARGS_END
1835 SIGNALS_BEGIN
1836 SIGNAL_DESCRIBE(StudioRenamed)
1837 SIGNAL_DESCRIBE(StudioStarted)
1838 SIGNAL_DESCRIBE(StudioStopped)
1839 SIGNAL_DESCRIBE(RoomAppeared)
1840 SIGNAL_DESCRIBE(RoomDisappeared)
1841 SIGNALS_END
1843 INTERFACE_BEGIN(g_interface_studio, IFACE_STUDIO)
1844 INTERFACE_DEFAULT_HANDLER
1845 INTERFACE_EXPOSE_METHODS
1846 INTERFACE_EXPOSE_SIGNALS
1847 INTERFACE_END