Quit when requested from the menu
[ladish.git] / daemon / studio.c
blobafef7348fddc5064b9fb518db7109cf95f44670a
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 studio object helpers
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"
30 struct studio
32 struct list_head all_connections; /* All connections (studio guts and all rooms). Including superconnections. */
33 struct list_head all_ports; /* All ports (studio guts and all rooms) */
34 struct list_head all_clients; /* All clients (studio guts and all rooms) */
35 struct list_head jack_connections; /* JACK connections (studio guts and all rooms). Including superconnections, excluding virtual connections. */
36 struct list_head jack_ports; /* JACK ports (studio guts and all rooms). Excluding virtual ports. */
37 struct list_head jack_clients; /* JACK clients (studio guts and all rooms). Excluding virtual clients. */
38 struct list_head rooms; /* Rooms connected to the studio */
39 struct list_head clients; /* studio clients (studio guts and room links) */
40 struct list_head ports; /* studio ports (studio guts and room links) */
42 bool persisted:1; /* Studio has on-disk representation, i.e. can be reloaded from disk */
43 bool modified:1; /* Studio needs saving */
44 bool jack_conf_stable:1; /* JACK server configuration obtained successfully */
46 struct list_head jack_conf; /* root of the conf tree */
47 struct list_head jack_params; /* list of conf tree leaves */
49 object_path_t * dbus_object;
52 #define JACK_CONF_MAX_ADDRESS_SIZE 1024
54 struct jack_conf_parameter
56 struct list_head siblings; /* siblings in container children list */
57 struct list_head leaves; /* studio::jack_param siblings */
58 char * name;
59 struct jack_conf_container * parent_ptr;
60 char address[JACK_CONF_MAX_ADDRESS_SIZE];
61 struct jack_parameter_variant parameter;
64 struct jack_conf_container
66 struct list_head siblings;
67 char * name;
68 struct jack_conf_container * parent_ptr;
69 bool children_leafs; /* if true, children are "jack_conf_parameter"s, if false, children are "jack_conf_container"s */
70 struct list_head children;
73 struct conf_callback_context
75 char address[JACK_CONF_MAX_ADDRESS_SIZE];
76 struct list_head * container_ptr;
77 struct studio * studio_ptr;
78 struct jack_conf_container * parent_ptr;
81 bool
82 jack_conf_container_create(
83 struct jack_conf_container ** container_ptr_ptr,
84 const char * name)
86 struct jack_conf_container * container_ptr;
88 container_ptr = malloc(sizeof(struct jack_conf_container));
89 if (container_ptr == NULL)
91 lash_error("malloc() failed to allocate struct jack_conf_container");
92 goto fail;
95 container_ptr->name = strdup(name);
96 if (container_ptr->name == NULL)
98 lash_error("strdup() failed to duplicate \"%s\"", name);
99 goto fail_free;
102 INIT_LIST_HEAD(&container_ptr->children);
103 container_ptr->children_leafs = false;
105 *container_ptr_ptr = container_ptr;
106 return true;
108 fail_free:
109 free(container_ptr);
111 fail:
112 return false;
115 bool
116 jack_conf_parameter_create(
117 struct jack_conf_parameter ** parameter_ptr_ptr,
118 const char * name)
120 struct jack_conf_parameter * parameter_ptr;
122 parameter_ptr = malloc(sizeof(struct jack_conf_parameter));
123 if (parameter_ptr == NULL)
125 lash_error("malloc() failed to allocate struct jack_conf_parameter");
126 goto fail;
129 parameter_ptr->name = strdup(name);
130 if (parameter_ptr->name == NULL)
132 lash_error("strdup() failed to duplicate \"%s\"", name);
133 goto fail_free;
136 *parameter_ptr_ptr = parameter_ptr;
137 return true;
139 fail_free:
140 free(parameter_ptr);
142 fail:
143 return false;
146 void
147 jack_conf_parameter_destroy(
148 struct jack_conf_parameter * parameter_ptr)
150 #if 0
151 lash_info("jack_conf_parameter destroy");
153 switch (parameter_ptr->parameter.type)
155 case jack_boolean:
156 lash_info("%s value is %s (boolean)", parameter_ptr->name, parameter_ptr->parameter.value.boolean ? "true" : "false");
157 break;
158 case jack_string:
159 lash_info("%s value is %s (string)", parameter_ptr->name, parameter_ptr->parameter.value.string);
160 break;
161 case jack_byte:
162 lash_info("%s value is %u/%c (byte/char)", parameter_ptr->name, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
163 break;
164 case jack_uint32:
165 lash_info("%s value is %u (uint32)", parameter_ptr->name, (unsigned int)parameter_ptr->parameter.value.uint32);
166 break;
167 case jack_int32:
168 lash_info("%s value is %u (int32)", parameter_ptr->name, (signed int)parameter_ptr->parameter.value.int32);
169 break;
170 default:
171 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, parameter_ptr->name);
172 break;
174 #endif
176 if (parameter_ptr->parameter.type == jack_string)
178 free(parameter_ptr->parameter.value.string);
181 free(parameter_ptr->name);
182 free(parameter_ptr);
185 void
186 jack_conf_container_destroy(
187 struct jack_conf_container * container_ptr)
189 struct list_head * node_ptr;
191 //lash_info("\"%s\" jack_conf_parameter destroy", container_ptr->name);
193 if (!container_ptr->children_leafs)
195 while (!list_empty(&container_ptr->children))
197 node_ptr = container_ptr->children.next;
198 list_del(node_ptr);
199 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
202 else
204 while (!list_empty(&container_ptr->children))
206 node_ptr = container_ptr->children.next;
207 list_del(node_ptr);
208 jack_conf_parameter_destroy(list_entry(node_ptr, struct jack_conf_parameter, siblings));
212 free(container_ptr->name);
213 free(container_ptr);
216 #define context_ptr ((struct conf_callback_context *)context)
218 static
219 bool
220 conf_callback(
221 void * context,
222 bool leaf,
223 const char * address,
224 char * child)
226 char path[JACK_CONF_MAX_ADDRESS_SIZE];
227 const char * component;
228 char * dst;
229 size_t len;
230 bool is_set;
231 struct jack_conf_container * parent_ptr;
232 struct jack_conf_container * container_ptr;
233 struct jack_conf_parameter * parameter_ptr;
235 assert(context_ptr->studio_ptr);
237 parent_ptr = context_ptr->parent_ptr;
239 dst = path;
240 component = address;
241 while (*component != 0)
243 len = strlen(component);
244 memcpy(dst, component, len);
245 dst[len] = ':';
246 component += len + 1;
247 dst += len + 1;
250 strcpy(dst, child);
252 /* address always is same buffer as the one supplied through context pointer */
253 assert(context_ptr->address == address);
254 dst = (char *)component;
256 len = strlen(child) + 1;
257 memcpy(dst, child, len);
258 dst[len] = 0;
260 if (leaf)
262 lash_debug("%s (leaf)", path);
264 if (parent_ptr == NULL)
266 lash_error("jack conf parameters can't appear in root container");
267 return false;
270 if (!parent_ptr->children_leafs)
272 if (!list_empty(&parent_ptr->children))
274 lash_error("jack conf parameters cant be mixed with containers at same hierarchy level");
275 return false;
278 parent_ptr->children_leafs = true;
281 if (!jack_conf_parameter_create(&parameter_ptr, child))
283 lash_error("jack_conf_parameter_create() failed");
284 return false;
287 if (!jack_proxy_get_parameter_value(context_ptr->address, &is_set, &parameter_ptr->parameter))
289 lash_error("cannot get value of %s", path);
290 return false;
293 if (is_set)
295 switch (parameter_ptr->parameter.type)
297 case jack_boolean:
298 lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false");
299 break;
300 case jack_string:
301 lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string);
302 break;
303 case jack_byte:
304 lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
305 break;
306 case jack_uint32:
307 lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32);
308 break;
309 case jack_int32:
310 lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32);
311 break;
312 default:
313 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
314 jack_conf_parameter_destroy(parameter_ptr);
315 return false;
318 parameter_ptr->parent_ptr = parent_ptr;
319 memcpy(parameter_ptr->address, context_ptr->address, JACK_CONF_MAX_ADDRESS_SIZE);
320 list_add_tail(&parameter_ptr->siblings, &parent_ptr->children);
321 list_add_tail(&parameter_ptr->leaves, &context_ptr->studio_ptr->jack_params);
323 else
325 jack_conf_parameter_destroy(parameter_ptr);
328 else
330 lash_debug("%s (container)", path);
332 if (parent_ptr != NULL && parent_ptr->children_leafs)
334 lash_error("jack conf containers cant be mixed with parameters at same hierarchy level");
335 return false;
338 if (!jack_conf_container_create(&container_ptr, child))
340 lash_error("jack_conf_container_create() failed");
341 return false;
344 container_ptr->parent_ptr = parent_ptr;
346 if (parent_ptr == NULL)
348 list_add_tail(&container_ptr->siblings, &context_ptr->studio_ptr->jack_conf);
350 else
352 list_add_tail(&container_ptr->siblings, &parent_ptr->children);
355 context_ptr->parent_ptr = container_ptr;
357 if (!jack_proxy_read_conf_container(context_ptr->address, context, conf_callback))
359 lash_error("cannot read container %s", path);
360 return false;
363 context_ptr->parent_ptr = parent_ptr;
366 *dst = 0;
368 return true;
371 #undef context_ptr
373 bool
374 studio_create(
375 studio_handle * studio_handle_ptr)
377 struct studio * studio_ptr;
379 lash_info("studio object construct");
381 studio_ptr = malloc(sizeof(struct studio));
382 if (studio_ptr == NULL)
384 lash_error("malloc() failed to allocate struct studio");
385 return false;
388 INIT_LIST_HEAD(&studio_ptr->all_connections);
389 INIT_LIST_HEAD(&studio_ptr->all_ports);
390 INIT_LIST_HEAD(&studio_ptr->all_clients);
391 INIT_LIST_HEAD(&studio_ptr->jack_connections);
392 INIT_LIST_HEAD(&studio_ptr->jack_ports);
393 INIT_LIST_HEAD(&studio_ptr->jack_clients);
394 INIT_LIST_HEAD(&studio_ptr->rooms);
395 INIT_LIST_HEAD(&studio_ptr->clients);
396 INIT_LIST_HEAD(&studio_ptr->ports);
398 studio_ptr->modified = false;
399 studio_ptr->persisted = false;
400 studio_ptr->jack_conf_stable = false;
402 INIT_LIST_HEAD(&studio_ptr->jack_conf);
403 INIT_LIST_HEAD(&studio_ptr->jack_params);
405 studio_ptr->dbus_object = NULL;
407 *studio_handle_ptr = (studio_handle)studio_ptr;
409 return true;
412 #define studio_ptr ((struct studio *)studio)
414 void
415 studio_destroy(
416 studio_handle studio)
418 struct list_head * node_ptr;
420 if (studio_ptr->dbus_object != NULL)
422 object_path_destroy(g_dbus_connection, studio_ptr->dbus_object);
425 while (!list_empty(&studio_ptr->jack_conf))
427 node_ptr = studio_ptr->jack_conf.next;
428 list_del(node_ptr);
429 jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings));
432 free(studio_ptr);
433 lash_info("studio object destroy");
436 bool
437 studio_activate(
438 studio_handle studio)
440 object_path_t * object;
442 object = object_path_new(DBUS_BASE_PATH "/Studio", NULL, 0, NULL);
443 if (object == NULL)
445 lash_error("object_path_new() failed");
446 return false;
449 if (!object_path_register(g_dbus_connection, object))
451 lash_error("object_path_register() failed");
452 object_path_destroy(g_dbus_connection, object);
453 return false;
456 lash_info("Studio D-Bus object created.");
458 studio_ptr->dbus_object = object;
460 return true;
463 bool
464 studio_is_persisted(
465 studio_handle studio)
467 return studio_ptr->persisted;
470 bool
471 studio_save(
472 studio_handle studio,
473 const char * file_path)
475 struct list_head * node_ptr;
476 struct jack_conf_parameter * parameter_ptr;
477 char path[JACK_CONF_MAX_ADDRESS_SIZE * 3]; /* encode each char in three bytes (percent encoding) */
478 const char * src;
479 char * dst;
480 static char hex_digits[] = "0123456789ABCDEF";
482 lash_info("saving studio...");
484 list_for_each(node_ptr, &studio_ptr->jack_params)
486 parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves);
488 /* compose the parameter path, percent-encode "bad" chars */
489 src = parameter_ptr->address;
490 dst = path;
493 *dst++ = '/';
494 while (*src != 0)
496 switch (*src)
498 case '/': /* used as separator for address components */
499 case '<': /* invalid attribute value char (XML spec) */
500 case '&': /* invalid attribute value char (XML spec) */
501 case '"': /* we store attribute values in double quotes - invalid attribute value char (XML spec) */
502 case '%':
503 dst[0] = '%';
504 dst[1] = hex_digits[*src >> 4];
505 dst[2] = hex_digits[*src & 0x0F];
506 dst += 3;
507 src++;
508 break;
509 default:
510 *dst++ = *src++;
513 src++;
515 while (*src != 0);
516 *dst = 0;
518 switch (parameter_ptr->parameter.type)
520 case jack_boolean:
521 lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false");
522 break;
523 case jack_string:
524 lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string);
525 break;
526 case jack_byte:
527 lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
528 break;
529 case jack_uint32:
530 lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32);
531 break;
532 case jack_int32:
533 lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32);
534 break;
535 default:
536 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
537 return false;
541 return false; /* not implemented yet */
544 bool
545 studio_load(
546 studio_handle studio,
547 const char * file_path)
549 return false; /* not implemented yet */
552 #undef studio_ptr
554 bool
555 studio_fetch_jack_settings(
556 studio_handle studio)
558 struct conf_callback_context context;
560 context.address[0] = 0;
561 context.studio_ptr = (struct studio *)studio;
562 context.container_ptr = &context.studio_ptr->jack_conf;
563 context.parent_ptr = NULL;
565 if (!jack_proxy_read_conf_container(context.address, &context, conf_callback))
567 lash_error("jack_proxy_read_conf_container() failed.");
568 return false;
571 return true;