daemon: on app stop, wait its client to disappear
[ladish.git] / daemon / studio.c
blob0db587753addf753452a1f7ad506980030055540
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains part of the studio singleton object implementation
9 * Other parts are in the other studio*.c files in same directory.
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "common.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <dirent.h>
35 #include "studio_internal.h"
36 #include "../dbus_constants.h"
37 #include "control.h"
38 #include "../catdup.h"
39 #include "dirhelpers.h"
40 #include "graph_dict.h"
41 #include "escape.h"
42 #include "studio.h"
43 #include "../proxies/notify_proxy.h"
45 #define STUDIOS_DIR "/studios/"
46 char * g_studios_dir;
48 struct studio g_studio;
50 bool ladish_studio_name_generate(char ** name_ptr)
52 time_t now;
53 char timestamp_str[26];
54 char * name;
56 time(&now);
57 //ctime_r(&now, timestamp_str);
58 //timestamp_str[24] = 0;
59 snprintf(timestamp_str, sizeof(timestamp_str), "%llu", (unsigned long long)now);
61 name = catdup("Studio ", timestamp_str);
62 if (name == NULL)
64 log_error("catdup failed to create studio name");
65 return false;
68 *name_ptr = name;
69 return true;
72 bool ladish_studio_publish(void)
74 dbus_object_path object;
76 ASSERT(g_studio.name != NULL);
78 object = dbus_object_path_new(
79 STUDIO_OBJECT_PATH,
80 &g_interface_studio, &g_studio,
81 &g_interface_patchbay, ladish_graph_get_dbus_context(g_studio.studio_graph),
82 &g_iface_graph_dict, g_studio.studio_graph,
83 &g_iface_app_supervisor, g_studio.app_supervisor,
84 NULL);
85 if (object == NULL)
87 log_error("dbus_object_path_new() failed");
88 return false;
91 if (!dbus_object_path_register(g_dbus_connection, object))
93 log_error("object_path_register() failed");
94 dbus_object_path_destroy(g_dbus_connection, object);
95 return false;
98 log_info("Studio D-Bus object created. \"%s\"", g_studio.name);
100 g_studio.dbus_object = object;
102 emit_studio_appeared();
103 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL, "Studio loaded", NULL);
105 return true;
108 void ladish_studio_emit_started(void)
110 dbus_signal_emit(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioStarted", "");
113 void ladish_studio_emit_crashed(void)
115 dbus_signal_emit(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioCrashed", "");
118 void ladish_studio_emit_stopped(void)
120 dbus_signal_emit(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioStopped", "");
123 static bool ladish_studio_fill_room_info(DBusMessageIter * iter_ptr, ladish_room_handle room)
125 DBusMessageIter dict_iter;
126 const char * name;
127 uuid_t template_uuid;
128 ladish_room_handle template;
129 const char * template_name;
130 const char * opath;
132 name = ladish_room_get_name(room);
133 opath = ladish_room_get_opath(room);
135 if (!ladish_room_get_template_uuid(room, template_uuid))
137 template = NULL;
138 template_name = NULL;
140 else
142 template = find_room_template_by_uuid(template_uuid);
143 if (template != NULL)
145 template_name = ladish_room_get_name(template);
147 else
149 template_name = NULL;
153 if (!dbus_message_iter_append_basic(iter_ptr, DBUS_TYPE_STRING, &opath))
155 log_error("dbus_message_iter_append_basic() failed.");
156 return false;
159 if (!dbus_message_iter_open_container(iter_ptr, DBUS_TYPE_ARRAY, "{sv}", &dict_iter))
161 log_error("dbus_message_iter_open_container() failed.");
162 return false;
165 if (!dbus_maybe_add_dict_entry_string(&dict_iter, "template", template_name))
167 log_error("dbus_maybe_add_dict_entry_string() failed.");
168 return false;
171 if (!dbus_maybe_add_dict_entry_string(&dict_iter, "name", name))
173 log_error("dbus_maybe_add_dict_entry_string() failed.");
174 return false;
177 if (!dbus_message_iter_close_container(iter_ptr, &dict_iter))
179 log_error("dbus_message_iter_close_container() failed.");
180 return false;
183 return true;
186 void ladish_studio_emit_room_appeared(ladish_room_handle room)
188 DBusMessage * message_ptr;
189 DBusMessageIter iter;
191 message_ptr = dbus_message_new_signal(STUDIO_OBJECT_PATH, IFACE_STUDIO, "RoomAppeared");
192 if (message_ptr == NULL)
194 log_error("dbus_message_new_signal() failed.");
195 return;
198 dbus_message_iter_init_append(message_ptr, &iter);
200 if (ladish_studio_fill_room_info(&iter, room))
202 dbus_signal_send(g_dbus_connection, message_ptr);
205 dbus_message_unref(message_ptr);
208 void ladish_studio_emit_room_disappeared(ladish_room_handle room)
210 DBusMessage * message_ptr;
211 DBusMessageIter iter;
213 message_ptr = dbus_message_new_signal(STUDIO_OBJECT_PATH, IFACE_STUDIO, "RoomDisappeared");
214 if (message_ptr == NULL)
216 log_error("dbus_message_new_signal() failed.");
217 return;
220 dbus_message_iter_init_append(message_ptr, &iter);
222 if (ladish_studio_fill_room_info(&iter, room))
224 dbus_signal_send(g_dbus_connection, message_ptr);
227 dbus_message_unref(message_ptr);
230 bool
231 ladish_studio_set_graph_connection_handlers(
232 void * context,
233 ladish_graph_handle graph,
234 ladish_app_supervisor_handle app_supervisor)
236 ladish_virtualizer_set_graph_connection_handlers(context, graph);
237 return true; /* iterate all graphs */
240 void ladish_studio_on_event_jack_started(void)
242 if (!ladish_studio_fetch_jack_settings())
244 log_error("studio_fetch_jack_settings() failed.");
246 return;
249 log_info("jack conf successfully retrieved");
250 g_studio.jack_conf_valid = true;
252 if (!graph_proxy_create(JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, false, &g_studio.jack_graph_proxy))
254 log_error("graph_proxy_create() failed for jackdbus");
256 else
258 if (!ladish_virtualizer_create(g_studio.jack_graph_proxy, g_studio.jack_graph, &g_studio.virtualizer))
260 log_error("ladish_virtualizer_create() failed.");
262 else
264 ladish_studio_iterate_virtual_graphs(g_studio.virtualizer, ladish_studio_set_graph_connection_handlers);
267 if (!graph_proxy_activate(g_studio.jack_graph_proxy))
269 log_error("graph_proxy_activate() failed.");
273 ladish_app_supervisor_autorun(g_studio.app_supervisor);
275 ladish_studio_emit_started();
276 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL, "Studio started", NULL);
279 static void ladish_studio_on_jack_stopped_internal(void)
281 if (g_studio.virtualizer)
283 ladish_virtualizer_destroy(g_studio.virtualizer);
284 g_studio.virtualizer = NULL;
287 if (g_studio.jack_graph_proxy)
289 graph_proxy_destroy(g_studio.jack_graph_proxy);
290 g_studio.jack_graph_proxy = NULL;
294 void ladish_studio_on_event_jack_stopped(void)
296 ladish_studio_emit_stopped();
297 ladish_studio_on_jack_stopped_internal();
298 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL, "Studio stopped", NULL);
301 void ladish_studio_handle_unexpected_jack_server_stop(void)
303 ladish_studio_emit_crashed();
304 ladish_studio_on_jack_stopped_internal();
306 /* TODO: if user wants, restart jack server and reconnect all jack apps to it */
309 static bool ladish_studio_hide_vgraph_non_virtual(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor)
311 ladish_graph_hide_non_virtual(graph);
312 return true; /* iterate all vgraphs */
315 void ladish_studio_run(void)
317 bool state;
319 ladish_cqueue_run(&g_studio.cmd_queue);
320 if (g_quit)
321 { /* if quit is requested, don't bother to process external events */
322 return;
325 if (ladish_environment_consume_change(&g_studio.env_store, ladish_environment_jack_server_started, &state))
327 ladish_cqueue_clear(&g_studio.cmd_queue);
329 if (state)
331 ladish_environment_ignore(&g_studio.env_store, ladish_environment_jack_server_present);
333 if (g_studio.jack_graph_proxy != NULL)
335 log_error("Ignoring \"JACK started\" notification because it is already known that JACK is currently started.");
336 return;
339 /* Automatic studio creation on JACK server start */
340 if (g_studio.dbus_object == NULL)
342 ASSERT(g_studio.name == NULL);
343 if (!ladish_studio_name_generate(&g_studio.name))
345 log_error("studio_name_generate() failed.");
346 return;
349 g_studio.automatic = true;
351 ladish_studio_publish();
354 ladish_studio_on_event_jack_started();
356 else
358 /* JACK stopped but this was not expected. When expected.
359 * the change will be consumed by the run method of the studio stop command */
361 if (g_studio.jack_graph_proxy == NULL)
363 log_error("Ignoring \"JACK stopped\" notification because it is already known that JACK is currently stopped.");
364 return;
367 if (g_studio.automatic)
369 log_info("Unloading automatic studio.");
370 ladish_command_unload_studio(NULL, &g_studio.cmd_queue);
372 ladish_studio_on_event_jack_stopped();
373 return;
376 log_error("JACK stopped unexpectedly.");
377 log_error("Save your work, then unload and reload the studio.");
378 ladish_notify_simple(
379 LADISH_NOTIFY_URGENCY_HIGH,
380 "Studio crashed",
381 "JACK stopped unexpectedly.\n\n"
382 "Save your work, then unload and reload the studio.");
383 ladish_studio_handle_unexpected_jack_server_stop();
387 if (ladish_environment_consume_change(&g_studio.env_store, ladish_environment_jack_server_present, &state))
389 if (g_studio.jack_graph_proxy != NULL)
391 ladish_cqueue_clear(&g_studio.cmd_queue);
393 /* jack was started, this probably means that jackdbus has crashed */
394 log_error("JACK disappeared unexpectedly. Maybe it crashed.");
395 log_error("Save your work, then unload and reload the studio.");
396 ladish_notify_simple(
397 LADISH_NOTIFY_URGENCY_HIGH,
398 "Studio crashed",
399 "JACK disappeared unexpectedly. Maybe it crashed.\n\n"
400 "Save your work, then unload and reload the studio.");
401 ladish_environment_reset_stealth(&g_studio.env_store, ladish_environment_jack_server_started);
403 ladish_studio_iterate_virtual_graphs(NULL, ladish_studio_hide_vgraph_non_virtual);
405 ladish_studio_handle_unexpected_jack_server_stop();
409 ladish_environment_assert_consumed(&g_studio.env_store);
412 static void ladish_studio_on_jack_server_started(void)
414 log_info("JACK server start detected.");
415 ladish_environment_set(&g_studio.env_store, ladish_environment_jack_server_started);
418 static void ladish_studio_on_jack_server_stopped(void)
420 log_info("JACK server stop detected.");
421 ladish_environment_reset(&g_studio.env_store, ladish_environment_jack_server_started);
424 static void ladish_studio_on_jack_server_appeared(void)
426 log_info("JACK controller appeared.");
427 ladish_environment_set(&g_studio.env_store, ladish_environment_jack_server_present);
430 static void ladish_studio_on_jack_server_disappeared(void)
432 log_info("JACK controller disappeared.");
433 ladish_environment_reset(&g_studio.env_store, ladish_environment_jack_server_present);
436 void ladish_on_app_renamed(void * context, const char * old_name, const char * new_app_name)
438 ladish_client_handle client;
440 client = ladish_graph_find_client_by_name(g_studio.jack_graph, old_name);
441 if (client != NULL)
443 ladish_graph_rename_client(g_studio.jack_graph, client, new_app_name);
446 client = ladish_graph_find_client_by_name(context, old_name);
447 if (client != NULL)
449 ladish_graph_rename_client(context, client, new_app_name);
453 bool ladish_studio_init(void)
455 log_info("studio object construct");
457 g_studios_dir = catdup(g_base_dir, STUDIOS_DIR);
458 if (g_studios_dir == NULL)
460 log_error("catdup failed for '%s' and '%s'", g_base_dir, STUDIOS_DIR);
461 goto fail;
464 if (!ensure_dir_exist(g_studios_dir, 0700))
466 goto free_studios_dir;
469 INIT_LIST_HEAD(&g_studio.all_connections);
470 INIT_LIST_HEAD(&g_studio.all_ports);
471 INIT_LIST_HEAD(&g_studio.all_clients);
472 INIT_LIST_HEAD(&g_studio.jack_connections);
473 INIT_LIST_HEAD(&g_studio.jack_ports);
474 INIT_LIST_HEAD(&g_studio.jack_clients);
475 INIT_LIST_HEAD(&g_studio.rooms);
476 INIT_LIST_HEAD(&g_studio.clients);
477 INIT_LIST_HEAD(&g_studio.ports);
479 INIT_LIST_HEAD(&g_studio.jack_conf);
480 INIT_LIST_HEAD(&g_studio.jack_params);
482 g_studio.dbus_object = NULL;
483 g_studio.name = NULL;
484 g_studio.filename = NULL;
486 g_studio.room_count = 0;
488 if (!ladish_graph_create(&g_studio.jack_graph, NULL))
490 log_error("ladish_graph_create() failed to create jack graph object.");
491 goto free_studios_dir;
494 if (!ladish_graph_create(&g_studio.studio_graph, STUDIO_OBJECT_PATH))
496 log_error("ladish_graph_create() failed to create studio graph object.");
497 goto jack_graph_destroy;
500 if (!ladish_app_supervisor_create(&g_studio.app_supervisor, STUDIO_OBJECT_PATH, "studio", g_studio.studio_graph, ladish_on_app_renamed))
502 log_error("ladish_app_supervisor_create() failed.");
503 goto studio_graph_destroy;
506 ladish_cqueue_init(&g_studio.cmd_queue);
507 ladish_environment_init(&g_studio.env_store);
509 if (!jack_proxy_init(
510 ladish_studio_on_jack_server_started,
511 ladish_studio_on_jack_server_stopped,
512 ladish_studio_on_jack_server_appeared,
513 ladish_studio_on_jack_server_disappeared))
515 log_error("jack_proxy_init() failed.");
516 goto app_supervisor_destroy;
519 return true;
521 app_supervisor_destroy:
522 ladish_app_supervisor_destroy(g_studio.app_supervisor);
523 studio_graph_destroy:
524 ladish_graph_destroy(g_studio.studio_graph);
525 jack_graph_destroy:
526 ladish_graph_destroy(g_studio.jack_graph);
527 free_studios_dir:
528 free(g_studios_dir);
529 fail:
530 return false;
533 void ladish_studio_uninit(void)
535 log_info("studio_uninit()");
537 jack_proxy_uninit();
539 ladish_cqueue_clear(&g_studio.cmd_queue);
541 ladish_graph_destroy(g_studio.studio_graph);
542 ladish_graph_destroy(g_studio.jack_graph);
544 free(g_studios_dir);
546 log_info("studio object destroy");
549 struct on_child_exit_context
551 pid_t pid;
552 bool found;
555 #define child_exit_context_ptr ((struct on_child_exit_context *)context)
557 static
558 bool
559 ladish_studio_on_child_exit_callback(
560 void * context,
561 ladish_graph_handle graph,
562 ladish_app_supervisor_handle app_supervisor)
564 child_exit_context_ptr->found = ladish_app_supervisor_child_exit(app_supervisor, child_exit_context_ptr->pid);
565 /* if child is found, return false - it will cause iteration to stop */
566 /* if child is not found, return true - it will cause next supervisor to be checked */
567 return !child_exit_context_ptr->found;
570 #undef child_exit_context_ptr
572 void ladish_studio_on_child_exit(pid_t pid)
574 struct on_child_exit_context context;
576 context.pid = pid;
577 context.found = false;
579 ladish_studio_iterate_virtual_graphs(&context, ladish_studio_on_child_exit_callback);
581 if (!context.found)
583 log_error("unknown child exit detected. pid is %llu", (unsigned long long)pid);
587 bool ladish_studio_is_loaded(void)
589 return g_studio.dbus_object != NULL;
592 bool ladish_studio_is_started(void)
594 return ladish_environment_get(&g_studio.env_store, ladish_environment_jack_server_started);
597 bool ladish_studio_compose_filename(const char * name, char ** filename_ptr_ptr, char ** backup_filename_ptr_ptr)
599 size_t len_dir;
600 char * p;
601 const char * src;
602 char * filename_ptr;
603 char * backup_filename_ptr = NULL;
605 len_dir = strlen(g_studios_dir);
607 filename_ptr = malloc(len_dir + 1 + strlen(name) * 3 + 4 + 1);
608 if (filename_ptr == NULL)
610 log_error("malloc failed to allocate memory for studio file path");
611 return false;
614 if (backup_filename_ptr_ptr != NULL)
616 backup_filename_ptr = malloc(len_dir + 1 + strlen(name) * 3 + 4 + 4 + 1);
617 if (backup_filename_ptr == NULL)
619 log_error("malloc failed to allocate memory for studio backup file path");
620 free(filename_ptr);
621 return false;
625 p = filename_ptr;
626 memcpy(p, g_studios_dir, len_dir);
627 p += len_dir;
629 *p++ = '/';
631 src = name;
632 escape(&src, &p);
633 strcpy(p, ".xml");
635 *filename_ptr_ptr = filename_ptr;
637 if (backup_filename_ptr_ptr != NULL)
639 strcpy(backup_filename_ptr, filename_ptr);
640 strcat(backup_filename_ptr, ".bak");
641 *backup_filename_ptr_ptr = backup_filename_ptr;
644 return true;
647 struct ladish_cqueue * ladish_studio_get_cmd_queue(void)
649 return &g_studio.cmd_queue;
652 ladish_virtualizer_handle ladish_studio_get_virtualizer(void)
654 return g_studio.virtualizer;
657 struct ladish_studio_app_supervisor_match_context
659 const char * opath;
660 ladish_app_supervisor_handle supervisor;
663 #define iterate_context_ptr ((struct ladish_studio_app_supervisor_match_context *)context)
665 static bool ladish_studio_app_supervisor_match(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor)
667 ASSERT(strcmp(ladish_app_supervisor_get_opath(app_supervisor), ladish_graph_get_opath(graph)) == 0);
668 if (strcmp(ladish_app_supervisor_get_opath(app_supervisor), iterate_context_ptr->opath) == 0)
670 ASSERT(iterate_context_ptr->supervisor == NULL);
671 iterate_context_ptr->supervisor = app_supervisor;
672 return false; /* stop iteration */
675 return true; /* continue iteration */
678 #undef iterate_context_ptr
680 ladish_app_supervisor_handle ladish_studio_find_app_supervisor(const char * opath)
682 struct ladish_studio_app_supervisor_match_context ctx;
684 ctx.opath = opath;
685 ctx.supervisor = NULL;
686 ladish_studio_iterate_virtual_graphs(&ctx, ladish_studio_app_supervisor_match);
687 return ctx.supervisor;
690 bool ladish_studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime))
692 DIR * dir;
693 struct dirent * dentry;
694 size_t len;
695 struct stat st;
696 char * path;
697 char * name;
699 dir = opendir(g_studios_dir);
700 if (dir == NULL)
702 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Cannot open directory '%s': %d (%s)", g_studios_dir, errno, strerror(errno));
703 return false;
706 while ((dentry = readdir(dir)) != NULL)
708 len = strlen(dentry->d_name);
709 if (len <= 4 || strcmp(dentry->d_name + (len - 4), ".xml") != 0)
710 continue;
712 path = catdup(g_studios_dir, dentry->d_name);
713 if (path == NULL)
715 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "catdup() failed");
716 return false;
719 if (stat(path, &st) != 0)
721 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to stat '%s': %d (%s)", path, errno, strerror(errno));
722 free(path);
723 return false;
726 free(path);
728 if (!S_ISREG(st.st_mode))
730 //log_info("Ignoring direntry that is not regular file. Mode is %07o", st.st_mode);
731 continue;
734 name = malloc(len - 4 + 1);
735 if (name == NULL)
737 log_error("malloc() failed.");
738 closedir(dir);
739 return false;
742 name[unescape(dentry->d_name, len - 4, name)] = 0;
743 //log_info("name = '%s'", name);
745 if (!callback(call_ptr, context, name, st.st_mtime))
747 free(name);
748 closedir(dir);
749 return false;
752 free(name);
755 closedir(dir);
756 return true;
759 bool ladish_studio_delete(void * call_ptr, const char * studio_name)
761 char * filename;
762 char * bak_filename;
763 struct stat st;
764 bool ret;
766 ret = false;
768 if (!ladish_studio_compose_filename(studio_name, &filename, &bak_filename))
770 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename");
771 goto exit;
774 log_info("Deleting studio ('%s')", filename);
776 if (unlink(filename) != 0)
778 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unlink(%s) failed: %d (%s)", filename, errno, strerror(errno));
779 goto free;
782 /* try to delete the backup file */
783 if (stat(bak_filename, &st) == 0)
785 if (unlink(bak_filename) != 0)
787 /* failing to delete backup file will not case delete command failure */
788 log_error("unlink(%s) failed: %d (%s)", bak_filename, errno, strerror(errno));
792 ret = true;
794 free:
795 free(filename);
796 free(bak_filename);
797 exit:
798 return ret;
801 bool
802 ladish_studio_iterate_virtual_graphs(
803 void * context,
804 bool (* callback)(
805 void * context,
806 ladish_graph_handle graph,
807 ladish_app_supervisor_handle app_supervisor))
809 struct list_head * node_ptr;
810 ladish_room_handle room;
811 ladish_app_supervisor_handle room_app_supervisor;
812 ladish_graph_handle room_graph;
814 if (!callback(context, g_studio.studio_graph, g_studio.app_supervisor))
816 return false;
819 list_for_each(node_ptr, &g_studio.rooms)
821 room = ladish_room_from_list_node(node_ptr);
822 room_app_supervisor = ladish_room_get_app_supervisor(room);
823 ASSERT(room_app_supervisor != NULL);
824 room_graph = ladish_room_get_graph(room);
826 if (!callback(context, room_graph, room_app_supervisor))
828 return false;
832 return true;
835 static bool ladish_studio_stop_app_supervisor(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor)
837 ladish_app_supervisor_stop(app_supervisor);
838 return true; /* iterate all supervisors */
841 void ladish_studio_stop_app_supervisors(void)
843 ladish_studio_iterate_virtual_graphs(NULL, ladish_studio_stop_app_supervisor);
846 void ladish_studio_emit_renamed(void)
848 dbus_signal_emit(g_dbus_connection, STUDIO_OBJECT_PATH, IFACE_STUDIO, "StudioRenamed", "s", &g_studio.name);
851 /**********************************************************************************/
852 /* D-Bus methods */
853 /**********************************************************************************/
855 static void ladish_studio_dbus_get_name(struct dbus_method_call * call_ptr)
857 method_return_new_single(call_ptr, DBUS_TYPE_STRING, &g_studio.name);
860 static void ladish_studio_dbus_rename(struct dbus_method_call * call_ptr)
862 const char * new_name;
863 char * new_name_dup;
865 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &new_name, DBUS_TYPE_INVALID))
867 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
868 dbus_error_free(&g_dbus_error);
869 return;
872 log_info("Rename studio request (%s)", new_name);
874 new_name_dup = strdup(new_name);
875 if (new_name_dup == NULL)
877 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed to allocate new name.");
878 return;
881 free(g_studio.name);
882 g_studio.name = new_name_dup;
884 method_return_new_void(call_ptr);
885 ladish_studio_emit_renamed();
888 static void ladish_studio_dbus_save(struct dbus_method_call * call_ptr)
890 log_info("Save studio request");
892 if (ladish_command_save_studio(call_ptr, &g_studio.cmd_queue, g_studio.name))
894 method_return_new_void(call_ptr);
898 static void ladish_studio_dbus_save_as(struct dbus_method_call * call_ptr)
900 const char * new_name;
902 log_info("SaveAs studio request");
904 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &new_name, DBUS_TYPE_INVALID))
906 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
907 dbus_error_free(&g_dbus_error);
908 return;
911 if (ladish_command_save_studio(call_ptr, &g_studio.cmd_queue, new_name))
913 method_return_new_void(call_ptr);
917 static void ladish_studio_dbus_unload(struct dbus_method_call * call_ptr)
919 log_info("Unload studio request");
921 if (ladish_command_unload_studio(call_ptr, &g_studio.cmd_queue))
923 method_return_new_void(call_ptr);
927 static void ladish_studio_dbus_stop(struct dbus_method_call * call_ptr)
929 log_info("Stop studio request");
931 g_studio.automatic = false; /* even if it was automatic, it is not anymore because user knows about it */
933 if (ladish_command_stop_studio(call_ptr, &g_studio.cmd_queue))
935 method_return_new_void(call_ptr);
939 static void ladish_studio_dbus_start(struct dbus_method_call * call_ptr)
941 log_info("Start studio request");
943 g_studio.automatic = false; /* even if it was automatic, it is not anymore because user knows about it */
945 if (ladish_command_start_studio(call_ptr, &g_studio.cmd_queue))
947 method_return_new_void(call_ptr);
951 static void ladish_studio_dbus_is_started(struct dbus_method_call * call_ptr)
953 dbus_bool_t started;
955 started = g_studio.jack_graph_proxy != NULL;
957 method_return_new_single(call_ptr, DBUS_TYPE_BOOLEAN, &started);
960 static void ladish_studio_dbus_create_room(struct dbus_method_call * call_ptr)
962 const char * room_name;
963 const char * template_name;
965 dbus_error_init(&g_dbus_error);
967 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &room_name, DBUS_TYPE_STRING, &template_name, DBUS_TYPE_INVALID))
969 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
970 dbus_error_free(&g_dbus_error);
971 return;
974 if (ladish_command_create_room(call_ptr, ladish_studio_get_cmd_queue(), room_name, template_name))
976 method_return_new_void(call_ptr);
980 static void ladish_studio_dbus_get_room_list(struct dbus_method_call * call_ptr)
982 DBusMessageIter iter, array_iter;
983 DBusMessageIter struct_iter;
984 struct list_head * node_ptr;
985 ladish_room_handle room;
987 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
988 if (call_ptr->reply == NULL)
990 goto fail;
993 dbus_message_iter_init_append(call_ptr->reply, &iter);
995 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sa{sv})", &array_iter))
997 goto fail_unref;
1000 list_for_each(node_ptr, &g_studio.rooms)
1002 room = ladish_room_from_list_node(node_ptr);
1004 if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
1005 goto fail_unref;
1007 if (!ladish_studio_fill_room_info(&struct_iter, room))
1008 goto fail_unref;
1010 if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
1011 goto fail_unref;
1014 if (!dbus_message_iter_close_container(&iter, &array_iter))
1016 goto fail_unref;
1019 return;
1021 fail_unref:
1022 dbus_message_unref(call_ptr->reply);
1023 call_ptr->reply = NULL;
1025 fail:
1026 log_error("Ran out of memory trying to construct method return");
1029 static void ladish_studio_dbus_delete_room(struct dbus_method_call * call_ptr)
1031 const char * name;
1033 dbus_error_init(&g_dbus_error);
1035 if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
1037 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
1038 dbus_error_free(&g_dbus_error);
1039 return;
1042 if (ladish_command_delete_room(call_ptr, ladish_studio_get_cmd_queue(), name))
1044 method_return_new_void(call_ptr);
1048 void ladish_studio_remove_all_rooms(void)
1050 struct list_head * node_ptr;
1051 ladish_room_handle room;
1053 while (!list_empty(&g_studio.rooms))
1055 node_ptr = g_studio.rooms.next;
1056 list_del(node_ptr);
1057 room = ladish_room_from_list_node(node_ptr);
1058 ladish_studio_emit_room_disappeared(room);
1059 ladish_room_destroy(room);
1063 METHOD_ARGS_BEGIN(GetName, "Get studio name")
1064 METHOD_ARG_DESCRIBE_OUT("studio_name", "s", "Name of studio")
1065 METHOD_ARGS_END
1067 METHOD_ARGS_BEGIN(Rename, "Rename studio")
1068 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1069 METHOD_ARGS_END
1071 METHOD_ARGS_BEGIN(Save, "Save studio")
1072 METHOD_ARGS_END
1074 METHOD_ARGS_BEGIN(SaveAs, "SaveAs studio")
1075 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1076 METHOD_ARGS_END
1078 METHOD_ARGS_BEGIN(Unload, "Unload studio")
1079 METHOD_ARGS_END
1081 METHOD_ARGS_BEGIN(Start, "Start studio")
1082 METHOD_ARGS_END
1084 METHOD_ARGS_BEGIN(Stop, "Stop studio")
1085 METHOD_ARGS_END
1087 METHOD_ARGS_BEGIN(IsStarted, "Check whether studio is started")
1088 METHOD_ARG_DESCRIBE_OUT("started", "b", "Whether studio is started")
1089 METHOD_ARGS_END
1091 METHOD_ARGS_BEGIN(CreateRoom, "Create new studio room")
1092 METHOD_ARG_DESCRIBE_IN("room_name", "s", "Studio room name")
1093 METHOD_ARG_DESCRIBE_IN("room_template_name", "s", "Room template name")
1094 METHOD_ARGS_END
1096 METHOD_ARGS_BEGIN(GetRoomList, "Get list of rooms in this studio")
1097 METHOD_ARG_DESCRIBE_OUT("room_list", "a(sa{sv})", "List of studio rooms: opaths and properties")
1098 METHOD_ARGS_END
1100 METHOD_ARGS_BEGIN(DeleteRoom, "Delete studio room")
1101 METHOD_ARG_DESCRIBE_IN("room_name", "s", "Name of studio room to delete")
1102 METHOD_ARGS_END
1104 METHODS_BEGIN
1105 METHOD_DESCRIBE(GetName, ladish_studio_dbus_get_name) /* sync */
1106 METHOD_DESCRIBE(Rename, ladish_studio_dbus_rename) /* sync */
1107 METHOD_DESCRIBE(Save, ladish_studio_dbus_save) /* async */
1108 METHOD_DESCRIBE(SaveAs, ladish_studio_dbus_save_as) /* async */
1109 METHOD_DESCRIBE(Unload, ladish_studio_dbus_unload) /* async */
1110 METHOD_DESCRIBE(Start, ladish_studio_dbus_start) /* async */
1111 METHOD_DESCRIBE(Stop, ladish_studio_dbus_stop) /* async */
1112 METHOD_DESCRIBE(IsStarted, ladish_studio_dbus_is_started) /* sync */
1113 METHOD_DESCRIBE(CreateRoom, ladish_studio_dbus_create_room) /* async */
1114 METHOD_DESCRIBE(GetRoomList, ladish_studio_dbus_get_room_list) /* sync */
1115 METHOD_DESCRIBE(DeleteRoom, ladish_studio_dbus_delete_room) /* async */
1116 METHODS_END
1118 SIGNAL_ARGS_BEGIN(StudioRenamed, "Studio name changed")
1119 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1120 SIGNAL_ARGS_END
1122 SIGNAL_ARGS_BEGIN(StudioStarted, "Studio started")
1123 SIGNAL_ARGS_END
1125 SIGNAL_ARGS_BEGIN(StudioCrashed, "Studio crashed")
1126 SIGNAL_ARGS_END
1128 SIGNAL_ARGS_BEGIN(StudioStopped, "Studio stopped")
1129 SIGNAL_ARGS_END
1131 SIGNAL_ARGS_BEGIN(RoomAppeared, "Room D-Bus object appeared")
1132 SIGNAL_ARG_DESCRIBE("opath", "s", "room object path")
1133 SIGNAL_ARG_DESCRIBE("properties", "a{sv}", "room object path and props")
1134 SIGNAL_ARGS_END
1136 SIGNAL_ARGS_BEGIN(RoomChanged, "Room D-Bus object changed")
1137 SIGNAL_ARG_DESCRIBE("opath", "s", "room object path")
1138 SIGNAL_ARG_DESCRIBE("properties", "a{sv}", "room object path and props")
1139 SIGNAL_ARGS_END
1141 SIGNAL_ARGS_BEGIN(RoomDisappeared, "Room D-Bus object disappeared")
1142 SIGNAL_ARG_DESCRIBE("opath", "s", "room object path")
1143 SIGNAL_ARG_DESCRIBE("properties", "a{sv}", "room object path and props")
1144 SIGNAL_ARGS_END
1146 SIGNALS_BEGIN
1147 SIGNAL_DESCRIBE(StudioRenamed)
1148 SIGNAL_DESCRIBE(StudioStarted)
1149 SIGNAL_DESCRIBE(StudioCrashed)
1150 SIGNAL_DESCRIBE(StudioStopped)
1151 SIGNAL_DESCRIBE(RoomAppeared)
1152 SIGNAL_DESCRIBE(RoomDisappeared)
1153 SIGNAL_DESCRIBE(RoomChanged)
1154 SIGNALS_END
1156 INTERFACE_BEGIN(g_interface_studio, IFACE_STUDIO)
1157 INTERFACE_DEFAULT_HANDLER
1158 INTERFACE_EXPOSE_METHODS
1159 INTERFACE_EXPOSE_SIGNALS
1160 INTERFACE_END