helpers for handling dbus signals
[ladish.git] / jack_proxy.c
blobf50432abdcb0115abbbf9b196fb3e0ea4f48d50f
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 helper functionality for accessing JACK through D-Bus
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 //#define LADISH_DEBUG
29 #include "common.h"
30 #include "jack_proxy.h"
31 #include "dbus/helpers.h"
32 #include "dbus_constants.h"
34 jack_proxy_callback_server_started g_on_server_started;
35 jack_proxy_callback_server_stopped g_on_server_stopped;
36 jack_proxy_callback_server_appeared g_on_server_appeared;
37 jack_proxy_callback_server_disappeared g_on_server_disappeared;
39 static void on_jack_server_started(void * context, DBusMessage * message_ptr)
41 log_debug("JACK server start signal received.");
42 if (g_on_server_started != NULL)
44 g_on_server_started();
48 static void on_jack_server_stopped(void * context, DBusMessage * message_ptr)
50 log_debug("JACK server stop signal received.");
51 if (g_on_server_stopped != NULL)
53 g_on_server_stopped();
57 static void on_jack_life_status_changed(bool appeared)
59 if (appeared)
61 log_debug("JACK serivce appeared");
62 if (g_on_server_appeared != NULL)
64 g_on_server_appeared();
67 else
69 log_debug("JACK serivce disappeared");
70 if (g_on_server_disappeared != NULL)
72 g_on_server_disappeared();
77 /* this must be static because it is referenced by the
78 * dbus helper layer when hooks are active */
79 static struct dbus_signal_hook g_control_signal_hooks[] =
81 {"ServerStarted", on_jack_server_started},
82 {"ServerStopped", on_jack_server_stopped},
83 {NULL, NULL}
86 bool
87 jack_proxy_init(
88 jack_proxy_callback_server_started server_started,
89 jack_proxy_callback_server_stopped server_stopped,
90 jack_proxy_callback_server_appeared server_appeared,
91 jack_proxy_callback_server_disappeared server_disappeared)
93 g_on_server_started = server_started;
94 g_on_server_stopped = server_stopped;
95 g_on_server_appeared = server_appeared;
96 g_on_server_disappeared = server_disappeared;
98 if (!dbus_register_service_lifetime_hook(g_dbus_connection, JACKDBUS_SERVICE_NAME, on_jack_life_status_changed))
100 log_error("dbus_register_service_lifetime_hook() failed for jackdbus service");
101 return false;
104 if (!dbus_register_object_signal_hooks(
105 g_dbus_connection,
106 JACKDBUS_SERVICE_NAME,
107 JACKDBUS_OBJECT_PATH,
108 JACKDBUS_IFACE_CONTROL,
109 NULL,
110 g_control_signal_hooks))
112 dbus_unregister_service_lifetime_hook(g_dbus_connection, JACKDBUS_SERVICE_NAME);
113 log_error("dbus_register_object_signal_hooks() failed for jackdbus control interface");
114 return false;
118 bool started;
120 if (jack_proxy_is_started(&started))
122 if (g_on_server_appeared != NULL)
124 g_on_server_appeared();
127 if (g_on_server_started != NULL && started)
129 g_on_server_started();
134 return true;
137 void
138 jack_proxy_uninit(
139 void)
141 dbus_unregister_object_signal_hooks(g_dbus_connection, JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL);
142 dbus_unregister_service_lifetime_hook(g_dbus_connection, JACKDBUS_SERVICE_NAME);
145 bool
146 jack_proxy_is_started(
147 bool * started_ptr)
149 dbus_bool_t started;
151 if (!dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "IsStarted", "", "b", &started))
153 return false;
156 *started_ptr = started;
157 return true;
160 bool
161 jack_proxy_get_client_pid(
162 uint64_t client_id,
163 pid_t * pid_ptr)
165 return false;
168 bool
169 jack_proxy_connect_ports(
170 uint64_t port1_id,
171 uint64_t port2_id)
173 return false;
176 static
177 bool
178 add_address(
179 DBusMessageIter * iter_ptr,
180 const char * address)
182 DBusMessageIter array_iter;
183 const char * component;
185 if (!dbus_message_iter_open_container(iter_ptr, DBUS_TYPE_ARRAY, "s", &array_iter))
187 log_error("dbus_message_iter_open_container() failed.");
188 return false;
191 if (address != NULL)
193 component = address;
194 while (*component != 0)
196 if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &component))
198 log_error("dbus_message_iter_append_basic() failed.");
199 return false;
202 component += strlen(component) + 1;
206 dbus_message_iter_close_container(iter_ptr, &array_iter);
208 return true;
211 bool
212 jack_proxy_read_conf_container(
213 const char * address,
214 void * callback_context,
215 bool (* callback)(void * context, bool leaf, const char * address, char * child))
217 DBusMessage * request_ptr;
218 DBusMessage * reply_ptr;
219 DBusMessageIter top_iter;
220 DBusMessageIter array_iter;
221 const char * reply_signature;
222 dbus_bool_t leaf; /* Whether children are parameters (true) or containers (false) */
223 char * child;
225 request_ptr = dbus_message_new_method_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONFIGURE, "ReadContainer");
226 if (request_ptr == NULL)
228 log_error("dbus_message_new_method_call() failed.");
229 return false;
232 dbus_message_iter_init_append(request_ptr, &top_iter);
234 if (!add_address(&top_iter, address))
236 dbus_message_unref(request_ptr);
237 return false;
240 // send message and get a handle for a reply
241 reply_ptr = dbus_connection_send_with_reply_and_block(
242 g_dbus_connection,
243 request_ptr,
244 DBUS_CALL_DEFAULT_TIMEOUT,
245 &g_dbus_error);
247 dbus_message_unref(request_ptr);
249 if (reply_ptr == NULL)
251 log_error("no reply from JACK server, error is '%s'", g_dbus_error.message);
252 dbus_error_free(&g_dbus_error);
253 return false;
256 reply_signature = dbus_message_get_signature(reply_ptr);
258 if (strcmp(reply_signature, "bas") != 0)
260 log_error("ReadContainer() reply signature mismatch. '%s'", reply_signature);
261 dbus_message_unref(reply_ptr);
262 return false;
265 dbus_message_iter_init(reply_ptr, &top_iter);
267 dbus_message_iter_get_basic(&top_iter, &leaf);
268 dbus_message_iter_next(&top_iter);
270 dbus_message_iter_recurse(&top_iter, &array_iter);
272 while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
274 dbus_message_iter_get_basic(&array_iter, &child);
276 if (!callback(callback_context, leaf, address, child))
278 break;
281 dbus_message_iter_next(&array_iter);
284 dbus_message_unref(reply_ptr);
286 return true;
289 bool
290 get_variant(
291 DBusMessageIter * iter_ptr,
292 struct jack_parameter_variant * parameter_ptr)
294 DBusMessageIter variant_iter;
295 int type;
296 dbus_bool_t boolean;
297 dbus_int32_t int32;
298 dbus_uint32_t uint32;
299 char * string;
301 dbus_message_iter_recurse(iter_ptr, &variant_iter);
302 log_debug("variant signature: '%s'", dbus_message_iter_get_signature(&variant_iter));
304 type = dbus_message_iter_get_arg_type(&variant_iter);
305 switch (type)
307 case DBUS_TYPE_INT32:
308 dbus_message_iter_get_basic(&variant_iter, &int32);
309 parameter_ptr->value.int32 = int32;
310 parameter_ptr->type = jack_int32;
311 return true;
312 case DBUS_TYPE_UINT32:
313 dbus_message_iter_get_basic(&variant_iter, &uint32);
314 parameter_ptr->value.uint32 = uint32;
315 parameter_ptr->type = jack_uint32;
316 return true;
317 case DBUS_TYPE_BYTE:
318 dbus_message_iter_get_basic(&variant_iter, &parameter_ptr->value.byte);
319 parameter_ptr->type = jack_byte;
320 return true;
321 case DBUS_TYPE_STRING:
322 dbus_message_iter_get_basic(&variant_iter, &string);
323 string = strdup(string);
324 if (string == NULL)
326 log_error("strdup failed.");
327 return false;
330 parameter_ptr->value.string = string;
331 parameter_ptr->type = jack_string;
332 return true;
333 case DBUS_TYPE_BOOLEAN:
334 dbus_message_iter_get_basic(&variant_iter, &boolean);
335 parameter_ptr->value.boolean = boolean;
336 parameter_ptr->type = jack_boolean;
337 return true;
340 log_error("Unknown D-Bus parameter type %i", (int)type);
341 return false;
344 bool
345 jack_proxy_get_parameter_value(
346 const char * address,
347 bool * is_set_ptr,
348 struct jack_parameter_variant * parameter_ptr)
350 DBusMessage * request_ptr;
351 DBusMessage * reply_ptr;
352 DBusMessageIter top_iter;
353 const char * reply_signature;
354 dbus_bool_t is_set;
355 struct jack_parameter_variant default_value;
357 request_ptr = dbus_message_new_method_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONFIGURE, "GetParameterValue");
358 if (request_ptr == NULL)
360 log_error("dbus_message_new_method_call() failed.");
361 return false;
364 dbus_message_iter_init_append(request_ptr, &top_iter);
366 if (!add_address(&top_iter, address))
368 dbus_message_unref(request_ptr);
369 return false;
372 // send message and get a handle for a reply
373 reply_ptr = dbus_connection_send_with_reply_and_block(
374 g_dbus_connection,
375 request_ptr,
376 DBUS_CALL_DEFAULT_TIMEOUT,
377 &g_dbus_error);
379 dbus_message_unref(request_ptr);
381 if (reply_ptr == NULL)
383 log_error("no reply from JACK server, error is '%s'", g_dbus_error.message);
384 dbus_error_free(&g_dbus_error);
385 return false;
388 reply_signature = dbus_message_get_signature(reply_ptr);
390 if (strcmp(reply_signature, "bvv") != 0)
392 log_error("GetParameterValue() reply signature mismatch. '%s'", reply_signature);
393 dbus_message_unref(reply_ptr);
394 return false;
397 dbus_message_iter_init(reply_ptr, &top_iter);
399 dbus_message_iter_get_basic(&top_iter, &is_set);
400 dbus_message_iter_next(&top_iter);
402 if (!get_variant(&top_iter, &default_value))
404 dbus_message_unref(reply_ptr);
405 return false;
408 if (default_value.type == jack_string)
410 free(default_value.value.string);
413 dbus_message_iter_next(&top_iter);
415 if (!get_variant(&top_iter, parameter_ptr))
417 dbus_message_unref(reply_ptr);
418 return false;
421 dbus_message_unref(reply_ptr);
423 *is_set_ptr = is_set;
425 return true;
428 bool
429 jack_proxy_set_parameter_value(
430 const char * address,
431 const struct jack_parameter_variant * parameter_ptr)
433 DBusMessage * request_ptr;
434 DBusMessage * reply_ptr;
435 DBusMessageIter top_iter;
436 const char * reply_signature;
437 int type;
438 const void * value_ptr;
439 dbus_bool_t boolean;
441 switch (parameter_ptr->type)
443 case jack_int32:
444 type = DBUS_TYPE_INT32;
445 value_ptr = &parameter_ptr->value.int32;
446 break;
447 case jack_uint32:
448 type = DBUS_TYPE_UINT32;
449 value_ptr = &parameter_ptr->value.uint32;
450 break;
451 case jack_byte:
452 type = DBUS_TYPE_BYTE;
453 value_ptr = &parameter_ptr->value.byte;
454 break;
455 case jack_string:
456 type = DBUS_TYPE_STRING;
457 value_ptr = &parameter_ptr->value.string;
458 break;
459 case jack_boolean:
460 type = DBUS_TYPE_BOOLEAN;
461 boolean = parameter_ptr->value.boolean;
462 value_ptr = &boolean;
463 break;
464 default:
465 log_error("Unknown jack parameter type %i", (int)parameter_ptr->type);
466 return false;
469 request_ptr = dbus_message_new_method_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONFIGURE, "SetParameterValue");
470 if (request_ptr == NULL)
472 log_error("dbus_message_new_method_call() failed.");
473 return false;
476 dbus_message_iter_init_append(request_ptr, &top_iter);
478 if (!add_address(&top_iter, address))
480 dbus_message_unref(request_ptr);
481 return false;
484 if (!dbus_iter_append_variant(&top_iter, type, value_ptr))
486 dbus_message_unref(request_ptr);
487 return false;
490 // send message and get a handle for a reply
491 reply_ptr = dbus_connection_send_with_reply_and_block(
492 g_dbus_connection,
493 request_ptr,
494 DBUS_CALL_DEFAULT_TIMEOUT,
495 &g_dbus_error);
497 dbus_message_unref(request_ptr);
499 if (reply_ptr == NULL)
501 log_error("no reply from JACK server, error is '%s'", g_dbus_error.message);
502 dbus_error_free(&g_dbus_error);
503 return false;
506 reply_signature = dbus_message_get_signature(reply_ptr);
508 dbus_message_unref(reply_ptr);
510 if (strcmp(reply_signature, "") != 0)
512 log_error("SetParameterValue() reply signature mismatch. '%s'", reply_signature);
513 return false;
516 return true;
519 bool
520 jack_proxy_reset_parameter_value(
521 const char * address)
523 DBusMessage * request_ptr;
524 DBusMessage * reply_ptr;
525 DBusMessageIter top_iter;
526 const char * reply_signature;
528 request_ptr = dbus_message_new_method_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONFIGURE, "ResetParameterValue");
529 if (request_ptr == NULL)
531 log_error("dbus_message_new_method_call() failed.");
532 return false;
535 dbus_message_iter_init_append(request_ptr, &top_iter);
537 if (!add_address(&top_iter, address))
539 dbus_message_unref(request_ptr);
540 return false;
543 // send message and get a handle for a reply
544 reply_ptr = dbus_connection_send_with_reply_and_block(
545 g_dbus_connection,
546 request_ptr,
547 DBUS_CALL_DEFAULT_TIMEOUT,
548 &g_dbus_error);
550 dbus_message_unref(request_ptr);
552 if (reply_ptr == NULL)
554 log_error("no reply from JACK server, error is '%s'", g_dbus_error.message);
555 dbus_error_free(&g_dbus_error);
556 return false;
559 reply_signature = dbus_message_get_signature(reply_ptr);
561 dbus_message_unref(reply_ptr);
563 if (strcmp(reply_signature, "") != 0)
565 log_error("ResetParameterValue() reply signature mismatch. '%s'", reply_signature);
566 return false;
569 return true;
572 bool jack_proxy_start_server(void)
574 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "StartServer", "", "");
577 bool jack_proxy_stop_server(void)
579 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "StopServer", "", "");
582 bool jack_proxy_is_realtime(bool * realtime_ptr)
584 dbus_bool_t realtime;
586 if (!dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "IsStarted", "", "b", &realtime))
588 return false;
591 *realtime_ptr = realtime;
592 return true;
595 bool jack_proxy_sample_rate(uint32_t * sample_rate_ptr)
597 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "GetSampleRate", "", "u", sample_rate_ptr);
600 bool jack_proxy_get_xruns(uint32_t * xruns_ptr)
602 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "GetXruns", "", "u", xruns_ptr);
605 bool jack_proxy_get_dsp_load(double * dsp_load_ptr)
607 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "GetLoad", "", "d", dsp_load_ptr);
610 bool jack_proxy_get_buffer_size(uint32_t * size_ptr)
612 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "GetBufferSize", "", "u", size_ptr);
615 bool jack_proxy_set_buffer_size(uint32_t size)
617 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "SetBufferSize", "u", &size, "");
620 bool jack_proxy_reset_xruns(void)
622 return dbus_call(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, JACKDBUS_IFACE_CONTROL, "ResetXruns", "", "");
625 static
626 bool
627 reset_callback(
628 void * context,
629 bool leaf,
630 const char * address,
631 char * child)
633 const char * component;
634 char * dst;
635 size_t len;
637 component = address;
638 while (*component != 0)
640 component += strlen(component) + 1;
643 /* address always is same buffer as the one in the jack_reset_all_params() stack */
644 dst = (char *)component;
646 len = strlen(child) + 1;
647 memcpy(dst, child, len);
648 dst[len] = 0;
650 if (leaf)
652 if (!jack_proxy_reset_parameter_value(address))
654 log_error("cannot reset value of parameter");
655 return false;
658 else
660 if (!jack_proxy_read_conf_container(address, context, reset_callback))
662 log_error("cannot read container");
663 return false;
667 *dst = 0;
669 return true;
672 bool jack_reset_all_params(void)
674 char address[1024] = "";
676 return jack_proxy_read_conf_container(address, NULL, reset_callback);