1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
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:
25 * "engine", "realtime"
26 * "engine", ...more engine parameters
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
46 #include <dbus/dbus.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
;
60 struct jack_parameter_container
* symlink
;
62 struct list_head children
;
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");
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");
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
;
133 static bool add_controlapi_param(struct list_head
* parent_list_ptr
, jackctl_parameter_t
* param
)
135 struct jack_parameter
* param_ptr
;
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");
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
, ¶m_ptr
->constraint
.range
.min
, ¶m_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
)
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
);
183 param_ptr
->constraint_flags
= 0;
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
;
198 list_add_tail(¶m_ptr
->siblings
, parent_list_ptr
);
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(¶m_ptr
->siblings
);
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
);
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
);
247 free_containers(&container_ptr
->children
);
250 free(container_ptr
->name
);
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
)
265 if (parent_ptr
->leaf
)
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
);
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
)
302 container_ptr
->leaf
= true;
303 container_ptr
->obj
= obj
;
307 if (!add_controlapi_param(&container_ptr
->children
, params_list
->data
))
312 params_list
= jack_slist_next(params_list
);
318 static bool init_engine(struct jack_params
* params_ptr
)
320 return init_leaf(¶ms_ptr
->root
.children
, PTNODE_ENGINE
, jackctl_server_get_parameters(params_ptr
->server
), NULL
);
323 static bool init_drivers(struct jack_params
* params_ptr
)
326 struct jack_parameter_container
* container_ptr
;
328 container_ptr
= create_container(¶ms_ptr
->root
.children
, PTNODE_DRIVERS
);
329 if (container_ptr
== NULL
)
334 params_ptr
->drivers_ptr
= &container_ptr
->children
;
335 params_ptr
->drivers_count
= 0;
337 list
= jackctl_server_get_drivers_list(params_ptr
->server
);
340 if (!init_leaf(&container_ptr
->children
, jackctl_driver_get_name(list
->data
), jackctl_driver_get_parameters(list
->data
), list
->data
))
345 params_ptr
->drivers_count
++;
347 list
= jack_slist_next(list
);
353 static bool init_internals(struct jack_params
* params_ptr
)
356 struct jack_parameter_container
* container_ptr
;
358 container_ptr
= create_container(¶ms_ptr
->root
.children
, PTNODE_INTERNALS
);
359 if (container_ptr
== NULL
)
364 list
= jackctl_server_get_internals_list(params_ptr
->server
);
367 if (!init_leaf(&container_ptr
->children
, jackctl_internal_get_name(list
->data
), jackctl_internal_get_parameters(list
->data
), NULL
))
372 list
= jack_slist_next(list
);
378 static bool init_driver(struct jack_params
* params_ptr
)
380 struct jack_parameter_container
* container_ptr
;
382 container_ptr
= create_container(¶ms_ptr
->root
.children
, PTNODE_DRIVER
);
383 if (container_ptr
== NULL
)
388 params_ptr
->driver_ptr
= container_ptr
;
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
))
407 params_ptr
->driver_set
= false;
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
);
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
);
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
))++;
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(¶ms_ptr
->root
, address
, PARAM_ADDRESS_SIZE
);
453 if (engine_ptr
== NULL
)
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");
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
)
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(¶m_ptr
->siblings
, &engine_ptr
->children
);
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");
511 params_ptr
->server
= server
;
512 INIT_LIST_HEAD(¶ms_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
);
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(¶ms_ptr
->root
.children
);
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;
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(¶ms_ptr
->root
, address
, PARAM_ADDRESS_SIZE
);
571 if (container_ptr
== NULL
)
576 if (want_leaf
&& !container_ptr
->leaf
)
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(¶ms_ptr
->root
, address
, PARAM_ADDRESS_SIZE
);
589 if (container_ptr
== NULL
)
595 return container_ptr
->leaf
;
599 jack_params_iterate_container(
600 jack_params_handle params
,
601 const char * const * address
,
602 bool (* callback
)(void * context
, const char * name
),
605 struct jack_parameter_container
* container_ptr
;
606 struct list_head
* node_ptr
;
609 container_ptr
= find_container(¶ms_ptr
->root
, address
, PARAM_ADDRESS_SIZE
);
610 if (container_ptr
== NULL
)
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
;
624 name
= list_entry(node_ptr
, struct jack_parameter_container
, siblings
)->name
;
627 if (!callback(context
, name
))
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
),
643 struct jack_parameter_container
* container_ptr
;
644 struct list_head
* node_ptr
;
645 struct jack_parameter
* param_ptr
;
647 container_ptr
= find_container(¶ms_ptr
->root
, address
, PARAM_ADDRESS_SIZE
);
648 if (container_ptr
== NULL
|| !container_ptr
->leaf
)
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
))
666 const struct jack_parameter
* jack_params_get_parameter(jack_params_handle params
, const char * const * address
)
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
)
683 container_ptr
= find_container(¶ms_ptr
->root
, address
, depth
);
684 if (container_ptr
== NULL
|| !container_ptr
->leaf
)
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)
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(¶ms_ptr
->root
, address
, PARAM_ADDRESS_SIZE
);
706 if (container_ptr
== NULL
|| !container_ptr
->leaf
)
712 param_ptr
->ext
= true;
716 list_add_tail(¶m_ptr
->siblings
, &container_ptr
->children
);
720 list_add(¶m_ptr
->siblings
, &container_ptr
->children
);