1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009, 2010, 2011 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.
30 #include <sys/types.h>
34 #include "studio_internal.h"
35 #include "../dbus_constants.h"
37 #include "../common/catdup.h"
38 #include "../common/dirhelpers.h"
39 #include "graph_dict.h"
40 #include "graph_manager.h"
43 #include "../proxies/notify_proxy.h"
45 #define STUDIOS_DIR "/studios/"
47 #define RECENT_STUDIOS_STORE_FILE "recent_studios"
48 #define RECENT_STUDIOS_STORE_MAX_ITEMS 50
51 ladish_recent_store_handle g_studios_recent_store
;
53 struct studio g_studio
;
55 bool ladish_studio_name_generate(char ** name_ptr
)
58 char timestamp_str
[26];
62 //ctime_r(&now, timestamp_str);
63 //timestamp_str[24] = 0;
64 snprintf(timestamp_str
, sizeof(timestamp_str
), "%llu", (unsigned long long)now
);
66 name
= catdup("Studio ", timestamp_str
);
69 log_error("catdup failed to create studio name");
77 bool ladish_studio_show(void)
79 dbus_object_path object
;
81 ASSERT(g_studio
.name
!= NULL
);
82 ASSERT(!g_studio
.announced
);
84 object
= dbus_object_path_new(
86 &g_interface_studio
, &g_studio
,
87 &g_interface_patchbay
, ladish_graph_get_dbus_context(g_studio
.studio_graph
),
88 &g_iface_graph_dict
, g_studio
.studio_graph
,
89 &g_iface_graph_manager
, g_studio
.studio_graph
,
90 &g_iface_app_supervisor
, g_studio
.app_supervisor
,
94 log_error("dbus_object_path_new() failed");
98 if (!dbus_object_path_register(cdbus_g_dbus_connection
, object
))
100 log_error("object_path_register() failed");
101 dbus_object_path_destroy(cdbus_g_dbus_connection
, object
);
105 log_info("Studio D-Bus object created. \"%s\"", g_studio
.name
);
107 g_studio
.dbus_object
= object
;
109 emit_studio_appeared();
114 void ladish_studio_announce(void)
116 ASSERT(!g_studio
.announced
);
118 /* notify the user that studio started successfully, but dont lie when jack was started externally */
119 if (!g_studio
.automatic
)
121 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL
, "Studio loaded", NULL
);
124 g_studio
.announced
= true;
127 bool ladish_studio_publish(void)
129 if (!ladish_studio_show())
134 ladish_studio_announce();
138 void ladish_studio_clear(void)
140 ladish_graph_dump(g_studio
.studio_graph
);
141 ladish_graph_dump(g_studio
.jack_graph
);
143 /* remove rooms that own clients in studio graph before clearing it */
144 ladish_studio_remove_all_rooms();
146 ladish_graph_clear(g_studio
.studio_graph
, NULL
);
147 ladish_graph_clear(g_studio
.jack_graph
, NULL
);
149 ladish_studio_jack_conf_clear();
151 g_studio
.modified
= false;
152 g_studio
.persisted
= false;
154 ladish_app_supervisor_clear(g_studio
.app_supervisor
);
156 if (g_studio
.dbus_object
!= NULL
)
158 dbus_object_path_destroy(cdbus_g_dbus_connection
, g_studio
.dbus_object
);
159 g_studio
.dbus_object
= NULL
;
160 emit_studio_disappeared();
163 if (g_studio
.announced
)
165 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL
, "Studio unloaded", NULL
);
166 g_studio
.announced
= false;
169 if (g_studio
.name
!= NULL
)
172 g_studio
.name
= NULL
;
175 if (g_studio
.filename
!= NULL
)
177 free(g_studio
.filename
);
178 g_studio
.filename
= NULL
;
182 void ladish_studio_emit_started(void)
184 dbus_signal_emit(cdbus_g_dbus_connection
, STUDIO_OBJECT_PATH
, IFACE_STUDIO
, "StudioStarted", "");
187 void ladish_studio_emit_crashed(void)
189 dbus_signal_emit(cdbus_g_dbus_connection
, STUDIO_OBJECT_PATH
, IFACE_STUDIO
, "StudioCrashed", "");
192 void ladish_studio_emit_stopped(void)
194 dbus_signal_emit(cdbus_g_dbus_connection
, STUDIO_OBJECT_PATH
, IFACE_STUDIO
, "StudioStopped", "");
197 static bool ladish_studio_fill_room_info(DBusMessageIter
* iter_ptr
, ladish_room_handle room
)
199 DBusMessageIter dict_iter
;
201 uuid_t template_uuid
;
202 ladish_room_handle
template;
203 const char * template_name
;
206 name
= ladish_room_get_name(room
);
207 opath
= ladish_room_get_opath(room
);
209 if (!ladish_room_get_template_uuid(room
, template_uuid
))
212 template_name
= NULL
;
216 template = find_room_template_by_uuid(template_uuid
);
217 if (template != NULL
)
219 template_name
= ladish_room_get_name(template);
223 template_name
= NULL
;
227 if (!dbus_message_iter_append_basic(iter_ptr
, DBUS_TYPE_STRING
, &opath
))
229 log_error("dbus_message_iter_append_basic() failed.");
233 if (!dbus_message_iter_open_container(iter_ptr
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
))
235 log_error("dbus_message_iter_open_container() failed.");
239 if (!dbus_maybe_add_dict_entry_string(&dict_iter
, "template", template_name
))
241 log_error("dbus_maybe_add_dict_entry_string() failed.");
245 if (!dbus_maybe_add_dict_entry_string(&dict_iter
, "name", name
))
247 log_error("dbus_maybe_add_dict_entry_string() failed.");
251 if (!dbus_message_iter_close_container(iter_ptr
, &dict_iter
))
253 log_error("dbus_message_iter_close_container() failed.");
260 static void ladish_studio_emit_room_appeared(ladish_room_handle room
)
262 DBusMessage
* message_ptr
;
263 DBusMessageIter iter
;
265 message_ptr
= dbus_message_new_signal(STUDIO_OBJECT_PATH
, IFACE_STUDIO
, "RoomAppeared");
266 if (message_ptr
== NULL
)
268 log_error("dbus_message_new_signal() failed.");
272 dbus_message_iter_init_append(message_ptr
, &iter
);
274 if (ladish_studio_fill_room_info(&iter
, room
))
276 dbus_signal_send(cdbus_g_dbus_connection
, message_ptr
);
279 dbus_message_unref(message_ptr
);
282 void ladish_studio_emit_room_disappeared(ladish_room_handle room
)
284 DBusMessage
* message_ptr
;
285 DBusMessageIter iter
;
287 message_ptr
= dbus_message_new_signal(STUDIO_OBJECT_PATH
, IFACE_STUDIO
, "RoomDisappeared");
288 if (message_ptr
== NULL
)
290 log_error("dbus_message_new_signal() failed.");
294 dbus_message_iter_init_append(message_ptr
, &iter
);
296 if (ladish_studio_fill_room_info(&iter
, room
))
298 dbus_signal_send(cdbus_g_dbus_connection
, message_ptr
);
301 dbus_message_unref(message_ptr
);
304 void ladish_studio_room_appeared(ladish_room_handle room
)
306 log_info("Room \"%s\" appeared", ladish_room_get_name(room
));
307 list_add_tail(ladish_room_get_list_node(room
), &g_studio
.rooms
);
308 ladish_studio_emit_room_appeared(room
);
311 void ladish_studio_room_disappeared(ladish_room_handle room
)
313 log_info("Room \"%s\" disappeared", ladish_room_get_name(room
));
314 list_del(ladish_room_get_list_node(room
));
315 ladish_studio_emit_room_disappeared(room
);
319 ladish_studio_set_graph_connection_handlers(
321 ladish_graph_handle graph
,
322 ladish_app_supervisor_handle app_supervisor
)
324 ladish_virtualizer_set_graph_connection_handlers(context
, graph
);
325 return true; /* iterate all graphs */
328 void ladish_studio_on_event_jack_started(void)
330 if (!ladish_studio_fetch_jack_settings())
332 log_error("studio_fetch_jack_settings() failed.");
337 log_info("jack conf successfully retrieved");
338 g_studio
.jack_conf_valid
= true;
340 if (!graph_proxy_create(JACKDBUS_SERVICE_NAME
, JACKDBUS_OBJECT_PATH
, false, false, &g_studio
.jack_graph_proxy
))
342 log_error("graph_proxy_create() failed for jackdbus");
346 if (!ladish_virtualizer_create(g_studio
.jack_graph_proxy
, g_studio
.jack_graph
, &g_studio
.virtualizer
))
348 log_error("ladish_virtualizer_create() failed.");
352 ladish_studio_iterate_virtual_graphs(g_studio
.virtualizer
, ladish_studio_set_graph_connection_handlers
);
355 if (!graph_proxy_activate(g_studio
.jack_graph_proxy
))
357 log_error("graph_proxy_activate() failed.");
361 ladish_app_supervisor_autorun(g_studio
.app_supervisor
);
363 ladish_studio_emit_started();
365 /* notify the user that studio started successfully, but dont lie when jack was started externally */
366 if (!g_studio
.automatic
)
368 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL
, "Studio started", NULL
);
372 static void ladish_studio_on_jack_stopped_internal(void)
374 if (g_studio
.virtualizer
)
376 ladish_virtualizer_destroy(g_studio
.virtualizer
);
377 g_studio
.virtualizer
= NULL
;
380 if (g_studio
.jack_graph_proxy
)
382 graph_proxy_destroy(g_studio
.jack_graph_proxy
);
383 g_studio
.jack_graph_proxy
= NULL
;
387 void ladish_studio_on_event_jack_stopped(void)
389 ladish_studio_emit_stopped();
390 ladish_studio_on_jack_stopped_internal();
391 ladish_notify_simple(LADISH_NOTIFY_URGENCY_NORMAL
, "Studio stopped", NULL
);
394 void ladish_studio_handle_unexpected_jack_server_stop(void)
396 ladish_studio_emit_crashed();
397 ladish_studio_on_jack_stopped_internal();
399 /* TODO: if user wants, restart jack server and reconnect all jack apps to it */
402 static bool ladish_studio_hide_vgraph_non_virtual(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
404 ladish_graph_hide_non_virtual(graph
);
405 return true; /* iterate all vgraphs */
408 void ladish_studio_run(void)
412 ladish_cqueue_run(&g_studio
.cmd_queue
);
414 { /* if quit is requested, don't bother to process external events */
418 if (ladish_environment_consume_change(&g_studio
.env_store
, ladish_environment_jack_server_started
, &state
))
420 ladish_cqueue_clear(&g_studio
.cmd_queue
);
424 ladish_environment_ignore(&g_studio
.env_store
, ladish_environment_jack_server_present
);
426 if (g_studio
.jack_graph_proxy
!= NULL
)
428 log_error("Ignoring \"JACK started\" notification because it is already known that JACK is currently started.");
432 /* Automatic studio creation on JACK server start */
433 if (g_studio
.dbus_object
== NULL
)
435 ASSERT(g_studio
.name
== NULL
);
436 if (!ladish_studio_name_generate(&g_studio
.name
))
438 log_error("studio_name_generate() failed.");
442 g_studio
.automatic
= true;
444 ladish_studio_publish();
447 ladish_studio_on_event_jack_started();
449 if (g_studio
.automatic
)
451 ladish_notify_simple(
452 LADISH_NOTIFY_URGENCY_NORMAL
,
453 "Automatic studio created",
454 "JACK server is started not by ladish daemon and there is no loaded studio, so a new studio is created and marked as started.");
459 /* JACK stopped but this was not expected. When expected.
460 * the change will be consumed by the run method of the studio stop command */
462 if (g_studio
.jack_graph_proxy
== NULL
)
464 log_error("Ignoring \"JACK stopped\" notification because it is already known that JACK is currently stopped.");
468 if (g_studio
.automatic
)
470 log_info("Unloading automatic studio.");
471 ladish_command_unload_studio(NULL
, &g_studio
.cmd_queue
);
473 ladish_studio_on_event_jack_stopped();
477 log_error("JACK stopped unexpectedly.");
478 log_error("Save your work, then unload and reload the studio.");
479 ladish_notify_simple(
480 LADISH_NOTIFY_URGENCY_HIGH
,
482 "JACK stopped unexpectedly.\n\n"
483 "Save your work, then unload and reload the studio.");
484 ladish_studio_handle_unexpected_jack_server_stop();
488 if (ladish_environment_consume_change(&g_studio
.env_store
, ladish_environment_jack_server_present
, &state
))
490 if (g_studio
.jack_graph_proxy
!= NULL
)
492 ladish_cqueue_clear(&g_studio
.cmd_queue
);
494 /* jack was started, this probably means that jackdbus has crashed */
495 log_error("JACK disappeared unexpectedly. Maybe it crashed.");
496 log_error("Save your work, then unload and reload the studio.");
497 ladish_notify_simple(
498 LADISH_NOTIFY_URGENCY_HIGH
,
500 "JACK disappeared unexpectedly. Maybe it crashed.\n\n"
501 "Save your work, then unload and reload the studio.");
502 ladish_environment_reset_stealth(&g_studio
.env_store
, ladish_environment_jack_server_started
);
504 ladish_studio_iterate_virtual_graphs(NULL
, ladish_studio_hide_vgraph_non_virtual
);
506 ladish_studio_handle_unexpected_jack_server_stop();
510 ladish_environment_assert_consumed(&g_studio
.env_store
);
513 static void ladish_studio_on_jack_server_started(void)
515 log_info("JACK server start detected.");
516 ladish_environment_set(&g_studio
.env_store
, ladish_environment_jack_server_started
);
519 static void ladish_studio_on_jack_server_stopped(void)
521 log_info("JACK server stop detected.");
522 ladish_environment_reset(&g_studio
.env_store
, ladish_environment_jack_server_started
);
525 static void ladish_studio_on_jack_server_appeared(void)
527 log_info("JACK controller appeared.");
528 ladish_environment_set(&g_studio
.env_store
, ladish_environment_jack_server_present
);
531 static void ladish_studio_on_jack_server_disappeared(void)
533 log_info("JACK controller disappeared.");
534 ladish_environment_reset(&g_studio
.env_store
, ladish_environment_jack_server_present
);
537 bool ladish_studio_init(void)
539 char * studios_recent_store_path
;
541 log_info("studio object construct");
543 g_studios_dir
= catdup(g_base_dir
, STUDIOS_DIR
);
544 if (g_studios_dir
== NULL
)
546 log_error("catdup failed for '%s' and '%s'", g_base_dir
, STUDIOS_DIR
);
550 if (!ensure_dir_exist(g_studios_dir
, 0700))
552 goto free_studios_dir
;
555 studios_recent_store_path
= catdup(g_base_dir
, "/" RECENT_STUDIOS_STORE_FILE
);
556 if (studios_recent_store_path
== NULL
)
558 log_error("catdup failed for to compose recent studios store file path");
559 goto free_studios_dir
;
562 if (!ladish_recent_store_create(studios_recent_store_path
, 10, &g_studios_recent_store
))
564 free(studios_recent_store_path
);
565 goto free_studios_dir
;
568 free(studios_recent_store_path
);
570 INIT_LIST_HEAD(&g_studio
.all_connections
);
571 INIT_LIST_HEAD(&g_studio
.all_ports
);
572 INIT_LIST_HEAD(&g_studio
.all_clients
);
573 INIT_LIST_HEAD(&g_studio
.jack_connections
);
574 INIT_LIST_HEAD(&g_studio
.jack_ports
);
575 INIT_LIST_HEAD(&g_studio
.jack_clients
);
576 INIT_LIST_HEAD(&g_studio
.rooms
);
577 INIT_LIST_HEAD(&g_studio
.clients
);
578 INIT_LIST_HEAD(&g_studio
.ports
);
580 INIT_LIST_HEAD(&g_studio
.jack_conf
);
581 INIT_LIST_HEAD(&g_studio
.jack_params
);
583 g_studio
.dbus_object
= NULL
;
584 g_studio
.announced
= false;
585 g_studio
.name
= NULL
;
586 g_studio
.filename
= NULL
;
588 g_studio
.room_count
= 0;
590 if (!ladish_graph_create(&g_studio
.jack_graph
, NULL
))
592 log_error("ladish_graph_create() failed to create jack graph object.");
593 goto destroy_recent_store
;
596 if (!ladish_graph_create(&g_studio
.studio_graph
, STUDIO_OBJECT_PATH
))
598 log_error("ladish_graph_create() failed to create studio graph object.");
599 goto jack_graph_destroy
;
602 if (!ladish_app_supervisor_create(&g_studio
.app_supervisor
, STUDIO_OBJECT_PATH
, "studio", g_studio
.studio_graph
, ladish_virtualizer_rename_app
))
604 log_error("ladish_app_supervisor_create() failed.");
605 goto studio_graph_destroy
;
608 ladish_cqueue_init(&g_studio
.cmd_queue
);
609 ladish_environment_init(&g_studio
.env_store
);
611 if (!jack_proxy_init(
612 ladish_studio_on_jack_server_started
,
613 ladish_studio_on_jack_server_stopped
,
614 ladish_studio_on_jack_server_appeared
,
615 ladish_studio_on_jack_server_disappeared
))
617 log_error("jack_proxy_init() failed.");
618 goto app_supervisor_destroy
;
623 app_supervisor_destroy
:
624 ladish_app_supervisor_destroy(g_studio
.app_supervisor
);
625 studio_graph_destroy
:
626 ladish_graph_destroy(g_studio
.studio_graph
);
628 ladish_graph_destroy(g_studio
.jack_graph
);
629 destroy_recent_store
:
630 ladish_recent_store_destroy(g_studios_recent_store
);
637 void ladish_studio_uninit(void)
639 log_info("studio_uninit()");
643 ladish_cqueue_clear(&g_studio
.cmd_queue
);
645 ladish_graph_destroy(g_studio
.studio_graph
);
646 ladish_graph_destroy(g_studio
.jack_graph
);
648 ladish_recent_store_destroy(g_studios_recent_store
);
652 log_info("studio object destroy");
655 struct on_child_exit_context
661 #define child_exit_context_ptr ((struct on_child_exit_context *)context)
665 ladish_studio_on_child_exit_callback(
667 ladish_graph_handle graph
,
668 ladish_app_supervisor_handle app_supervisor
)
670 child_exit_context_ptr
->found
= ladish_app_supervisor_child_exit(app_supervisor
, child_exit_context_ptr
->pid
);
671 /* if child is found, return false - it will cause iteration to stop */
672 /* if child is not found, return true - it will cause next supervisor to be checked */
673 return !child_exit_context_ptr
->found
;
676 #undef child_exit_context_ptr
678 void ladish_studio_on_child_exit(pid_t pid
)
680 struct on_child_exit_context context
;
683 context
.found
= false;
685 ladish_studio_iterate_virtual_graphs(&context
, ladish_studio_on_child_exit_callback
);
689 log_error("unknown child exit detected. pid is %llu", (unsigned long long)pid
);
693 bool ladish_studio_is_loaded(void)
695 return g_studio
.dbus_object
!= NULL
&& g_studio
.announced
;
698 bool ladish_studio_is_started(void)
700 return ladish_environment_get(&g_studio
.env_store
, ladish_environment_jack_server_started
);
703 bool ladish_studio_compose_filename(const char * name
, char ** filename_ptr_ptr
, char ** backup_filename_ptr_ptr
)
709 char * backup_filename_ptr
= NULL
;
711 len_dir
= strlen(g_studios_dir
);
713 filename_ptr
= malloc(len_dir
+ 1 + strlen(name
) * 3 + 4 + 1);
714 if (filename_ptr
== NULL
)
716 log_error("malloc failed to allocate memory for studio file path");
720 if (backup_filename_ptr_ptr
!= NULL
)
722 backup_filename_ptr
= malloc(len_dir
+ 1 + strlen(name
) * 3 + 4 + 4 + 1);
723 if (backup_filename_ptr
== NULL
)
725 log_error("malloc failed to allocate memory for studio backup file path");
732 memcpy(p
, g_studios_dir
, len_dir
);
738 escape(&src
, &p
, LADISH_ESCAPE_FLAG_ALL
);
741 *filename_ptr_ptr
= filename_ptr
;
743 if (backup_filename_ptr_ptr
!= NULL
)
745 strcpy(backup_filename_ptr
, filename_ptr
);
746 strcat(backup_filename_ptr
, ".bak");
747 *backup_filename_ptr_ptr
= backup_filename_ptr
;
753 struct ladish_cqueue
* ladish_studio_get_cmd_queue(void)
755 return &g_studio
.cmd_queue
;
758 ladish_virtualizer_handle
ladish_studio_get_virtualizer(void)
760 return g_studio
.virtualizer
;
763 ladish_graph_handle
ladish_studio_get_jack_graph(void)
765 return g_studio
.jack_graph
;
768 ladish_graph_handle
ladish_studio_get_studio_graph(void)
770 return g_studio
.studio_graph
;
773 ladish_app_supervisor_handle
ladish_studio_get_studio_app_supervisor(void)
775 return g_studio
.app_supervisor
;
778 struct ladish_studio_app_supervisor_match_opath_context
781 ladish_app_supervisor_handle supervisor
;
784 #define iterate_context_ptr ((struct ladish_studio_app_supervisor_match_opath_context *)context)
786 static bool ladish_studio_app_supervisor_match_opath(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
788 ASSERT(strcmp(ladish_app_supervisor_get_opath(app_supervisor
), ladish_graph_get_opath(graph
)) == 0);
789 if (strcmp(ladish_app_supervisor_get_opath(app_supervisor
), iterate_context_ptr
->opath
) == 0)
791 ASSERT(iterate_context_ptr
->supervisor
== NULL
);
792 iterate_context_ptr
->supervisor
= app_supervisor
;
793 return false; /* stop iteration */
796 return true; /* continue iteration */
799 #undef iterate_context_ptr
801 ladish_app_supervisor_handle
ladish_studio_find_app_supervisor(const char * opath
)
803 struct ladish_studio_app_supervisor_match_opath_context ctx
;
806 ctx
.supervisor
= NULL
;
807 ladish_studio_iterate_virtual_graphs(&ctx
, ladish_studio_app_supervisor_match_opath
);
808 return ctx
.supervisor
;
811 struct ladish_studio_app_supervisor_match_app_context
814 ladish_app_handle app
;
817 #define iterate_context_ptr ((struct ladish_studio_app_supervisor_match_app_context *)context)
819 static bool ladish_studio_app_supervisor_match_app(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
821 ASSERT(strcmp(ladish_app_supervisor_get_opath(app_supervisor
), ladish_graph_get_opath(graph
)) == 0);
822 ASSERT(iterate_context_ptr
->app
== NULL
);
824 iterate_context_ptr
->app
= ladish_app_supervisor_find_app_by_uuid(app_supervisor
, iterate_context_ptr
->app_uuid
);
825 if (iterate_context_ptr
->app
!= NULL
)
827 return false; /* stop iteration */
830 return true; /* continue iteration */
833 #undef iterate_context_ptr
835 ladish_app_handle
ladish_studio_find_app_by_uuid(const uuid_t app_uuid
)
837 struct ladish_studio_app_supervisor_match_app_context ctx
;
839 uuid_copy(ctx
.app_uuid
, app_uuid
);
841 ladish_studio_iterate_virtual_graphs(&ctx
, ladish_studio_app_supervisor_match_app
);
845 bool ladish_studio_delete(void * call_ptr
, const char * studio_name
)
854 if (!ladish_studio_compose_filename(studio_name
, &filename
, &bak_filename
))
856 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "failed to compose studio filename");
860 log_info("Deleting studio ('%s')", filename
);
862 if (unlink(filename
) != 0)
864 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "unlink(%s) failed: %d (%s)", filename
, errno
, strerror(errno
));
868 /* try to delete the backup file */
869 if (stat(bak_filename
, &st
) == 0)
871 if (unlink(bak_filename
) != 0)
873 /* failing to delete backup file will not case delete command failure */
874 log_error("unlink(%s) failed: %d (%s)", bak_filename
, errno
, strerror(errno
));
888 ladish_studio_iterate_virtual_graphs(
892 ladish_graph_handle graph
,
893 ladish_app_supervisor_handle app_supervisor
))
895 struct list_head
* node_ptr
;
896 ladish_room_handle room
;
897 ladish_app_supervisor_handle room_app_supervisor
;
898 ladish_graph_handle room_graph
;
900 if (!callback(context
, g_studio
.studio_graph
, g_studio
.app_supervisor
))
905 list_for_each(node_ptr
, &g_studio
.rooms
)
907 room
= ladish_room_from_list_node(node_ptr
);
908 room_app_supervisor
= ladish_room_get_app_supervisor(room
);
909 ASSERT(room_app_supervisor
!= NULL
);
910 room_graph
= ladish_room_get_graph(room
);
912 if (!callback(context
, room_graph
, room_app_supervisor
))
922 ladish_studio_iterate_rooms(
926 ladish_room_handle room
))
928 struct list_head
* node_ptr
;
929 ladish_room_handle room
;
931 list_for_each(node_ptr
, &g_studio
.rooms
)
933 room
= ladish_room_from_list_node(node_ptr
);
934 if (!callback(context
, room
))
943 bool ladish_studio_has_rooms(void)
945 return !list_empty(&g_studio
.rooms
);
948 static bool ladish_studio_stop_app_supervisor(void * context
, ladish_graph_handle graph
, ladish_app_supervisor_handle app_supervisor
)
950 ladish_app_supervisor_stop(app_supervisor
);
951 return true; /* iterate all supervisors */
954 void ladish_studio_stop_app_supervisors(void)
956 ladish_studio_iterate_virtual_graphs(NULL
, ladish_studio_stop_app_supervisor
);
959 void ladish_studio_emit_renamed(void)
961 dbus_signal_emit(cdbus_g_dbus_connection
, STUDIO_OBJECT_PATH
, IFACE_STUDIO
, "StudioRenamed", "s", &g_studio
.name
);
964 unsigned int ladish_studio_get_room_index(void)
966 return ++g_studio
.room_count
;
969 void ladish_studio_release_room_index(unsigned int index
)
971 if (index
== g_studio
.room_count
)
973 g_studio
.room_count
--;
977 void ladish_studio_remove_all_rooms(void)
979 while (!list_empty(&g_studio
.rooms
))
981 ladish_room_destroy(ladish_room_from_list_node(g_studio
.rooms
.next
));
985 ladish_room_handle
ladish_studio_find_room_by_uuid(const uuid_t room_uuid_ptr
)
987 struct list_head
* node_ptr
;
988 ladish_room_handle room
;
991 list_for_each(node_ptr
, &g_studio
.rooms
)
993 room
= ladish_room_from_list_node(node_ptr
);
994 ladish_room_get_uuid(room
, room_uuid
);
995 if (uuid_compare(room_uuid
, room_uuid_ptr
) == 0)
1004 bool ladish_studio_check_room_name(const char * room_name
)
1006 struct list_head
* node_ptr
;
1007 ladish_room_handle room
;
1009 list_for_each(node_ptr
, &g_studio
.rooms
)
1011 room
= ladish_room_from_list_node(node_ptr
);
1012 if (strcmp(ladish_room_get_name(room
), room_name
) == 0)
1021 /**********************************************************************************/
1023 /**********************************************************************************/
1025 static void ladish_studio_dbus_get_name(struct dbus_method_call
* call_ptr
)
1027 method_return_new_single(call_ptr
, DBUS_TYPE_STRING
, &g_studio
.name
);
1030 static void ladish_studio_dbus_rename(struct dbus_method_call
* call_ptr
)
1032 const char * new_name
;
1033 char * new_name_dup
;
1035 if (!dbus_message_get_args(call_ptr
->message
, &cdbus_g_dbus_error
, DBUS_TYPE_STRING
, &new_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
, cdbus_g_dbus_error
.message
);
1038 dbus_error_free(&cdbus_g_dbus_error
);
1042 log_info("Rename studio request (%s)", new_name
);
1044 new_name_dup
= strdup(new_name
);
1045 if (new_name_dup
== NULL
)
1047 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup() failed to allocate new name.");
1051 free(g_studio
.name
);
1052 g_studio
.name
= new_name_dup
;
1054 method_return_new_void(call_ptr
);
1055 ladish_studio_emit_renamed();
1058 static void ladish_studio_dbus_save(struct dbus_method_call
* call_ptr
)
1060 log_info("Save studio request");
1062 if (ladish_command_save_studio(call_ptr
, &g_studio
.cmd_queue
, g_studio
.name
))
1064 method_return_new_void(call_ptr
);
1068 static void ladish_studio_dbus_save_as(struct dbus_method_call
* call_ptr
)
1070 const char * new_name
;
1072 log_info("SaveAs studio request");
1074 if (!dbus_message_get_args(call_ptr
->message
, &cdbus_g_dbus_error
, DBUS_TYPE_STRING
, &new_name
, DBUS_TYPE_INVALID
))
1076 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, cdbus_g_dbus_error
.message
);
1077 dbus_error_free(&cdbus_g_dbus_error
);
1081 if (ladish_command_save_studio(call_ptr
, &g_studio
.cmd_queue
, new_name
))
1083 method_return_new_void(call_ptr
);
1087 static void ladish_studio_dbus_unload(struct dbus_method_call
* call_ptr
)
1089 log_info("Unload studio request");
1091 if (ladish_command_unload_studio(call_ptr
, &g_studio
.cmd_queue
))
1093 method_return_new_void(call_ptr
);
1097 static void ladish_studio_dbus_stop(struct dbus_method_call
* call_ptr
)
1099 log_info("Stop studio request");
1101 g_studio
.automatic
= false; /* even if it was automatic, it is not anymore because user knows about it */
1103 if (ladish_command_stop_studio(call_ptr
, &g_studio
.cmd_queue
))
1105 method_return_new_void(call_ptr
);
1109 static void ladish_studio_dbus_start(struct dbus_method_call
* call_ptr
)
1111 log_info("Start studio request");
1113 g_studio
.automatic
= false; /* even if it was automatic, it is not anymore because user knows about it */
1115 if (ladish_command_start_studio(call_ptr
, &g_studio
.cmd_queue
))
1117 method_return_new_void(call_ptr
);
1121 static void ladish_studio_dbus_is_started(struct dbus_method_call
* call_ptr
)
1123 dbus_bool_t started
;
1125 started
= g_studio
.jack_graph_proxy
!= NULL
;
1127 method_return_new_single(call_ptr
, DBUS_TYPE_BOOLEAN
, &started
);
1130 static void ladish_studio_dbus_create_room(struct dbus_method_call
* call_ptr
)
1132 const char * room_name
;
1133 const char * template_name
;
1135 dbus_error_init(&cdbus_g_dbus_error
);
1137 if (!dbus_message_get_args(call_ptr
->message
, &cdbus_g_dbus_error
, DBUS_TYPE_STRING
, &room_name
, DBUS_TYPE_STRING
, &template_name
, DBUS_TYPE_INVALID
))
1139 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, cdbus_g_dbus_error
.message
);
1140 dbus_error_free(&cdbus_g_dbus_error
);
1144 if (ladish_command_create_room(call_ptr
, ladish_studio_get_cmd_queue(), room_name
, template_name
))
1146 method_return_new_void(call_ptr
);
1150 static void ladish_studio_dbus_get_room_list(struct dbus_method_call
* call_ptr
)
1152 DBusMessageIter iter
, array_iter
;
1153 DBusMessageIter struct_iter
;
1154 struct list_head
* node_ptr
;
1155 ladish_room_handle room
;
1157 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
1158 if (call_ptr
->reply
== NULL
)
1163 dbus_message_iter_init_append(call_ptr
->reply
, &iter
);
1165 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(sa{sv})", &array_iter
))
1170 list_for_each(node_ptr
, &g_studio
.rooms
)
1172 room
= ladish_room_from_list_node(node_ptr
);
1174 if (!dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
))
1177 if (!ladish_studio_fill_room_info(&struct_iter
, room
))
1180 if (!dbus_message_iter_close_container(&array_iter
, &struct_iter
))
1184 if (!dbus_message_iter_close_container(&iter
, &array_iter
))
1192 dbus_message_unref(call_ptr
->reply
);
1193 call_ptr
->reply
= NULL
;
1196 log_error("Ran out of memory trying to construct method return");
1199 static void ladish_studio_dbus_delete_room(struct dbus_method_call
* call_ptr
)
1203 dbus_error_init(&cdbus_g_dbus_error
);
1205 if (!dbus_message_get_args(call_ptr
->message
, &cdbus_g_dbus_error
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
))
1207 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\": %s", call_ptr
->method_name
, cdbus_g_dbus_error
.message
);
1208 dbus_error_free(&cdbus_g_dbus_error
);
1212 if (ladish_command_delete_room(call_ptr
, ladish_studio_get_cmd_queue(), name
))
1214 method_return_new_void(call_ptr
);
1218 METHOD_ARGS_BEGIN(GetName
, "Get studio name")
1219 METHOD_ARG_DESCRIBE_OUT("studio_name", "s", "Name of studio")
1222 METHOD_ARGS_BEGIN(Rename
, "Rename studio")
1223 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1226 METHOD_ARGS_BEGIN(Save
, "Save studio")
1229 METHOD_ARGS_BEGIN(SaveAs
, "SaveAs studio")
1230 METHOD_ARG_DESCRIBE_IN("studio_name", "s", "New name")
1233 METHOD_ARGS_BEGIN(Unload
, "Unload studio")
1236 METHOD_ARGS_BEGIN(Start
, "Start studio")
1239 METHOD_ARGS_BEGIN(Stop
, "Stop studio")
1242 METHOD_ARGS_BEGIN(IsStarted
, "Check whether studio is started")
1243 METHOD_ARG_DESCRIBE_OUT("started", "b", "Whether studio is started")
1246 METHOD_ARGS_BEGIN(CreateRoom
, "Create new studio room")
1247 METHOD_ARG_DESCRIBE_IN("room_name", "s", "Studio room name")
1248 METHOD_ARG_DESCRIBE_IN("room_template_name", "s", "Room template name")
1251 METHOD_ARGS_BEGIN(GetRoomList
, "Get list of rooms in this studio")
1252 METHOD_ARG_DESCRIBE_OUT("room_list", "a(sa{sv})", "List of studio rooms: opaths and properties")
1255 METHOD_ARGS_BEGIN(DeleteRoom
, "Delete studio room")
1256 METHOD_ARG_DESCRIBE_IN("room_name", "s", "Name of studio room to delete")
1260 METHOD_DESCRIBE(GetName
, ladish_studio_dbus_get_name
) /* sync */
1261 METHOD_DESCRIBE(Rename
, ladish_studio_dbus_rename
) /* sync */
1262 METHOD_DESCRIBE(Save
, ladish_studio_dbus_save
) /* async */
1263 METHOD_DESCRIBE(SaveAs
, ladish_studio_dbus_save_as
) /* async */
1264 METHOD_DESCRIBE(Unload
, ladish_studio_dbus_unload
) /* async */
1265 METHOD_DESCRIBE(Start
, ladish_studio_dbus_start
) /* async */
1266 METHOD_DESCRIBE(Stop
, ladish_studio_dbus_stop
) /* async */
1267 METHOD_DESCRIBE(IsStarted
, ladish_studio_dbus_is_started
) /* sync */
1268 METHOD_DESCRIBE(CreateRoom
, ladish_studio_dbus_create_room
) /* async */
1269 METHOD_DESCRIBE(GetRoomList
, ladish_studio_dbus_get_room_list
) /* sync */
1270 METHOD_DESCRIBE(DeleteRoom
, ladish_studio_dbus_delete_room
) /* async */
1273 SIGNAL_ARGS_BEGIN(StudioRenamed
, "Studio name changed")
1274 SIGNAL_ARG_DESCRIBE("studio_name", "s", "New studio name")
1277 SIGNAL_ARGS_BEGIN(StudioStarted
, "Studio started")
1280 SIGNAL_ARGS_BEGIN(StudioCrashed
, "Studio crashed")
1283 SIGNAL_ARGS_BEGIN(StudioStopped
, "Studio stopped")
1286 SIGNAL_ARGS_BEGIN(RoomAppeared
, "Room D-Bus object appeared")
1287 SIGNAL_ARG_DESCRIBE("opath", "s", "room object path")
1288 SIGNAL_ARG_DESCRIBE("properties", "a{sv}", "room properties")
1291 SIGNAL_ARGS_BEGIN(RoomChanged
, "Room D-Bus object changed")
1292 SIGNAL_ARG_DESCRIBE("opath", "s", "room object path")
1293 SIGNAL_ARG_DESCRIBE("properties", "a{sv}", "room properties")
1296 SIGNAL_ARGS_BEGIN(RoomDisappeared
, "Room D-Bus object disappeared")
1297 SIGNAL_ARG_DESCRIBE("opath", "s", "room object path")
1298 SIGNAL_ARG_DESCRIBE("properties", "a{sv}", "room properties")
1302 SIGNAL_DESCRIBE(StudioRenamed
)
1303 SIGNAL_DESCRIBE(StudioStarted
)
1304 SIGNAL_DESCRIBE(StudioCrashed
)
1305 SIGNAL_DESCRIBE(StudioStopped
)
1306 SIGNAL_DESCRIBE(RoomAppeared
)
1307 SIGNAL_DESCRIBE(RoomDisappeared
)
1308 SIGNAL_DESCRIBE(RoomChanged
)
1311 INTERFACE_BEGIN(g_interface_studio
, IFACE_STUDIO
)
1312 INTERFACE_DEFAULT_HANDLER
1313 INTERFACE_EXPOSE_METHODS
1314 INTERFACE_EXPOSE_SIGNALS