Add missing header text
[ladish.git] / daemon / load.c
blob77e34feae1389b60280b85613e5a201f848f72fc
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009,2010,2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation for the load helper functions
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 "load.h"
28 #include "limits.h"
29 #include "studio.h"
30 #include "../proxies/jmcore_proxy.h"
32 void ladish_dump_element_stack(struct ladish_parse_context * context_ptr)
34 signed int depth;
35 const char * descr;
37 log_info("depth=%d", context_ptr->depth);
39 for (depth = context_ptr->depth; depth >= 0; depth--)
41 switch (context_ptr->element[depth])
43 case PARSE_CONTEXT_ROOT:
44 descr = "root";
45 break;
46 case PARSE_CONTEXT_STUDIO:
47 descr = "studio";
48 break;
49 case PARSE_CONTEXT_JACK:
50 descr = "jack";
51 break;
52 case PARSE_CONTEXT_CONF:
53 descr = "conf";
54 break;
55 case PARSE_CONTEXT_PARAMETER:
56 descr = "parameter";
57 break;
58 case PARSE_CONTEXT_CLIENTS:
59 descr = "clients";
60 break;
61 case PARSE_CONTEXT_CLIENT:
62 descr = "client";
63 break;
64 case PARSE_CONTEXT_PORTS:
65 descr = "ports";
66 break;
67 case PARSE_CONTEXT_PORT:
68 descr = "port";
69 break;
70 case PARSE_CONTEXT_DICT:
71 descr = "dict";
72 break;
73 case PARSE_CONTEXT_KEY:
74 descr = "key";
75 break;
76 case PARSE_CONTEXT_CONNECTIONS:
77 descr = "connections";
78 break;
79 case PARSE_CONTEXT_CONNECTION:
80 descr = "connection";
81 break;
82 case PARSE_CONTEXT_APPLICATIONS:
83 descr = "applications";
84 break;
85 case PARSE_CONTEXT_APPLICATION:
86 descr = "application";
87 break;
88 case PARSE_CONTEXT_ROOMS:
89 descr = "rooms";
90 break;
91 case PARSE_CONTEXT_ROOM:
92 descr = "room";
93 break;
94 case PARSE_CONTEXT_PROJECT:
95 descr = "project";
96 break;
97 default:
98 descr = "?";
101 log_info("%d - %u (%s)", depth, context_ptr->element[depth], descr);
105 static const char * get_string_attribute_internal(const char * const * attr, const char * key, bool optional)
107 while (attr[0] != NULL)
109 ASSERT(attr[1] != NULL);
110 if (strcmp(attr[0], key) == 0)
112 return attr[1];
114 attr += 2;
117 if (!optional)
119 log_error("attribute \"%s\" is missing", key);
122 return NULL;
125 const char * ladish_get_string_attribute(const char * const * attr, const char * key)
127 return get_string_attribute_internal(attr, key, false);
130 const char * ladish_get_uuid_attribute(const char * const * attr, const char * key, uuid_t uuid, bool optional)
132 const char * value;
134 value = get_string_attribute_internal(attr, key, optional);
135 if (value == NULL)
137 return NULL;
140 if (uuid_parse(value, uuid) != 0)
142 log_error("cannot parse uuid \"%s\"", value);
143 return NULL;
146 return value;
149 const char * ladish_get_bool_attribute(const char * const * attr, const char * key, bool * bool_value_ptr)
151 const char * value_str;
153 value_str = ladish_get_string_attribute(attr, key);
154 if (value_str == NULL)
156 return NULL;
159 if (strcmp(value_str, "true") == 0)
161 *bool_value_ptr = true;
162 return value_str;
165 if (strcmp(value_str, "false") == 0)
167 *bool_value_ptr = false;
168 return value_str;
171 log_error("boolean XML attribute has value of \"%s\" but only \"true\" and \"false\" are valid", value_str);
172 return NULL;
175 const char * ladish_get_byte_attribute(const char * const * attr, const char * key, uint8_t * byte_value_ptr)
177 const char * value_str;
178 long int li_value;
179 char * end_ptr;
181 value_str = ladish_get_string_attribute(attr, key);
182 if (value_str == NULL)
184 return NULL;
187 errno = 0; /* To distinguish success/failure after call */
188 li_value = strtol(value_str, &end_ptr, 10);
189 if ((errno == ERANGE && (li_value == LONG_MAX || li_value == LONG_MIN)) || (errno != 0 && li_value == 0) || end_ptr == value_str)
191 log_error("value '%s' of attribute '%s' is not valid integer.", value_str, key);
192 return NULL;
195 if (li_value < 0 || li_value > 255)
197 log_error("value '%s' of attribute '%s' is not valid uint8.", value_str, key);
198 return NULL;
201 *byte_value_ptr = (uint8_t)li_value;
202 return value_str;
205 bool
206 ladish_get_name_and_uuid_attributes(
207 const char * element_description,
208 const char * const * attr,
209 const char ** name_str_ptr,
210 const char ** uuid_str_ptr,
211 uuid_t uuid)
213 const char * name_str;
214 const char * uuid_str;
216 name_str = ladish_get_string_attribute(attr, "name");
217 if (name_str == NULL)
219 log_error("%s \"name\" attribute is not available", element_description);
220 return false;
223 uuid_str = ladish_get_uuid_attribute(attr, "uuid", uuid, false);
224 if (uuid_str == NULL)
226 log_error("%s \"uuid\" attribute is not available. name=\"%s\"", element_description, name_str);
227 return false;
230 *name_str_ptr = name_str;
231 *uuid_str_ptr = uuid_str;
232 return true;
235 bool
236 ladish_parse_port_type_and_direction_attributes(
237 const char * element_description,
238 const char * const * attr,
239 uint32_t * type_ptr,
240 uint32_t * flags_ptr)
242 const char * type_str;
243 const char * direction_str;
245 type_str = ladish_get_string_attribute(attr, "type");
246 if (type_str == NULL)
248 log_error("%s \"type\" attribute is not available", element_description);
249 return false;
252 direction_str = ladish_get_string_attribute(attr, "direction");
253 if (direction_str == NULL)
255 log_error("%s \"direction\" attribute is not available", element_description);
256 return false;
259 if (strcmp(type_str, "midi") == 0)
261 *type_ptr = JACKDBUS_PORT_TYPE_MIDI;
263 else if (strcmp(type_str, "audio") == 0)
265 *type_ptr = JACKDBUS_PORT_TYPE_AUDIO;
267 else
269 log_error("%s \"type\" attribute contains unknown value \"%s\"", element_description, type_str);
270 return false;
273 if (strcmp(direction_str, "playback") == 0)
275 *flags_ptr = 0;
276 JACKDBUS_PORT_SET_INPUT(*flags_ptr);
278 else if (strcmp(direction_str, "capture") == 0)
280 *flags_ptr = 0;
281 JACKDBUS_PORT_SET_OUTPUT(*flags_ptr);
283 else
285 log_error("%s \"direction\" attribute contains unknown value \"%s\"", element_description, direction_str);
286 return false;
289 return true;
292 struct interlink_context
294 ladish_graph_handle vgraph;
295 ladish_app_supervisor_handle app_supervisor;
298 #define ctx_ptr ((struct interlink_context *)context)
300 static
301 bool
302 interlink_client(
303 void * context,
304 ladish_graph_handle UNUSED(graph_handle),
305 bool UNUSED(hidden),
306 ladish_client_handle jclient,
307 const char * name,
308 void ** UNUSED(client_iteration_context_ptr_ptr))
310 uuid_t app_uuid;
311 uuid_t vclient_app_uuid;
312 uuid_t vclient_uuid;
313 ladish_client_handle vclient;
314 pid_t pid;
315 ladish_app_handle app;
316 bool interlinked;
317 bool jmcore;
318 ladish_graph_handle vgraph;
320 ASSERT(ctx_ptr->vgraph != NULL);
321 vgraph = ladish_client_get_vgraph(jclient);
322 if (vgraph != NULL && ctx_ptr->vgraph != vgraph)
324 /* skip clients of different vgraphs */
325 return true;
328 if (strcmp(name, "system") == 0)
330 return true;
333 interlinked = ladish_client_get_interlink(jclient, vclient_uuid);
335 if (ladish_client_has_app(jclient))
337 ASSERT(interlinked); /* jclient has app associated but is not interlinked */
338 return true;
340 else if (interlinked)
342 /* jclient has no app associated but is interlinked */
343 /* this can happen if there is an external app (presumably in a different vgraph) */
344 ASSERT_NO_PASS; /* if vgraph is different, then we should have skipped the client earlier */
345 return true;
347 ASSERT(!interlinked);
349 /* XXX: why this is is here is a mystery. interlink is supposed to be called just after load so pid will always be 0 */
350 pid = ladish_client_get_pid(jclient);
351 jmcore = pid != 0 && pid == jmcore_proxy_get_pid_cached();
352 if (jmcore)
354 return true;
357 if (ladish_virtualizer_is_a2j_client(jclient))
359 return true;
362 app = ladish_app_supervisor_find_app_by_name(ctx_ptr->app_supervisor, name);
363 if (app == NULL)
365 log_info("JACK client \"%s\" not found in app supervisor", name);
366 return true;
369 vclient = ladish_graph_find_client_by_name(ctx_ptr->vgraph, name, false);
370 if (vclient == NULL)
372 log_error("JACK client '%s' has no vclient associated", name);
373 return true;
376 log_info("Interlinking clients of app '%s'", name);
377 ladish_client_interlink(jclient, vclient);
379 ladish_app_get_uuid(app, app_uuid);
380 if (ladish_client_get_app(vclient, vclient_app_uuid))
382 if (uuid_compare(app_uuid, vclient_app_uuid) != 0)
384 log_error("vclient of app '%s' already has a different app uuid", name);
387 else
389 log_info("associating vclient with app '%s'", name);
390 ladish_client_set_app(vclient, app_uuid);
393 ladish_client_set_app(jclient, app_uuid);
394 ladish_client_set_vgraph(jclient, ctx_ptr->vgraph);
396 return true;
399 bool
400 interlink_port(
401 void * UNUSED(context),
402 ladish_graph_handle UNUSED(graph_handle),
403 bool UNUSED(hidden),
404 void * UNUSED(client_iteration_context_ptr),
405 ladish_client_handle client_handle,
406 const char * UNUSED(client_name),
407 ladish_port_handle port_handle,
408 const char * UNUSED(port_name),
409 uint32_t UNUSED(port_type),
410 uint32_t UNUSED(port_flags))
412 uuid_t app_uuid;
414 if (ladish_client_get_app(client_handle, app_uuid))
416 ladish_port_set_app(port_handle, app_uuid);
419 return true;
422 void ladish_interlink(ladish_graph_handle vgraph, ladish_app_supervisor_handle app_supervisor)
424 struct interlink_context ctx;
426 ctx.vgraph = vgraph;
427 ctx.app_supervisor = app_supervisor;
429 ladish_graph_iterate_nodes(ladish_studio_get_jack_graph(), &ctx, interlink_client, NULL, NULL);
430 ladish_graph_iterate_nodes(vgraph, &ctx, NULL, interlink_port, NULL);