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 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
;
83 #define EVENT_JACK_START 0
84 #define EVENT_JACK_STOP 1
88 struct list_head siblings
;
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 */
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
;
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
133 unsigned int element
[MAX_STACK_DEPTH
];
135 char data
[MAX_DATA_SIZE
];
141 jack_conf_container_create(
142 struct jack_conf_container
** container_ptr_ptr
,
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");
154 container_ptr
->name
= strdup(name
);
155 if (container_ptr
->name
== NULL
)
157 lash_error("strdup() failed to duplicate \"%s\"", name
);
161 INIT_LIST_HEAD(&container_ptr
->children
);
162 container_ptr
->children_leafs
= false;
164 *container_ptr_ptr
= container_ptr
;
175 jack_conf_parameter_create(
176 struct jack_conf_parameter
** parameter_ptr_ptr
,
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");
188 parameter_ptr
->name
= strdup(name
);
189 if (parameter_ptr
->name
== NULL
)
191 lash_error("strdup() failed to duplicate \"%s\"", name
);
195 *parameter_ptr_ptr
= parameter_ptr
;
206 jack_conf_parameter_destroy(
207 struct jack_conf_parameter
* parameter_ptr
)
210 lash_info("jack_conf_parameter destroy");
212 switch (parameter_ptr
->parameter
.type
)
215 lash_info("%s value is %s (boolean)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
218 lash_info("%s value is %s (string)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.string
);
221 lash_info("%s value is %u/%c (byte/char)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
224 lash_info("%s value is %u (uint32)", parameter_ptr
->name
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
227 lash_info("%s value is %u (int32)", parameter_ptr
->name
, (signed int)parameter_ptr
->parameter
.value
.int32
);
230 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, parameter_ptr
->name
);
235 if (parameter_ptr
->parameter
.type
== jack_string
)
237 free(parameter_ptr
->parameter
.value
.string
);
240 free(parameter_ptr
->name
);
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
;
258 jack_conf_container_destroy(list_entry(node_ptr
, struct jack_conf_container
, siblings
));
263 while (!list_empty(&container_ptr
->children
))
265 node_ptr
= container_ptr
->children
.next
;
267 jack_conf_parameter_destroy(list_entry(node_ptr
, struct jack_conf_parameter
, siblings
));
271 free(container_ptr
->name
);
275 #define context_ptr ((struct conf_callback_context *)context)
282 const char * address
,
285 char path
[JACK_CONF_MAX_ADDRESS_SIZE
];
286 const char * component
;
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");
304 while (*component
!= 0)
306 len
= strlen(component
);
307 memcpy(dst
, component
, len
);
309 component
+= len
+ 1;
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
);
325 lash_debug("%s (leaf)", path
);
327 if (parent_ptr
== NULL
)
329 lash_error("jack conf parameters can't appear in root container");
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");
341 parent_ptr
->children_leafs
= true;
344 if (!jack_conf_parameter_create(¶meter_ptr
, child
))
346 lash_error("jack_conf_parameter_create() failed");
350 if (!jack_proxy_get_parameter_value(context_ptr
->address
, &is_set
, ¶meter_ptr
->parameter
))
352 lash_error("cannot get value of %s", path
);
359 switch (parameter_ptr
->parameter
.type
)
362 lash_info("%s value is %s (boolean)", path
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
365 lash_info("%s value is %s (string)", path
, parameter_ptr
->parameter
.value
.string
);
368 lash_info("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
371 lash_info("%s value is %u (uint32)", path
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
374 lash_info("%s value is %u (int32)", path
, (signed int)parameter_ptr
->parameter
.value
.int32
);
377 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
378 jack_conf_parameter_destroy(parameter_ptr
);
383 parameter_ptr
->parent_ptr
= parent_ptr
;
384 memcpy(parameter_ptr
->address
, context_ptr
->address
, JACK_CONF_MAX_ADDRESS_SIZE
);
385 list_add_tail(¶meter_ptr
->siblings
, &parent_ptr
->children
);
386 list_add_tail(¶meter_ptr
->leaves
, &g_studio
.jack_params
);
390 jack_conf_parameter_destroy(parameter_ptr
);
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");
403 if (!jack_conf_container_create(&container_ptr
, child
))
405 lash_error("jack_conf_container_create() failed");
409 container_ptr
->parent_ptr
= parent_ptr
;
411 if (parent_ptr
== NULL
)
413 list_add_tail(&container_ptr
->siblings
, &g_studio
.jack_conf
);
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
);
428 context_ptr
->parent_ptr
= parent_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
;
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
;
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.");
472 bool studio_name_generate(char ** name_ptr
)
475 char timestamp_str
[26];
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
);
486 lash_error("catdup failed to create studio name");
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
);
504 lash_error("object_path_new() failed");
508 if (!object_path_register(g_dbus_connection
, object
))
510 lash_error("object_path_register() failed");
511 object_path_destroy(g_dbus_connection
, object
);
515 lash_info("Studio D-Bus object created. \"%s\"", g_studio
.name
);
517 g_studio
.dbus_object
= object
;
519 emit_studio_appeared();
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.");
547 emit_studio_started();
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();
567 lash_error("Stopping JACK server failed.");
578 g_studio
.modified
= false;
579 g_studio
.persisted
= false;
580 g_studio
.automatic
= false;
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
)
596 g_studio
.name
= NULL
;
599 if (g_studio
.filename
!= NULL
)
601 free(g_studio
.filename
);
602 g_studio
.filename
= NULL
;
607 studio_clear_if_automatic(void)
609 if (g_studio
.automatic
)
611 lash_info("Unloading automatic studio.");
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.");
628 g_studio
.automatic
= true;
633 if (!studio_fetch_jack_settings(g_studio
))
635 lash_error("studio_fetch_jack_settings() failed.");
637 studio_clear_if_automatic();
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();
669 case EVENT_JACK_STOP
:
670 on_event_jack_stopped();
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.");
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.");
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)
725 studio_get_graph_version(
728 //lash_info("studio_get_graph_version() called");
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
);
745 if (!ensure_dir_exist(g_studios_dir
, 0700))
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;
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
))
787 void studio_uninit(void)
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
)
805 static char hex_digits
[] = "0123456789ABCDEF";
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) */
820 dst
[1] = hex_digits
[*src
>> 4];
821 dst
[2] = hex_digits
[*src
& 0x0F];
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
)
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);
869 static bool compose_filename(const char * name
, char ** filename_ptr_ptr
, char ** backup_filename_ptr_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");
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");
898 memcpy(p
, g_studios_dir
, len_dir
);
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
;
920 write_string(int fd
, const char * string
, void * call_ptr
)
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.");
936 write_jack_parameter(
939 struct jack_conf_parameter
* parameter_ptr
,
944 char path
[JACK_CONF_MAX_ADDRESS_SIZE
* 3]; /* encode each char in three bytes (percent encoding) */
945 const char * content
;
948 /* compose the parameter path, percent-encode "bad" chars */
949 src
= parameter_ptr
->address
;
960 if (!write_string(fd
, indent
, call_ptr
))
965 if (!write_string(fd
, "<parameter path=\"", call_ptr
))
970 if (!write_string(fd
, path
, call_ptr
))
975 if (!write_string(fd
, "\">", call_ptr
))
980 switch (parameter_ptr
->parameter
.type
)
983 content
= parameter_ptr
->parameter
.value
.boolean
? "true" : "false";
984 lash_debug("%s value is %s (boolean)", path
, content
);
987 content
= parameter_ptr
->parameter
.value
.string
;
988 lash_debug("%s value is %s (string)", path
, content
);
991 valbuf
[0] = (char)parameter_ptr
->parameter
.value
.byte
;
994 lash_debug("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
997 snprintf(valbuf
, sizeof(valbuf
), "%" PRIu32
, parameter_ptr
->parameter
.value
.uint32
);
999 lash_debug("%s value is %s (uint32)", path
, content
);
1002 snprintf(valbuf
, sizeof(valbuf
), "%" PRIi32
, parameter_ptr
->parameter
.value
.int32
);
1004 lash_debug("%s value is %s (int32)", path
, content
);
1007 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
1011 if (!write_string(fd
, content
, call_ptr
))
1016 if (!write_string(fd
, "</parameter>\n", call_ptr
))
1024 bool studio_save(void * call_ptr
)
1026 struct list_head
* node_ptr
;
1027 struct jack_conf_parameter
* parameter_ptr
;
1030 char timestamp_str
[26];
1032 char * filename
; /* filename */
1033 char * bak_filename
; /* filename of the backup file */
1034 char * old_filename
; /* filename where studio was persisted before save */
1038 ctime_r(×tamp
, timestamp_str
);
1039 timestamp_str
[24] = 0;
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");
1049 if (g_studio
.filename
== NULL
)
1051 /* saving studio for first time */
1052 g_studio
.filename
= 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
;
1064 /* saving renamed studio */
1065 old_filename
= g_studio
.filename
;
1066 g_studio
.filename
= filename
;
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
;
1088 /* mark that there is no backup file */
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);
1099 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "open(%s) failed: %d (%s)", g_studio
.filename
, errno
, strerror(errno
));
1103 if (!write_string(fd
, "<?xml version=\"1.0\"?>\n", call_ptr
))
1108 if (!write_string(fd
, "<!--\n", call_ptr
))
1113 if (!write_string(fd
, STUDIO_HEADER_TEXT
, call_ptr
))
1118 if (!write_string(fd
, "-->\n", call_ptr
))
1123 if (!write_string(fd
, "<!-- ", call_ptr
))
1128 if (!write_string(fd
, timestamp_str
, call_ptr
))
1133 if (!write_string(fd
, " -->\n", call_ptr
))
1138 if (!write_string(fd
, "<studio>\n", call_ptr
))
1143 if (!write_string(fd
, " <jack>\n", call_ptr
))
1148 if (!write_string(fd
, " <conf>\n", call_ptr
))
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
))
1163 if (!write_string(fd
, " </conf>\n", call_ptr
))
1168 if (!write_string(fd
, " </jack>\n", call_ptr
))
1173 if (!write_string(fd
, "</studio>\n", call_ptr
))
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 */
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
));
1197 if (bak_filename
!= NULL
)
1202 if (old_filename
!= NULL
)
1207 assert(filename
== NULL
);
1208 assert(g_studio
.filename
!= NULL
);
1214 bool studios_iterate(void * call_ptr
, void * context
, bool (* callback
)(void * call_ptr
, void * context
, const char * studio
, uint32_t modtime
))
1217 struct dirent
* dentry
;
1223 dir
= opendir(g_studios_dir
);
1226 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Cannot open directory '%s': %d (%s)", g_studios_dir
, errno
, strerror(errno
));
1230 while ((dentry
= readdir(dir
)) != NULL
)
1232 if (dentry
->d_type
!= DT_REG
)
1235 len
= strlen(dentry
->d_name
);
1236 if (len
<= 4 || strcmp(dentry
->d_name
+ (len
- 4), ".xml") != 0)
1239 path
= catdup(g_studios_dir
, dentry
->d_name
);
1242 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "catdup() failed");
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
));
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
))
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
)
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
;
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
)
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
;
1310 if (strcmp(el
, "studio") == 0)
1312 //lash_info("<studio>");
1313 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_STUDIO
;
1317 if (strcmp(el
, "jack") == 0)
1319 //lash_info("<jack>");
1320 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_JACK
;
1324 if (strcmp(el
, "conf") == 0)
1326 //lash_info("<conf>");
1327 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_CONF
;
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
;
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
;
1349 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_PARAMETER
;
1350 context_ptr
->data_used
= 0;
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
)
1366 struct jack_parameter_variant parameter
;
1369 if (context_ptr
->error
)
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;
1390 sep
= strchr(src
, '/');
1393 src_len
= strlen(src
);
1397 src_len
= sep
- src
;
1400 dst_len
= unescape(src
, src_len
, dst
);
1405 assert(*src
== '/' || *src
== 0);
1408 assert(*src
== '/');
1409 src
++; /* skip separator */
1416 *dst
= 0; /* ASCIZZ */
1418 if (!jack_proxy_get_parameter_value(address
, &is_set
, ¶meter
))
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
)
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;
1443 lash_dbus_error(context_ptr
->call_ptr
, LASH_DBUS_ERROR_GENERIC
, "bad value for a bool jack param");
1444 goto fail_free_address
;
1448 lash_info("%s value is %s (string)", context_ptr
->path
, context_ptr
->data
);
1449 parameter
.value
.string
= context_ptr
->data
;
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];
1462 lash_info("%s value is %s (uint32)", context_ptr
->path
, context_ptr
->data
);
1463 if (sscanf(context_ptr
->data
, "%" PRIu32
, ¶meter
.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
;
1470 lash_info("%s value is %s (int32)", context_ptr
->path
, context_ptr
->data
);
1471 if (sscanf(context_ptr
->data
, "%" PRIi32
, ¶meter
.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
;
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
, ¶meter
))
1484 lash_dbus_error(context_ptr
->call_ptr
, LASH_DBUS_ERROR_GENERIC
, "jack_proxy_set_parameter_value() failed");
1485 goto fail_free_address
;
1491 context_ptr
->depth
--;
1493 if (context_ptr
->path
!= NULL
)
1495 free(context_ptr
->path
);
1496 context_ptr
->path
= NULL
;
1503 context_ptr
->error
= XML_TRUE
;
1509 bool studio_delete(void * call_ptr
, const char * studio_name
)
1512 char * bak_filename
;
1518 if (!compose_filename(studio_name
, &filename
, &bak_filename
))
1520 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to compose studio filename");
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
));
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
));
1551 bool studio_load(void * call_ptr
, const char * studio_name
)
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
);
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
));
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
);
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");
1595 fd
= open(path
, O_RDONLY
);
1598 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to open '%s': %d (%s)", path
, errno
, strerror(errno
));
1602 parser
= XML_ParserCreate(NULL
);
1605 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "XML_ParserCreate() failed to create parser object.");
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
);
1617 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "XML_GetBuffer() failed.");
1618 XML_ParserFree(parser
);
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
);
1632 context
.error
= XML_FALSE
;
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
);
1653 XML_ParserFree(parser
);
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.");
1666 if (!studio_start())
1668 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Failed to start JACK server.");
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
);
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.");
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");
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
);
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.");
1744 else if (!studio_name_generate(&g_studio
.name
))
1746 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "studio_name_generate() failed.");
1750 if (!studio_publish())
1752 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "studio_publish() failed.");
1760 static void ladish_stop_studio(method_call_t
* call_ptr
)
1762 lash_info("Studio stop requested");
1766 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "Failed to stop studio.");
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.");
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")
1792 METHOD_ARGS_BEGIN(Rename
, "Rename studio")
1793 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1796 METHOD_ARGS_BEGIN(Save
, "Save studio")
1799 METHOD_ARGS_BEGIN(Unload
, "Unload studio")
1802 METHOD_ARGS_BEGIN(Start
, "Start studio")
1805 METHOD_ARGS_BEGIN(Stop
, "Stop studio")
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
)
1817 SIGNAL_ARGS_BEGIN(StudioRenamed
, "Studio name changed")
1818 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1821 SIGNAL_ARGS_BEGIN(StudioStarted
, "Studio started")
1824 SIGNAL_ARGS_BEGIN(StudioStopped
, "Studio stopped")
1827 SIGNAL_ARGS_BEGIN(RoomAppeared
, "Room D-Bus object appeared")
1828 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1831 SIGNAL_ARGS_BEGIN(RoomDisappeared
, "Room D-Bus object disappeared")
1832 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
1836 SIGNAL_DESCRIBE(StudioRenamed
)
1837 SIGNAL_DESCRIBE(StudioStarted
)
1838 SIGNAL_DESCRIBE(StudioStopped
)
1839 SIGNAL_DESCRIBE(RoomAppeared
)
1840 SIGNAL_DESCRIBE(RoomDisappeared
)
1843 INTERFACE_BEGIN(g_interface_studio
, IFACE_STUDIO
)
1844 INTERFACE_DEFAULT_HANDLER
1845 INTERFACE_EXPOSE_METHODS
1846 INTERFACE_EXPOSE_SIGNALS