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 while (!list_empty(&g_studio
.jack_conf
))
516 node_ptr
= g_studio
.jack_conf
.next
;
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;
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
)
547 g_studio
.name
= NULL
;
550 if (g_studio
.filename
!= NULL
)
552 free(g_studio
.filename
);
553 g_studio
.filename
= NULL
;
558 studio_clear_if_not_persisted(void)
560 if (!g_studio
.persisted
)
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.");
581 if (!studio_fetch_jack_settings(g_studio
))
583 lash_error("studio_fetch_jack_settings() failed.");
585 studio_clear_if_not_persisted();
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();
617 case EVENT_JACK_STOP
:
618 on_event_jack_stopped();
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.");
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.");
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)
673 studio_get_graph_version(
676 //lash_info("studio_get_graph_version() called");
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
);
693 if (!ensure_dir_exist(g_studios_dir
, 0700))
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;
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
))
735 void studio_uninit(void)
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
)
753 static char hex_digits
[] = "0123456789ABCDEF";
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) */
768 dst
[1] = hex_digits
[*src
>> 4];
769 dst
[2] = hex_digits
[*src
& 0x0F];
782 bool maybe_compose_filename(void)
788 if (g_studio
.filename
!= NULL
)
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");
802 p
= g_studio
.filename
;
803 memcpy(p
, g_studios_dir
, len_dir
);
816 write_string(int fd
, const char * string
, void * call_ptr
)
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.");
832 write_jack_parameter(
835 struct jack_conf_parameter
* parameter_ptr
,
840 char path
[JACK_CONF_MAX_ADDRESS_SIZE
* 3]; /* encode each char in three bytes (percent encoding) */
841 const char * content
;
844 /* compose the parameter path, percent-encode "bad" chars */
845 src
= parameter_ptr
->address
;
856 if (!write_string(fd
, indent
, call_ptr
))
861 if (!write_string(fd
, "<parameter path=\"", call_ptr
))
866 if (!write_string(fd
, path
, call_ptr
))
871 if (!write_string(fd
, "\">", call_ptr
))
876 switch (parameter_ptr
->parameter
.type
)
879 content
= parameter_ptr
->parameter
.value
.boolean
? "true" : "false";
880 lash_debug("%s value is %s (boolean)", path
, content
);
883 content
= parameter_ptr
->parameter
.value
.string
;
884 lash_debug("%s value is %s (string)", path
, content
);
887 valbuf
[0] = (char)parameter_ptr
->parameter
.value
.byte
;
890 lash_debug("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
893 snprintf(valbuf
, sizeof(valbuf
), "%" PRIu32
, parameter_ptr
->parameter
.value
.uint32
);
895 lash_debug("%s value is %s (uint32)", path
, content
);
898 snprintf(valbuf
, sizeof(valbuf
), "%" PRIi32
, parameter_ptr
->parameter
.value
.int32
);
900 lash_debug("%s value is %s (int32)", path
, content
);
903 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
907 if (!write_string(fd
, content
, call_ptr
))
912 if (!write_string(fd
, "</parameter>\n", call_ptr
))
920 bool studio_save(void * call_ptr
)
922 struct list_head
* node_ptr
;
923 struct jack_conf_parameter
* parameter_ptr
;
926 char timestamp_str
[26];
930 ctime_r(×tamp
, timestamp_str
);
931 timestamp_str
[24] = 0;
935 if (!maybe_compose_filename())
937 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to compose studio filename");
941 lash_info("saving studio... (%s)", g_studio
.filename
);
943 fd
= open(g_studio
.filename
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0700);
946 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "open(\"%s\") failed: %d (%s)", g_studio
.filename
, errno
, strerror(errno
));
950 if (!write_string(fd
, "<?xml version=\"1.0\"?>\n", call_ptr
))
955 if (!write_string(fd
, "<!--\n", call_ptr
))
960 if (!write_string(fd
, STUDIO_HEADER_TEXT
, call_ptr
))
965 if (!write_string(fd
, "-->\n", call_ptr
))
970 if (!write_string(fd
, "<!-- ", call_ptr
))
975 if (!write_string(fd
, timestamp_str
, call_ptr
))
980 if (!write_string(fd
, " -->\n", call_ptr
))
985 if (!write_string(fd
, "<studio>\n", call_ptr
))
990 if (!write_string(fd
, " <jack>\n", call_ptr
))
995 if (!write_string(fd
, " <conf>\n", call_ptr
))
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
))
1010 if (!write_string(fd
, " </conf>\n", call_ptr
))
1015 if (!write_string(fd
, " </jack>\n", call_ptr
))
1020 if (!write_string(fd
, "</studio>\n", call_ptr
))
1025 lash_info("studio saved. (%s)", g_studio
.filename
);
1035 bool studios_iterate(void * call_ptr
, void * context
, bool (* callback
)(void * call_ptr
, void * context
, const char * studio
, uint32_t modtime
))
1038 struct dirent
* dentry
;
1043 dir
= opendir(g_studios_dir
);
1046 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot open directory '%s': %d (%s)", g_studios_dir
, errno
, strerror(errno
));
1050 while ((dentry
= readdir(dir
)) != NULL
)
1052 if (dentry
->d_type
!= DT_REG
)
1055 len
= strlen(dentry
->d_name
);
1056 if (len
< 4 || strcmp(dentry
->d_name
+ (len
- 4), ".xml"))
1059 path
= catdup(g_studios_dir
, dentry
->d_name
);
1062 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "catdup() failed");
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
));
1078 if (!callback(call_ptr
, context
, dentry
->d_name
, st
.st_mtime
))
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
)
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
;
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
)
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
;
1126 if (strcmp(el
, "studio") == 0)
1128 //lash_info("<studio>");
1129 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_STUDIO
;
1133 if (strcmp(el
, "jack") == 0)
1135 //lash_info("<jack>");
1136 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_JACK
;
1140 if (strcmp(el
, "conf") == 0)
1142 //lash_info("<conf>");
1143 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONF
;
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
;
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
;
1165 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PARAMETER
;
1166 context_ptr
->data_used
= 0;
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
)
1179 struct jack_parameter_variant parameter
;
1182 if (context_ptr
->error
)
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;
1217 dst
[1] = 0; /* ASCIZZ */
1219 if (!jack_proxy_get_parameter_value(address
, &is_set
, ¶meter
))
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
)
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;
1239 lash_dbus_error(context_ptr
->call_ptr
, LASH_DBUS_ERROR_GENERIC
, "bad value for a bool jack param");
1240 goto fail_free_address
;
1244 lash_info("%s value is %s (string)", context_ptr
->path
, context_ptr
->data
);
1245 parameter
.value
.string
= context_ptr
->data
;
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];
1258 lash_info("%s value is %s (uint32)", context_ptr
->path
, context_ptr
->data
);
1259 if (sscanf(context_ptr
->data
, "%" PRIu32
, ¶meter
.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
;
1266 lash_info("%s value is %s (int32)", context_ptr
->path
, context_ptr
->data
);
1267 if (sscanf(context_ptr
->data
, "%" PRIi32
, ¶meter
.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
;
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
, ¶meter
))
1280 lash_dbus_error(context_ptr
->call_ptr
, LASH_DBUS_ERROR_GENERIC
, "jack_proxy_set_parameter_value() failed");
1281 goto fail_free_address
;
1287 context_ptr
->depth
--;
1289 if (context_ptr
->path
!= NULL
)
1291 free(context_ptr
->path
);
1292 context_ptr
->path
= NULL
;
1299 context_ptr
->error
= XML_TRUE
;
1305 bool studio_load(void * call_ptr
, const char * studio_name
)
1313 enum XML_Status xmls
;
1314 struct parse_context context
;
1316 /* TODO: unescape */
1317 path
= catdup3(g_studios_dir
, studio_name
, ".xml");
1320 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "catdup3() failed to compose path of studio \%s\" file", studio_name
);
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
));
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
);
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");
1351 fd
= open(path
, O_RDONLY
);
1354 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to open '%s': %d (%s)", path
, errno
, strerror(errno
));
1358 parser
= XML_ParserCreate(NULL
);
1361 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "XML_ParserCreate() failed to create parser object.");
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
);
1373 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "XML_GetBuffer() failed.");
1374 XML_ParserFree(parser
);
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
);
1388 context
.error
= XML_FALSE
;
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
);
1409 XML_ParserFree(parser
);
1412 lash_info("Studio loaded. ('%s')", path
);
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.");
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
);
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.");
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")
1474 METHOD_ARGS_BEGIN(Rename
, "Rename studio")
1475 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1478 METHOD_ARGS_BEGIN(Save
, "Save studio")
1482 METHOD_DESCRIBE(GetName
, ladish_get_studio_name
)
1483 METHOD_DESCRIBE(Rename
, ladish_rename_studio
)
1484 METHOD_DESCRIBE(Save
, ladish_save_studio
)
1487 SIGNAL_ARGS_BEGIN(StudioRenamed
, "Studio name changed")
1488 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1491 SIGNAL_ARGS_BEGIN(RoomAppeared
, "Room D-Bus object appeared")
1492 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1495 SIGNAL_ARGS_BEGIN(RoomDisappeared
, "Room D-Bus object disappeared")
1496 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1500 SIGNAL_DESCRIBE(StudioRenamed
)
1501 SIGNAL_DESCRIBE(RoomAppeared
)
1502 SIGNAL_DESCRIBE(RoomDisappeared
)
1505 INTERFACE_BEGIN(g_interface_studio
, IFACE_STUDIO
)
1506 INTERFACE_DEFAULT_HANDLER
1507 INTERFACE_EXPOSE_METHODS
1508 INTERFACE_EXPOSE_SIGNALS