GNUmakefile: fix jack2dbus build
[jackdbus.git] / dbus / params.c
blob5acbe19b8b76d594d65a6f66505c6041cd4e455a
1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
2 /*
3 Copyright (C) 2011 Nedko Arnaudov
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Parameter addresses:
23 * "engine"
24 * "engine", "driver"
25 * "engine", "realtime"
26 * "engine", ...more engine parameters
28 * "driver", "device"
29 * "driver", ...more driver parameters
31 * "drivers", "alsa", "device"
32 * "drivers", "alsa", ...more alsa driver parameters
34 * "drivers", ...more drivers
36 * "internals", "netmanager", "multicast_ip"
37 * "internals", "netmanager", ...more netmanager parameters
39 * "internals", ...more internals
43 #include <stdbool.h>
44 #include <string.h>
45 #include <assert.h>
46 #include <dbus/dbus.h>
48 #include "params.h"
49 #include "controller_internal.h"
51 #define PTNODE_ENGINE "engine"
52 #define PTNODE_DRIVER "driver"
53 #define PTNODE_DRIVERS "drivers"
54 #define PTNODE_INTERNALS "internals"
56 struct jack_parameter_container
58 struct list_head siblings;
59 char * name;
60 struct jack_parameter_container * symlink;
61 bool leaf;
62 struct list_head children;
63 void * obj;
66 struct jack_params
68 jackctl_server_t * server;
69 struct jack_parameter_container root;
70 struct list_head * drivers_ptr;
71 uint32_t drivers_count;
72 struct jack_parameter_container * driver_ptr;
73 bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */
76 static bool controlapi_parameter_is_set(void * obj)
78 return jackctl_parameter_is_set((jackctl_parameter_t *)obj);
81 static bool controlapi_parameter_reset(void * obj)
83 return jackctl_parameter_reset((jackctl_parameter_t *)obj);
86 union jackctl_parameter_value controlapi_parameter_get_value(void * obj)
88 return jackctl_parameter_get_value((jackctl_parameter_t *)obj);
91 bool controlapi_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
93 return jackctl_parameter_set_value((jackctl_parameter_t *)obj, value_ptr);
96 union jackctl_parameter_value controlapi_parameter_get_default_value(void * obj)
98 return jackctl_parameter_get_default_value((jackctl_parameter_t *)obj);
101 static struct jack_parameter_container * create_container(struct list_head * parent_list_ptr, const char * name)
103 struct jack_parameter_container * container_ptr;
105 container_ptr = malloc(sizeof(struct jack_parameter_container));
106 if (container_ptr == NULL)
108 jack_error("Ran out of memory trying to allocate struct jack_parameter_container");
109 goto fail;
112 container_ptr->name = strdup(name);
113 if (container_ptr->name == NULL)
115 jack_error("Ran out of memory trying to strdup parameter container name");
116 goto free;
119 container_ptr->leaf = false;
120 container_ptr->symlink = NULL;
121 container_ptr->obj = NULL;
122 INIT_LIST_HEAD(&container_ptr->children);
123 list_add_tail(&container_ptr->siblings, parent_list_ptr);
125 return container_ptr;
127 free:
128 free(container_ptr);
129 fail:
130 return NULL;
133 static bool add_controlapi_param(struct list_head * parent_list_ptr, jackctl_parameter_t * param)
135 struct jack_parameter * param_ptr;
136 uint32_t i;
138 param_ptr = malloc(sizeof(struct jack_parameter));
139 if (param_ptr == NULL)
141 jack_error("Ran out of memory trying to allocate struct jack_parameter");
142 goto fail;
145 param_ptr->ext = false;
146 param_ptr->obj = param;
147 param_ptr->vtable.is_set = controlapi_parameter_is_set;
148 param_ptr->vtable.reset = controlapi_parameter_reset;
149 param_ptr->vtable.get_value = controlapi_parameter_get_value;
150 param_ptr->vtable.set_value = controlapi_parameter_set_value;
151 param_ptr->vtable.get_default_value = controlapi_parameter_get_default_value;
153 param_ptr->type = jackctl_parameter_get_type(param);
154 param_ptr->name = jackctl_parameter_get_name(param);
155 param_ptr->short_decr = jackctl_parameter_get_short_description(param);
156 param_ptr->long_descr = jackctl_parameter_get_long_description(param);
158 if (jackctl_parameter_has_range_constraint(param))
160 param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
161 param_ptr->constraint_range = true;
162 jackctl_parameter_get_range_constraint(param, &param_ptr->constraint.range.min, &param_ptr->constraint.range.max);
164 else if (jackctl_parameter_has_enum_constraint(param))
166 param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
167 param_ptr->constraint_range = false;
168 param_ptr->constraint.enumeration.count = jackctl_parameter_get_enum_constraints_count(param);
169 param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * param_ptr->constraint.enumeration.count);
170 if (param_ptr->constraint.enumeration.possible_values_array == NULL)
172 goto free;
175 for (i = 0; i < param_ptr->constraint.enumeration.count; i++)
177 param_ptr->constraint.enumeration.possible_values_array[i].value = jackctl_parameter_get_enum_constraint_value(param, i);
178 param_ptr->constraint.enumeration.possible_values_array[i].short_desc = jackctl_parameter_get_enum_constraint_description(param, i);
181 else
183 param_ptr->constraint_flags = 0;
184 goto add;
187 if (jackctl_parameter_constraint_is_strict(param))
189 param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_STRICT;
192 if (jackctl_parameter_constraint_is_fake_value(param))
194 param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_FAKE_VALUE;
197 add:
198 list_add_tail(&param_ptr->siblings, parent_list_ptr);
199 return true;
201 free:
202 free(param_ptr);
203 fail:
204 return false;
207 static void free_params(struct list_head * parent_list_ptr)
209 struct jack_parameter * param_ptr;
211 while (!list_empty(parent_list_ptr))
213 param_ptr = list_entry(parent_list_ptr->next, struct jack_parameter, siblings);
214 list_del(&param_ptr->siblings);
216 if (param_ptr->ext)
218 continue;
221 if ((param_ptr->constraint_flags & JACK_CONSTRAINT_FLAG_VALID) != 0 &&
222 !param_ptr->constraint_range &&
223 param_ptr->constraint.enumeration.possible_values_array != NULL)
225 free(param_ptr->constraint.enumeration.possible_values_array);
228 free(param_ptr);
232 static void free_containers(struct list_head * parent_list_ptr)
234 struct jack_parameter_container * container_ptr;
236 while (!list_empty(parent_list_ptr))
238 container_ptr = list_entry(parent_list_ptr->next, struct jack_parameter_container, siblings);
239 list_del(&container_ptr->siblings);
241 if (container_ptr->leaf)
243 free_params(&container_ptr->children);
245 else
247 free_containers(&container_ptr->children);
250 free(container_ptr->name);
251 free(container_ptr);
255 static struct jack_parameter_container * find_container(struct jack_parameter_container * parent_ptr, const char * const * address, int max_depth)
257 struct list_head * node_ptr;
258 struct jack_parameter_container * container_ptr;
260 if (max_depth == 0 || *address == NULL)
262 return parent_ptr;
265 if (parent_ptr->leaf)
267 return NULL;
270 if (max_depth > 0)
272 max_depth--;
275 list_for_each(node_ptr, &parent_ptr->children)
277 container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
278 if (strcmp(container_ptr->name, *address) == 0)
280 if (container_ptr->symlink != NULL)
282 container_ptr = container_ptr->symlink;
285 return find_container(container_ptr, address + 1, max_depth);
289 return NULL;
292 static bool init_leaf(struct list_head * parent_list_ptr, const char * name, const JSList * params_list, void * obj)
294 struct jack_parameter_container * container_ptr;
296 container_ptr = create_container(parent_list_ptr, name);
297 if (container_ptr == NULL)
299 return false;
302 container_ptr->leaf = true;
303 container_ptr->obj = obj;
305 while (params_list)
307 if (!add_controlapi_param(&container_ptr->children, params_list->data))
309 return false;
312 params_list = jack_slist_next(params_list);
315 return true;
318 static bool init_engine(struct jack_params * params_ptr)
320 return init_leaf(&params_ptr->root.children, PTNODE_ENGINE, jackctl_server_get_parameters(params_ptr->server), NULL);
323 static bool init_drivers(struct jack_params * params_ptr)
325 const JSList * list;
326 struct jack_parameter_container * container_ptr;
328 container_ptr = create_container(&params_ptr->root.children, PTNODE_DRIVERS);
329 if (container_ptr == NULL)
331 return false;
334 params_ptr->drivers_ptr = &container_ptr->children;
335 params_ptr->drivers_count = 0;
337 list = jackctl_server_get_drivers_list(params_ptr->server);
338 while (list)
340 if (!init_leaf(&container_ptr->children, jackctl_driver_get_name(list->data), jackctl_driver_get_parameters(list->data), list->data))
342 return false;
345 params_ptr->drivers_count++;
347 list = jack_slist_next(list);
350 return true;
353 static bool init_internals(struct jack_params * params_ptr)
355 const JSList * list;
356 struct jack_parameter_container * container_ptr;
358 container_ptr = create_container(&params_ptr->root.children, PTNODE_INTERNALS);
359 if (container_ptr == NULL)
361 return false;
364 list = jackctl_server_get_internals_list(params_ptr->server);
365 while (list)
367 if (!init_leaf(&container_ptr->children, jackctl_internal_get_name(list->data), jackctl_internal_get_parameters(list->data), NULL))
369 return false;
372 list = jack_slist_next(list);
375 return true;
378 static bool init_driver(struct jack_params * params_ptr)
380 struct jack_parameter_container * container_ptr;
382 container_ptr = create_container(&params_ptr->root.children, PTNODE_DRIVER);
383 if (container_ptr == NULL)
385 return false;
388 params_ptr->driver_ptr = container_ptr;
390 return true;
393 #define params_ptr ((struct jack_params *)obj)
395 static bool engine_driver_parameter_is_set(void * obj)
397 return params_ptr->driver_set;
400 static bool engine_driver_parameter_reset(void * obj)
402 if (!jack_params_set_driver(obj, DEFAULT_DRIVER))
404 return false;
407 params_ptr->driver_set = false;
409 return true;
412 union jackctl_parameter_value engine_driver_parameter_get_value(void * obj)
414 union jackctl_parameter_value value;
416 strcpy(value.str, params_ptr->driver_ptr->symlink->name);
418 return value;
421 bool engine_driver_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
423 return jack_params_set_driver(obj, value_ptr->str);
426 union jackctl_parameter_value engine_driver_parameter_get_default_value(void * obj)
428 union jackctl_parameter_value value;
430 strcpy(value.str, DEFAULT_DRIVER);
432 return value;
435 #undef params_ptr
437 static bool add_engine_driver_enum_constraint(void * context, const char * name)
439 strcpy((*((struct jack_parameter_enum **)context))->value.str, name);
440 (*((struct jack_parameter_enum **)context))->short_desc = name;
441 (*((struct jack_parameter_enum **)context))++;
442 return true;
445 static bool init_engine_driver_parameter(struct jack_params * params_ptr)
447 struct jack_parameter * param_ptr;
448 const char * address[PARAM_ADDRESS_SIZE] = {PTNODE_ENGINE, NULL};
449 struct jack_parameter_container * engine_ptr;
450 struct jack_parameter_enum * possible_value;
452 engine_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
453 if (engine_ptr == NULL)
455 return false;
458 param_ptr = malloc(sizeof(struct jack_parameter));
459 if (param_ptr == NULL)
461 jack_error("Ran out of memory trying to allocate struct jack_parameter");
462 goto fail;
465 param_ptr->ext = false;
466 param_ptr->obj = params_ptr;
467 param_ptr->vtable.is_set = engine_driver_parameter_is_set;
468 param_ptr->vtable.reset = engine_driver_parameter_reset;
469 param_ptr->vtable.get_value = engine_driver_parameter_get_value;
470 param_ptr->vtable.set_value = engine_driver_parameter_set_value;
471 param_ptr->vtable.get_default_value = engine_driver_parameter_get_default_value;
473 param_ptr->type = JackParamString;
474 param_ptr->name = "driver";
475 param_ptr->short_decr = "Driver to use";
476 param_ptr->long_descr = "";
478 param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID | JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
479 param_ptr->constraint_range = false;
480 param_ptr->constraint.enumeration.count = params_ptr->drivers_count;
481 param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * params_ptr->drivers_count);
482 if (param_ptr->constraint.enumeration.possible_values_array == NULL)
484 goto free;
487 address[0] = PTNODE_DRIVERS;
488 possible_value = param_ptr->constraint.enumeration.possible_values_array;
489 jack_params_iterate_container((jack_params_handle)params_ptr, address, add_engine_driver_enum_constraint, &possible_value);
491 list_add(&param_ptr->siblings, &engine_ptr->children);
492 return true;
494 free:
495 free(param_ptr);
496 fail:
497 return false;
500 jack_params_handle jack_params_create(jackctl_server_t * server)
502 struct jack_params * params_ptr;
504 params_ptr = malloc(sizeof(struct jack_params));
505 if (params_ptr == NULL)
507 jack_error("Ran out of memory trying to allocate struct jack_params");
508 return NULL;
511 params_ptr->server = server;
512 INIT_LIST_HEAD(&params_ptr->root.children);
513 params_ptr->root.leaf = false;
514 params_ptr->root.name = NULL;
516 if (!init_engine(params_ptr) ||
517 !init_drivers(params_ptr) ||
518 !init_driver(params_ptr) ||
519 !init_engine_driver_parameter(params_ptr) ||
520 !jack_params_set_driver((jack_params_handle)params_ptr, DEFAULT_DRIVER) ||
521 !init_internals(params_ptr))
523 jack_params_destroy((jack_params_handle)params_ptr);
524 return NULL;
527 params_ptr->driver_set = false;
529 assert(strcmp(params_ptr->driver_ptr->symlink->name, DEFAULT_DRIVER) == 0);
531 return (jack_params_handle)params_ptr;
534 #define params_ptr ((struct jack_params *)params)
536 void jack_params_destroy(jack_params_handle params)
538 free_containers(&params_ptr->root.children);
539 free(params);
542 bool jack_params_set_driver(jack_params_handle params, const char * name)
544 struct list_head * node_ptr;
545 struct jack_parameter_container * container_ptr;
547 list_for_each(node_ptr, params_ptr->drivers_ptr)
549 container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
550 if (strcmp(container_ptr->name, name) == 0)
552 params_ptr->driver_ptr->symlink = container_ptr;
553 params_ptr->driver_set = true;
554 return true;
558 return false;
561 jackctl_driver_t * jack_params_get_driver(jack_params_handle params)
563 return params_ptr->driver_ptr->symlink->obj;
566 bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf)
568 struct jack_parameter_container * container_ptr;
570 container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
571 if (container_ptr == NULL)
573 return false;
576 if (want_leaf && !container_ptr->leaf)
578 return false;
581 return true;
584 bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address)
586 struct jack_parameter_container * container_ptr;
588 container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
589 if (container_ptr == NULL)
591 assert(false);
592 return false;
595 return container_ptr->leaf;
598 bool
599 jack_params_iterate_container(
600 jack_params_handle params,
601 const char * const * address,
602 bool (* callback)(void * context, const char * name),
603 void * context)
605 struct jack_parameter_container * container_ptr;
606 struct list_head * node_ptr;
607 const char * name;
609 container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
610 if (container_ptr == NULL)
612 assert(false);
613 return true;
616 list_for_each(node_ptr, &container_ptr->children)
618 if (container_ptr->leaf)
620 name = list_entry(node_ptr, struct jack_parameter, siblings)->name;
622 else
624 name = list_entry(node_ptr, struct jack_parameter_container, siblings)->name;
627 if (!callback(context, name))
629 return false;
633 return true;
636 bool
637 jack_params_iterate_params(
638 jack_params_handle params,
639 const char * const * address,
640 bool (* callback)(void * context, const struct jack_parameter * param_ptr),
641 void * context)
643 struct jack_parameter_container * container_ptr;
644 struct list_head * node_ptr;
645 struct jack_parameter * param_ptr;
647 container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
648 if (container_ptr == NULL || !container_ptr->leaf)
650 assert(false);
651 return true;
654 list_for_each(node_ptr, &container_ptr->children)
656 param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
657 if (!callback(context, param_ptr))
659 return false;
663 return true;
666 const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address)
668 int depth;
669 struct jack_parameter_container * container_ptr;
670 struct list_head * node_ptr;
671 struct jack_parameter * param_ptr;
673 for (depth = 0; depth < PARAM_ADDRESS_SIZE; depth++)
675 if (address[depth] == NULL)
677 break;
681 depth--;
683 container_ptr = find_container(&params_ptr->root, address, depth);
684 if (container_ptr == NULL || !container_ptr->leaf)
686 return NULL;
689 list_for_each(node_ptr, &container_ptr->children)
691 param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
692 if (strcmp(param_ptr->name, address[depth]) == 0)
694 return param_ptr;
698 return NULL;
701 void jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr)
703 struct jack_parameter_container * container_ptr;
705 container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
706 if (container_ptr == NULL || !container_ptr->leaf)
708 assert(false);
709 return;
712 param_ptr->ext = true;
714 if (end)
716 list_add_tail(&param_ptr->siblings, &container_ptr->children);
718 else
720 list_add(&param_ptr->siblings, &container_ptr->children);
723 return;
726 #undef params_ptr