Move jack handling into studio object; fix race
[ladish.git] / daemon / studio.c
blobce36dde927b0eaab04c9ca1449f2793599912709
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the studio singleton object
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
28 #include "../jack_proxy.h"
29 #include "patchbay.h"
30 #include "../dbus_constants.h"
31 #include "control.h"
33 extern const interface_t g_interface_studio;
35 struct studio
37 /* this must be first member of struct studio because object_path_new() assumes all interfaces have same context */
38 struct patchbay_implementator patchbay_impl;
40 struct list_head all_connections; /* All connections (studio guts and all rooms). Including superconnections. */
41 struct list_head all_ports; /* All ports (studio guts and all rooms) */
42 struct list_head all_clients; /* All clients (studio guts and all rooms) */
43 struct list_head jack_connections; /* JACK connections (studio guts and all rooms). Including superconnections, excluding virtual connections. */
44 struct list_head jack_ports; /* JACK ports (studio guts and all rooms). Excluding virtual ports. */
45 struct list_head jack_clients; /* JACK clients (studio guts and all rooms). Excluding virtual clients. */
46 struct list_head rooms; /* Rooms connected to the studio */
47 struct list_head clients; /* studio clients (studio guts and room links) */
48 struct list_head ports; /* studio ports (studio guts and room links) */
50 bool persisted:1; /* Studio has on-disk representation, i.e. can be reloaded from disk */
51 bool modified:1; /* Studio needs saving */
52 bool jack_conf_valid:1; /* JACK server configuration obtained successfully */
54 struct list_head jack_conf; /* root of the conf tree */
55 struct list_head jack_params; /* list of conf tree leaves */
57 object_path_t * dbus_object;
59 struct list_head event_queue;
60 } g_studio;
62 #define EVENT_JACK_START 0
63 #define EVENT_JACK_STOP 1
65 struct event
67 struct list_head siblings;
68 unsigned int type;
71 #define JACK_CONF_MAX_ADDRESS_SIZE 1024
73 struct jack_conf_parameter
75 struct list_head siblings; /* siblings in container children list */
76 struct list_head leaves; /* studio::jack_param siblings */
77 char * name;
78 struct jack_conf_container * parent_ptr;
79 char address[JACK_CONF_MAX_ADDRESS_SIZE];
80 struct jack_parameter_variant parameter;
83 struct jack_conf_container
85 struct list_head siblings;
86 char * name;
87 struct jack_conf_container * parent_ptr;
88 bool children_leafs; /* if true, children are "jack_conf_parameter"s, if false, children are "jack_conf_container"s */
89 struct list_head children;
92 struct conf_callback_context
94 char address[JACK_CONF_MAX_ADDRESS_SIZE];
95 struct list_head * container_ptr;
96 struct jack_conf_container * parent_ptr;
99 bool
100 jack_conf_container_create(
101 struct jack_conf_container ** container_ptr_ptr,
102 const char * name)
104 struct jack_conf_container * container_ptr;
106 container_ptr = malloc(sizeof(struct jack_conf_container));
107 if (container_ptr == NULL)
109 lash_error("malloc() failed to allocate struct jack_conf_container");
110 goto fail;
113 container_ptr->name = strdup(name);
114 if (container_ptr->name == NULL)
116 lash_error("strdup() failed to duplicate \"%s\"", name);
117 goto fail_free;
120 INIT_LIST_HEAD(&container_ptr->children);
121 container_ptr->children_leafs = false;
123 *container_ptr_ptr = container_ptr;
124 return true;
126 fail_free:
127 free(container_ptr);
129 fail:
130 return false;
133 bool
134 jack_conf_parameter_create(
135 struct jack_conf_parameter ** parameter_ptr_ptr,
136 const char * name)
138 struct jack_conf_parameter * parameter_ptr;
140 parameter_ptr = malloc(sizeof(struct jack_conf_parameter));
141 if (parameter_ptr == NULL)
143 lash_error("malloc() failed to allocate struct jack_conf_parameter");
144 goto fail;
147 parameter_ptr->name = strdup(name);
148 if (parameter_ptr->name == NULL)
150 lash_error("strdup() failed to duplicate \"%s\"", name);
151 goto fail_free;
154 *parameter_ptr_ptr = parameter_ptr;
155 return true;
157 fail_free:
158 free(parameter_ptr);
160 fail:
161 return false;
164 void
165 jack_conf_parameter_destroy(
166 struct jack_conf_parameter * parameter_ptr)
168 #if 0
169 lash_info("jack_conf_parameter destroy");
171 switch (parameter_ptr->parameter.type)
173 case jack_boolean:
174 lash_info("%s value is %s (boolean)", parameter_ptr->name, parameter_ptr->parameter.value.boolean ? "true" : "false");
175 break;
176 case jack_string:
177 lash_info("%s value is %s (string)", parameter_ptr->name, parameter_ptr->parameter.value.string);
178 break;
179 case jack_byte:
180 lash_info("%s value is %u/%c (byte/char)", parameter_ptr->name, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
181 break;
182 case jack_uint32:
183 lash_info("%s value is %u (uint32)", parameter_ptr->name, (unsigned int)parameter_ptr->parameter.value.uint32);
184 break;
185 case jack_int32:
186 lash_info("%s value is %u (int32)", parameter_ptr->name, (signed int)parameter_ptr->parameter.value.int32);
187 break;
188 default:
189 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, parameter_ptr->name);
190 break;
192 #endif
194 if (parameter_ptr->parameter.type == jack_string)
196 free(parameter_ptr->parameter.value.string);
199 free(parameter_ptr->name);
200 free(parameter_ptr);
203 void
204 jack_conf_container_destroy(
205 struct jack_conf_container * container_ptr)
207 struct list_head * node_ptr;
209 //lash_info("\"%s\" jack_conf_parameter destroy", container_ptr->name);
211 if (!container_ptr->children_leafs)
213 while (!list_empty(&container_ptr->children))
215 node_ptr = container_ptr->children.next;
216 list_del(node_ptr);
217 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
220 else
222 while (!list_empty(&container_ptr->children))
224 node_ptr = container_ptr->children.next;
225 list_del(node_ptr);
226 jack_conf_parameter_destroy(list_entry(node_ptr, struct jack_conf_parameter, siblings));
230 free(container_ptr->name);
231 free(container_ptr);
234 #define context_ptr ((struct conf_callback_context *)context)
236 static
237 bool
238 conf_callback(
239 void * context,
240 bool leaf,
241 const char * address,
242 char * child)
244 char path[JACK_CONF_MAX_ADDRESS_SIZE];
245 const char * component;
246 char * dst;
247 size_t len;
248 bool is_set;
249 struct jack_conf_container * parent_ptr;
250 struct jack_conf_container * container_ptr;
251 struct jack_conf_parameter * parameter_ptr;
253 parent_ptr = context_ptr->parent_ptr;
255 dst = path;
256 component = address;
257 while (*component != 0)
259 len = strlen(component);
260 memcpy(dst, component, len);
261 dst[len] = ':';
262 component += len + 1;
263 dst += len + 1;
266 strcpy(dst, child);
268 /* address always is same buffer as the one supplied through context pointer */
269 assert(context_ptr->address == address);
270 dst = (char *)component;
272 len = strlen(child) + 1;
273 memcpy(dst, child, len);
274 dst[len] = 0;
276 if (leaf)
278 lash_debug("%s (leaf)", path);
280 if (parent_ptr == NULL)
282 lash_error("jack conf parameters can't appear in root container");
283 return false;
286 if (!parent_ptr->children_leafs)
288 if (!list_empty(&parent_ptr->children))
290 lash_error("jack conf parameters cant be mixed with containers at same hierarchy level");
291 return false;
294 parent_ptr->children_leafs = true;
297 if (!jack_conf_parameter_create(&parameter_ptr, child))
299 lash_error("jack_conf_parameter_create() failed");
300 return false;
303 if (!jack_proxy_get_parameter_value(context_ptr->address, &is_set, &parameter_ptr->parameter))
305 lash_error("cannot get value of %s", path);
306 return false;
309 if (is_set)
311 switch (parameter_ptr->parameter.type)
313 case jack_boolean:
314 lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false");
315 break;
316 case jack_string:
317 lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string);
318 break;
319 case jack_byte:
320 lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
321 break;
322 case jack_uint32:
323 lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32);
324 break;
325 case jack_int32:
326 lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32);
327 break;
328 default:
329 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
330 jack_conf_parameter_destroy(parameter_ptr);
331 return false;
334 parameter_ptr->parent_ptr = parent_ptr;
335 memcpy(parameter_ptr->address, context_ptr->address, JACK_CONF_MAX_ADDRESS_SIZE);
336 list_add_tail(&parameter_ptr->siblings, &parent_ptr->children);
337 list_add_tail(&parameter_ptr->leaves, &g_studio.jack_params);
339 else
341 jack_conf_parameter_destroy(parameter_ptr);
344 else
346 lash_debug("%s (container)", path);
348 if (parent_ptr != NULL && parent_ptr->children_leafs)
350 lash_error("jack conf containers cant be mixed with parameters at same hierarchy level");
351 return false;
354 if (!jack_conf_container_create(&container_ptr, child))
356 lash_error("jack_conf_container_create() failed");
357 return false;
360 container_ptr->parent_ptr = parent_ptr;
362 if (parent_ptr == NULL)
364 list_add_tail(&container_ptr->siblings, &g_studio.jack_conf);
366 else
368 list_add_tail(&container_ptr->siblings, &parent_ptr->children);
371 context_ptr->parent_ptr = container_ptr;
373 if (!jack_proxy_read_conf_container(context_ptr->address, context, conf_callback))
375 lash_error("cannot read container %s", path);
376 return false;
379 context_ptr->parent_ptr = parent_ptr;
382 *dst = 0;
384 return true;
387 #undef context_ptr
389 bool studio_fetch_jack_settings()
391 struct conf_callback_context context;
393 context.address[0] = 0;
394 context.container_ptr = &g_studio.jack_conf;
395 context.parent_ptr = NULL;
397 if (!jack_proxy_read_conf_container(context.address, &context, conf_callback))
399 lash_error("jack_proxy_read_conf_container() failed.");
400 return false;
403 return true;
406 bool
407 studio_activate(void)
409 object_path_t * object;
411 object = object_path_new(STUDIO_OBJECT_PATH, &g_studio, 2, &g_interface_studio, &g_interface_patchbay);
412 if (object == NULL)
414 lash_error("object_path_new() failed");
415 return false;
418 if (!object_path_register(g_dbus_connection, object))
420 lash_error("object_path_register() failed");
421 object_path_destroy(g_dbus_connection, object);
422 return false;
425 lash_info("Studio D-Bus object created.");
427 g_studio.dbus_object = object;
429 emit_studio_appeared();
431 return true;
434 void
435 studio_clear(void)
437 struct list_head * node_ptr;
439 g_studio.modified = false;
440 g_studio.persisted = false;
442 while (!list_empty(&g_studio.jack_conf))
444 node_ptr = g_studio.jack_conf.next;
445 list_del(node_ptr);
446 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
449 g_studio.jack_conf_valid = false;
451 if (g_studio.dbus_object != NULL)
453 object_path_destroy(g_dbus_connection, g_studio.dbus_object);
454 g_studio.dbus_object = NULL;
455 emit_studio_disappeared();
459 void
460 studio_clear_if_not_persisted(void)
462 if (!g_studio.persisted)
464 studio_clear();
465 return;
469 void on_event_jack_started(void)
471 if (g_studio.dbus_object == NULL)
473 studio_activate();
476 if (!studio_fetch_jack_settings(g_studio))
478 lash_error("studio_fetch_jack_settings() failed.");
480 studio_clear_if_not_persisted();
481 return;
484 lash_info("jack conf successfully retrieved");
485 g_studio.jack_conf_valid = true;
488 void on_event_jack_stopped(void)
490 studio_clear_if_not_persisted();
492 /* TODO: if user wants, restart jack server and reconnect all jack apps to it */
495 void studio_run(void)
497 struct event * event_ptr;
499 while (!list_empty(&g_studio.event_queue))
501 event_ptr = list_entry(g_studio.event_queue.next, struct event, siblings);
502 list_del(g_studio.event_queue.next);
504 switch (event_ptr->type)
506 case EVENT_JACK_START:
507 on_event_jack_started();
508 break;
509 case EVENT_JACK_STOP:
510 on_event_jack_stopped();
511 break;
514 free(event_ptr);
518 static void on_jack_server_started(void)
520 struct event * event_ptr;
522 lash_info("JACK server start detected.");
524 event_ptr = malloc(sizeof(struct event));
525 if (event_ptr == NULL)
527 lash_error("malloc() failed to allocate struct event. Ignoring JACK start.");
528 return;
531 event_ptr->type = EVENT_JACK_START;
532 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
535 static void on_jack_server_stopped(void)
537 struct event * event_ptr;
539 lash_info("JACK server stop detected.");
541 event_ptr = malloc(sizeof(struct event));
542 if (event_ptr == NULL)
544 lash_error("malloc() failed to allocate struct event. Ignoring JACK stop.");
545 return;
548 event_ptr->type = EVENT_JACK_STOP;
549 list_add_tail(&event_ptr->siblings, &g_studio.event_queue);
552 static void on_jack_server_appeared(void)
554 lash_info("JACK controller appeared.");
557 static void on_jack_server_disappeared(void)
559 lash_info("JACK controller disappeared.");
562 #define studio_ptr ((struct studio *)this)
564 uint64_t
565 studio_get_graph_version(
566 void * this)
568 //lash_info("studio_get_graph_version() called");
569 return 1;
572 #undef studio_ptr
574 bool studio_init(void)
576 lash_info("studio object construct");
578 g_studio.patchbay_impl.this = &g_studio;
579 g_studio.patchbay_impl.get_graph_version = studio_get_graph_version;
581 INIT_LIST_HEAD(&g_studio.all_connections);
582 INIT_LIST_HEAD(&g_studio.all_ports);
583 INIT_LIST_HEAD(&g_studio.all_clients);
584 INIT_LIST_HEAD(&g_studio.jack_connections);
585 INIT_LIST_HEAD(&g_studio.jack_ports);
586 INIT_LIST_HEAD(&g_studio.jack_clients);
587 INIT_LIST_HEAD(&g_studio.rooms);
588 INIT_LIST_HEAD(&g_studio.clients);
589 INIT_LIST_HEAD(&g_studio.ports);
591 INIT_LIST_HEAD(&g_studio.jack_conf);
592 INIT_LIST_HEAD(&g_studio.jack_params);
594 INIT_LIST_HEAD(&g_studio.event_queue);
596 g_studio.dbus_object = NULL;
597 studio_clear();
599 if (!jack_proxy_init(
600 on_jack_server_started,
601 on_jack_server_stopped,
602 on_jack_server_appeared,
603 on_jack_server_disappeared))
605 return false;
608 return true;
611 void studio_uninit(void)
613 jack_proxy_uninit();
615 studio_clear();
617 lash_info("studio object destroy");
620 bool studio_is_loaded(void)
622 return g_studio.dbus_object != NULL;
625 bool studio_save(const char * file_path)
627 struct list_head * node_ptr;
628 struct jack_conf_parameter * parameter_ptr;
629 char path[JACK_CONF_MAX_ADDRESS_SIZE * 3]; /* encode each char in three bytes (percent encoding) */
630 const char * src;
631 char * dst;
632 static char hex_digits[] = "0123456789ABCDEF";
634 lash_info("saving studio...");
636 list_for_each(node_ptr, &g_studio.jack_params)
638 parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves);
640 /* compose the parameter path, percent-encode "bad" chars */
641 src = parameter_ptr->address;
642 dst = path;
645 *dst++ = '/';
646 while (*src != 0)
648 switch (*src)
650 case '/': /* used as separator for address components */
651 case '<': /* invalid attribute value char (XML spec) */
652 case '&': /* invalid attribute value char (XML spec) */
653 case '"': /* we store attribute values in double quotes - invalid attribute value char (XML spec) */
654 case '%':
655 dst[0] = '%';
656 dst[1] = hex_digits[*src >> 4];
657 dst[2] = hex_digits[*src & 0x0F];
658 dst += 3;
659 src++;
660 break;
661 default:
662 *dst++ = *src++;
665 src++;
667 while (*src != 0);
668 *dst = 0;
670 switch (parameter_ptr->parameter.type)
672 case jack_boolean:
673 lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false");
674 break;
675 case jack_string:
676 lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string);
677 break;
678 case jack_byte:
679 lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
680 break;
681 case jack_uint32:
682 lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32);
683 break;
684 case jack_int32:
685 lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32);
686 break;
687 default:
688 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
689 return false;
693 return false; /* not implemented yet */
696 bool studio_load(const char * file_path)
698 return false; /* not implemented yet */
701 static void ladish_save_studio(method_call_t * call_ptr)
703 //studio_save(g_studio, NULL)
706 METHOD_ARGS_BEGIN(Save, "Save studio")
707 METHOD_ARGS_END
709 METHODS_BEGIN
710 METHOD_DESCRIBE(Save, ladish_save_studio)
711 METHODS_END
713 SIGNAL_ARGS_BEGIN(RoomAppeared, "Room D-Bus object appeared")
714 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
715 SIGNAL_ARGS_END
717 SIGNAL_ARGS_BEGIN(RoomDisappeared, "Room D-Bus object disappeared")
718 SIGNAL_ARG_DESCRIBE("room_path", "s", "room object path")
719 SIGNAL_ARGS_END
721 SIGNALS_BEGIN
722 SIGNAL_DESCRIBE(RoomAppeared)
723 SIGNAL_DESCRIBE(RoomDisappeared)
724 SIGNALS_END
726 INTERFACE_BEGIN(g_interface_studio, IFACE_STUDIO)
727 INTERFACE_DEFAULT_HANDLER
728 INTERFACE_EXPOSE_METHODS
729 INTERFACE_EXPOSE_SIGNALS
730 INTERFACE_END