1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the 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.
29 #include <sys/types.h>
36 #include "../jack_proxy.h"
38 #include "../dbus_constants.h"
40 #include "../catdup.h"
41 #include "../dbus/error.h"
42 #include "dirhelpers.h"
44 #define STUDIOS_DIR "/studios/"
47 #define STUDIO_HEADER_TEXT BASE_NAME " Studio configuration.\n"
49 extern const interface_t g_interface_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
;
82 #define EVENT_JACK_START 0
83 #define EVENT_JACK_STOP 1
87 struct list_head siblings
;
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 */
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
;
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
132 unsigned int element
[MAX_STACK_DEPTH
];
134 char data
[MAX_DATA_SIZE
];
140 jack_conf_container_create(
141 struct jack_conf_container
** container_ptr_ptr
,
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");
153 container_ptr
->name
= strdup(name
);
154 if (container_ptr
->name
== NULL
)
156 lash_error("strdup() failed to duplicate \"%s\"", name
);
160 INIT_LIST_HEAD(&container_ptr
->children
);
161 container_ptr
->children_leafs
= false;
163 *container_ptr_ptr
= container_ptr
;
174 jack_conf_parameter_create(
175 struct jack_conf_parameter
** parameter_ptr_ptr
,
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");
187 parameter_ptr
->name
= strdup(name
);
188 if (parameter_ptr
->name
== NULL
)
190 lash_error("strdup() failed to duplicate \"%s\"", name
);
194 *parameter_ptr_ptr
= parameter_ptr
;
205 jack_conf_parameter_destroy(
206 struct jack_conf_parameter
* parameter_ptr
)
209 lash_info("jack_conf_parameter destroy");
211 switch (parameter_ptr
->parameter
.type
)
214 lash_info("%s value is %s (boolean)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
217 lash_info("%s value is %s (string)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.string
);
220 lash_info("%s value is %u/%c (byte/char)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
223 lash_info("%s value is %u (uint32)", parameter_ptr
->name
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
226 lash_info("%s value is %u (int32)", parameter_ptr
->name
, (signed int)parameter_ptr
->parameter
.value
.int32
);
229 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, parameter_ptr
->name
);
234 if (parameter_ptr
->parameter
.type
== jack_string
)
236 free(parameter_ptr
->parameter
.value
.string
);
239 free(parameter_ptr
->name
);
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
;
257 jack_conf_container_destroy(list_entry(node_ptr
, struct jack_conf_container
, siblings
));
262 while (!list_empty(&container_ptr
->children
))
264 node_ptr
= container_ptr
->children
.next
;
266 jack_conf_parameter_destroy(list_entry(node_ptr
, struct jack_conf_parameter
, siblings
));
270 free(container_ptr
->name
);
274 #define context_ptr ((struct conf_callback_context *)context)
281 const char * address
,
284 char path
[JACK_CONF_MAX_ADDRESS_SIZE
];
285 const char * component
;
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");
303 while (*component
!= 0)
305 len
= strlen(component
);
306 memcpy(dst
, component
, len
);
308 component
+= len
+ 1;
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
);
324 lash_debug("%s (leaf)", path
);
326 if (parent_ptr
== NULL
)
328 lash_error("jack conf parameters can't appear in root container");
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");
340 parent_ptr
->children_leafs
= true;
343 if (!jack_conf_parameter_create(¶meter_ptr
, child
))
345 lash_error("jack_conf_parameter_create() failed");
349 if (!jack_proxy_get_parameter_value(context_ptr
->address
, &is_set
, ¶meter_ptr
->parameter
))
351 lash_error("cannot get value of %s", path
);
358 switch (parameter_ptr
->parameter
.type
)
361 lash_info("%s value is %s (boolean)", path
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
364 lash_info("%s value is %s (string)", path
, parameter_ptr
->parameter
.value
.string
);
367 lash_info("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
370 lash_info("%s value is %u (uint32)", path
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
373 lash_info("%s value is %u (int32)", path
, (signed int)parameter_ptr
->parameter
.value
.int32
);
376 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
377 jack_conf_parameter_destroy(parameter_ptr
);
382 parameter_ptr
->parent_ptr
= parent_ptr
;
383 memcpy(parameter_ptr
->address
, context_ptr
->address
, JACK_CONF_MAX_ADDRESS_SIZE
);
384 list_add_tail(¶meter_ptr
->siblings
, &parent_ptr
->children
);
385 list_add_tail(¶meter_ptr
->leaves
, &g_studio
.jack_params
);
389 jack_conf_parameter_destroy(parameter_ptr
);
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");
402 if (!jack_conf_container_create(&container_ptr
, child
))
404 lash_error("jack_conf_container_create() failed");
408 container_ptr
->parent_ptr
= parent_ptr
;
410 if (parent_ptr
== NULL
)
412 list_add_tail(&container_ptr
->siblings
, &g_studio
.jack_conf
);
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
);
427 context_ptr
->parent_ptr
= parent_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.");
454 bool studio_name_generate(char ** name_ptr
)
457 char timestamp_str
[26];
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
);
468 lash_error("catdup failed to create studio name");
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
);
486 lash_error("object_path_new() failed");
490 if (!object_path_register(g_dbus_connection
, object
))
492 lash_error("object_path_register() failed");
493 object_path_destroy(g_dbus_connection
, object
);
497 lash_info("Studio D-Bus object created. \"%s\"", g_studio
.name
);
499 g_studio
.dbus_object
= object
;
501 emit_studio_appeared();
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
;
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;
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
)
548 g_studio
.name
= NULL
;
551 if (g_studio
.filename
!= NULL
)
553 free(g_studio
.filename
);
554 g_studio
.filename
= NULL
;
559 studio_clear_if_not_persisted(void)
561 if (!g_studio
.persisted
)
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.");
582 if (!studio_fetch_jack_settings(g_studio
))
584 lash_error("studio_fetch_jack_settings() failed.");
586 studio_clear_if_not_persisted();
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();
618 case EVENT_JACK_STOP
:
619 on_event_jack_stopped();
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.");
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.");
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)
674 studio_get_graph_version(
677 //lash_info("studio_get_graph_version() called");
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
);
694 if (!ensure_dir_exist(g_studios_dir
, 0700))
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;
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
))
736 void studio_uninit(void)
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
)
754 static char hex_digits
[] = "0123456789ABCDEF";
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) */
769 dst
[1] = hex_digits
[*src
>> 4];
770 dst
[2] = hex_digits
[*src
& 0x0F];
783 static bool compose_filename(const char * name
, char ** filename_ptr_ptr
, char ** backup_filename_ptr_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");
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");
809 memcpy(p
, g_studios_dir
, len_dir
);
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
;
828 write_string(int fd
, const char * string
, void * call_ptr
)
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.");
844 write_jack_parameter(
847 struct jack_conf_parameter
* parameter_ptr
,
852 char path
[JACK_CONF_MAX_ADDRESS_SIZE
* 3]; /* encode each char in three bytes (percent encoding) */
853 const char * content
;
856 /* compose the parameter path, percent-encode "bad" chars */
857 src
= parameter_ptr
->address
;
868 if (!write_string(fd
, indent
, call_ptr
))
873 if (!write_string(fd
, "<parameter path=\"", call_ptr
))
878 if (!write_string(fd
, path
, call_ptr
))
883 if (!write_string(fd
, "\">", call_ptr
))
888 switch (parameter_ptr
->parameter
.type
)
891 content
= parameter_ptr
->parameter
.value
.boolean
? "true" : "false";
892 lash_debug("%s value is %s (boolean)", path
, content
);
895 content
= parameter_ptr
->parameter
.value
.string
;
896 lash_debug("%s value is %s (string)", path
, content
);
899 valbuf
[0] = (char)parameter_ptr
->parameter
.value
.byte
;
902 lash_debug("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
905 snprintf(valbuf
, sizeof(valbuf
), "%" PRIu32
, parameter_ptr
->parameter
.value
.uint32
);
907 lash_debug("%s value is %s (uint32)", path
, content
);
910 snprintf(valbuf
, sizeof(valbuf
), "%" PRIi32
, parameter_ptr
->parameter
.value
.int32
);
912 lash_debug("%s value is %s (int32)", path
, content
);
915 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
919 if (!write_string(fd
, content
, call_ptr
))
924 if (!write_string(fd
, "</parameter>\n", call_ptr
))
932 bool studio_save(void * call_ptr
)
934 struct list_head
* node_ptr
;
935 struct jack_conf_parameter
* parameter_ptr
;
938 char timestamp_str
[26];
940 char * filename
; /* filename */
941 char * bak_filename
; /* filename of the backup file */
942 char * old_filename
; /* filename where studio was persisted before save */
946 ctime_r(×tamp
, timestamp_str
);
947 timestamp_str
[24] = 0;
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");
957 if (g_studio
.filename
== NULL
)
959 /* saving studio for first time */
960 g_studio
.filename
= filename
;
965 else if (strcmp(g_studio
.filename
, filename
) == 0)
967 /* saving already persisted studio that was not renamed */
968 old_filename
= filename
;
972 /* saving renamed studio */
973 old_filename
= g_studio
.filename
;
974 g_studio
.filename
= filename
;
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
));
996 /* mark that there is no backup file */
1002 lash_info("saving studio... (%s)", g_studio
.filename
);
1004 fd
= open(g_studio
.filename
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0700);
1007 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "open(%s) failed: %d (%s)", g_studio
.filename
, errno
, strerror(errno
));
1011 if (!write_string(fd
, "<?xml version=\"1.0\"?>\n", call_ptr
))
1016 if (!write_string(fd
, "<!--\n", call_ptr
))
1021 if (!write_string(fd
, STUDIO_HEADER_TEXT
, call_ptr
))
1026 if (!write_string(fd
, "-->\n", call_ptr
))
1031 if (!write_string(fd
, "<!-- ", call_ptr
))
1036 if (!write_string(fd
, timestamp_str
, call_ptr
))
1041 if (!write_string(fd
, " -->\n", call_ptr
))
1046 if (!write_string(fd
, "<studio>\n", call_ptr
))
1051 if (!write_string(fd
, " <jack>\n", call_ptr
))
1056 if (!write_string(fd
, " <conf>\n", call_ptr
))
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
))
1071 if (!write_string(fd
, " </conf>\n", call_ptr
))
1076 if (!write_string(fd
, " </jack>\n", call_ptr
))
1081 if (!write_string(fd
, "</studio>\n", call_ptr
))
1086 lash_info("studio saved. (%s)", g_studio
.filename
);
1087 g_studio
.persisted
= true;
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
));
1104 if (bak_filename
!= NULL
)
1109 if (old_filename
!= NULL
)
1114 assert(filename
== NULL
);
1115 assert(g_studio
.filename
!= NULL
);
1121 bool studios_iterate(void * call_ptr
, void * context
, bool (* callback
)(void * call_ptr
, void * context
, const char * studio
, uint32_t modtime
))
1124 struct dirent
* dentry
;
1129 dir
= opendir(g_studios_dir
);
1132 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot open directory '%s': %d (%s)", g_studios_dir
, errno
, strerror(errno
));
1136 while ((dentry
= readdir(dir
)) != NULL
)
1138 if (dentry
->d_type
!= DT_REG
)
1141 len
= strlen(dentry
->d_name
);
1142 if (len
< 4 || strcmp(dentry
->d_name
+ (len
- 4), ".xml"))
1145 path
= catdup(g_studios_dir
, dentry
->d_name
);
1148 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "catdup() failed");
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
));
1164 if (!callback(call_ptr
, context
, dentry
->d_name
, st
.st_mtime
))
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
)
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
;
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
)
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
;
1212 if (strcmp(el
, "studio") == 0)
1214 //lash_info("<studio>");
1215 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_STUDIO
;
1219 if (strcmp(el
, "jack") == 0)
1221 //lash_info("<jack>");
1222 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_JACK
;
1226 if (strcmp(el
, "conf") == 0)
1228 //lash_info("<conf>");
1229 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONF
;
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
;
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
;
1251 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PARAMETER
;
1252 context_ptr
->data_used
= 0;
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
)
1265 struct jack_parameter_variant parameter
;
1268 if (context_ptr
->error
)
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;
1303 dst
[1] = 0; /* ASCIZZ */
1305 if (!jack_proxy_get_parameter_value(address
, &is_set
, ¶meter
))
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
)
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;
1330 lash_dbus_error(context_ptr
->call_ptr
, LASH_DBUS_ERROR_GENERIC
, "bad value for a bool jack param");
1331 goto fail_free_address
;
1335 lash_info("%s value is %s (string)", context_ptr
->path
, context_ptr
->data
);
1336 parameter
.value
.string
= context_ptr
->data
;
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];
1349 lash_info("%s value is %s (uint32)", context_ptr
->path
, context_ptr
->data
);
1350 if (sscanf(context_ptr
->data
, "%" PRIu32
, ¶meter
.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
;
1357 lash_info("%s value is %s (int32)", context_ptr
->path
, context_ptr
->data
);
1358 if (sscanf(context_ptr
->data
, "%" PRIi32
, ¶meter
.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
;
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
, ¶meter
))
1371 lash_dbus_error(context_ptr
->call_ptr
, LASH_DBUS_ERROR_GENERIC
, "jack_proxy_set_parameter_value() failed");
1372 goto fail_free_address
;
1378 context_ptr
->depth
--;
1380 if (context_ptr
->path
!= NULL
)
1382 free(context_ptr
->path
);
1383 context_ptr
->path
= NULL
;
1390 context_ptr
->error
= XML_TRUE
;
1396 bool studio_delete(void * call_ptr
, const char * studio_name
)
1399 char * bak_filename
;
1405 if (!compose_filename(studio_name
, &filename
, &bak_filename
))
1407 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to compose studio filename");
1411 lash_info("Deleting 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
));
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
));
1438 bool studio_load(void * call_ptr
, const char * studio_name
)
1446 enum XML_Status xmls
;
1447 struct parse_context context
;
1449 /* TODO: unescape */
1450 path
= catdup3(g_studios_dir
, studio_name
, ".xml");
1453 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "catdup3() failed to compose path of studio \%s\" file", studio_name
);
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
));
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
);
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");
1484 fd
= open(path
, O_RDONLY
);
1487 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to open '%s': %d (%s)", path
, errno
, strerror(errno
));
1491 parser
= XML_ParserCreate(NULL
);
1494 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "XML_ParserCreate() failed to create parser object.");
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
);
1506 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "XML_GetBuffer() failed.");
1507 XML_ParserFree(parser
);
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
);
1521 context
.error
= XML_FALSE
;
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
);
1542 XML_ParserFree(parser
);
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.");
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.");
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
);
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.");
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 static void ladish_unload_studio(method_call_t
* call_ptr
)
1613 method_return_new_void(call_ptr
);
1616 bool studio_new(void * call_ptr
, const char * studio_name
)
1620 assert(g_studio
.name
== NULL
);
1621 if (*studio_name
!= 0)
1623 g_studio
.name
= strdup(studio_name
);
1624 if (g_studio
.name
== NULL
)
1626 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed to allocate studio name.");
1630 else if (!studio_name_generate(&g_studio
.name
))
1632 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "studio_name_generate() failed.");
1636 if (!studio_activate())
1638 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "studio_activate() failed.");
1643 if (!studio_fetch_jack_settings(g_studio
))
1645 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "studio_fetch_jack_settings() failed.");
1653 METHOD_ARGS_BEGIN(GetName
, "Get studio name")
1654 METHOD_ARG_DESCRIBE_OUT("studio_name", "s", "Name of studio")
1657 METHOD_ARGS_BEGIN(Rename
, "Rename studio")
1658 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1661 METHOD_ARGS_BEGIN(Save
, "Save studio")
1664 METHOD_ARGS_BEGIN(Unload
, "Unload studio")
1668 METHOD_DESCRIBE(GetName
, ladish_get_studio_name
)
1669 METHOD_DESCRIBE(Rename
, ladish_rename_studio
)
1670 METHOD_DESCRIBE(Save
, ladish_save_studio
)
1671 METHOD_DESCRIBE(Unload
, ladish_unload_studio
)
1674 SIGNAL_ARGS_BEGIN(StudioRenamed
, "Studio name changed")
1675 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1678 SIGNAL_ARGS_BEGIN(RoomAppeared
, "Room D-Bus object appeared")
1679 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1682 SIGNAL_ARGS_BEGIN(RoomDisappeared
, "Room D-Bus object disappeared")
1683 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1687 SIGNAL_DESCRIBE(StudioRenamed
)
1688 SIGNAL_DESCRIBE(RoomAppeared
)
1689 SIGNAL_DESCRIBE(RoomDisappeared
)
1692 INTERFACE_BEGIN(g_interface_studio
, IFACE_STUDIO
)
1693 INTERFACE_DEFAULT_HANDLER
1694 INTERFACE_EXPOSE_METHODS
1695 INTERFACE_EXPOSE_SIGNALS