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 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.
28 #include "../jack_proxy.h"
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 */
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
;
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
;
82 jack_conf_container_create(
83 struct jack_conf_container
** container_ptr_ptr
,
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");
95 container_ptr
->name
= strdup(name
);
96 if (container_ptr
->name
== NULL
)
98 lash_error("strdup() failed to duplicate \"%s\"", name
);
102 INIT_LIST_HEAD(&container_ptr
->children
);
103 container_ptr
->children_leafs
= false;
105 *container_ptr_ptr
= container_ptr
;
116 jack_conf_parameter_create(
117 struct jack_conf_parameter
** parameter_ptr_ptr
,
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");
129 parameter_ptr
->name
= strdup(name
);
130 if (parameter_ptr
->name
== NULL
)
132 lash_error("strdup() failed to duplicate \"%s\"", name
);
136 *parameter_ptr_ptr
= parameter_ptr
;
147 jack_conf_parameter_destroy(
148 struct jack_conf_parameter
* parameter_ptr
)
151 lash_info("jack_conf_parameter destroy");
153 switch (parameter_ptr
->parameter
.type
)
156 lash_info("%s value is %s (boolean)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
159 lash_info("%s value is %s (string)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.string
);
162 lash_info("%s value is %u/%c (byte/char)", parameter_ptr
->name
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
165 lash_info("%s value is %u (uint32)", parameter_ptr
->name
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
168 lash_info("%s value is %u (int32)", parameter_ptr
->name
, (signed int)parameter_ptr
->parameter
.value
.int32
);
171 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, parameter_ptr
->name
);
176 if (parameter_ptr
->parameter
.type
== jack_string
)
178 free(parameter_ptr
->parameter
.value
.string
);
181 free(parameter_ptr
->name
);
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
;
199 jack_conf_container_destroy(list_entry(node_ptr
, struct jack_conf_container
, siblings
));
204 while (!list_empty(&container_ptr
->children
))
206 node_ptr
= container_ptr
->children
.next
;
208 jack_conf_parameter_destroy(list_entry(node_ptr
, struct jack_conf_parameter
, siblings
));
212 free(container_ptr
->name
);
216 #define context_ptr ((struct conf_callback_context *)context)
223 const char * address
,
226 char path
[JACK_CONF_MAX_ADDRESS_SIZE
];
227 const char * component
;
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
;
241 while (*component
!= 0)
243 len
= strlen(component
);
244 memcpy(dst
, component
, len
);
246 component
+= len
+ 1;
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
);
262 lash_debug("%s (leaf)", path
);
264 if (parent_ptr
== NULL
)
266 lash_error("jack conf parameters can't appear in root container");
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");
278 parent_ptr
->children_leafs
= true;
281 if (!jack_conf_parameter_create(¶meter_ptr
, child
))
283 lash_error("jack_conf_parameter_create() failed");
287 if (!jack_proxy_get_parameter_value(context_ptr
->address
, &is_set
, ¶meter_ptr
->parameter
))
289 lash_error("cannot get value of %s", path
);
295 switch (parameter_ptr
->parameter
.type
)
298 lash_info("%s value is %s (boolean)", path
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
301 lash_info("%s value is %s (string)", path
, parameter_ptr
->parameter
.value
.string
);
304 lash_info("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
307 lash_info("%s value is %u (uint32)", path
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
310 lash_info("%s value is %u (int32)", path
, (signed int)parameter_ptr
->parameter
.value
.int32
);
313 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
314 jack_conf_parameter_destroy(parameter_ptr
);
318 parameter_ptr
->parent_ptr
= parent_ptr
;
319 memcpy(parameter_ptr
->address
, context_ptr
->address
, JACK_CONF_MAX_ADDRESS_SIZE
);
320 list_add_tail(¶meter_ptr
->siblings
, &parent_ptr
->children
);
321 list_add_tail(¶meter_ptr
->leaves
, &context_ptr
->studio_ptr
->jack_params
);
325 jack_conf_parameter_destroy(parameter_ptr
);
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");
338 if (!jack_conf_container_create(&container_ptr
, child
))
340 lash_error("jack_conf_container_create() failed");
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
);
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
);
363 context_ptr
->parent_ptr
= parent_ptr
;
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");
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
;
412 #define studio_ptr ((struct studio *)studio)
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
;
429 jack_conf_container_destroy(list_entry(node_ptr
, struct jack_conf_container
, siblings
));
433 lash_info("studio object destroy");
438 studio_handle studio
)
440 object_path_t
* object
;
442 object
= object_path_new(DBUS_BASE_PATH
"/Studio", NULL
, 0, NULL
);
445 lash_error("object_path_new() failed");
449 if (!object_path_register(g_dbus_connection
, object
))
451 lash_error("object_path_register() failed");
452 object_path_destroy(g_dbus_connection
, object
);
456 lash_info("Studio D-Bus object created.");
458 studio_ptr
->dbus_object
= object
;
465 studio_handle studio
)
467 return studio_ptr
->persisted
;
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) */
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
;
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) */
504 dst
[1] = hex_digits
[*src
>> 4];
505 dst
[2] = hex_digits
[*src
& 0x0F];
518 switch (parameter_ptr
->parameter
.type
)
521 lash_info("%s value is %s (boolean)", path
, parameter_ptr
->parameter
.value
.boolean
? "true" : "false");
524 lash_info("%s value is %s (string)", path
, parameter_ptr
->parameter
.value
.string
);
527 lash_info("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
530 lash_info("%s value is %u (uint32)", path
, (unsigned int)parameter_ptr
->parameter
.value
.uint32
);
533 lash_info("%s value is %u (int32)", path
, (signed int)parameter_ptr
->parameter
.value
.int32
);
536 lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
541 return false; /* not implemented yet */
546 studio_handle studio
,
547 const char * file_path
)
549 return false; /* not implemented yet */
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.");