diff --git a/daemon/cmd_change_app_state.c b/daemon/cmd_change_app_state.c index 4b269140..eaa8daa4 100644 --- a/daemon/cmd_change_app_state.c +++ b/daemon/cmd_change_app_state.c @@ -29,6 +29,7 @@ #include "studio.h" #include "../dbus/error.h" #include "../proxies/notify_proxy.h" +#include "virtualizer.h" struct ladish_command_change_app_state { @@ -36,11 +37,15 @@ struct ladish_command_change_app_state char * opath; uint64_t id; unsigned int target_state; + const char * target_state_description; + bool (* run_target)(struct ladish_command_change_app_state *, ladish_app_supervisor_handle, ladish_app_handle); + void (* initiate_stop)(ladish_app_supervisor_handle supervisor, ladish_app_handle app); }; static bool run_target_start(struct ladish_command_change_app_state * cmd_ptr, ladish_app_supervisor_handle supervisor, ladish_app_handle app) { ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING); + ASSERT(cmd_ptr->initiate_stop == NULL); if (!ladish_studio_is_started()) { @@ -68,49 +73,38 @@ static bool run_target_start(struct ladish_command_change_app_state * cmd_ptr, l static bool run_target_stop(struct ladish_command_change_app_state * cmd_ptr, ladish_app_supervisor_handle supervisor, ladish_app_handle app) { - if (!ladish_app_is_running(app)) + const char * app_name; + + ASSERT(cmd_ptr->initiate_stop != NULL); + + app_name = ladish_app_get_name(app); + + if (ladish_app_is_running(app)) { if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) { - log_info("App %s is already stopped (stop)", ladish_app_get_name(app)); + cmd_ptr->initiate_stop(supervisor, app); + cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING; + return true; } - cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + + ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_WAITING); + log_info("Waiting '%s' process termination (%s)...", app_name, cmd_ptr->target_state_description); + return true; + } + + if (!ladish_virtualizer_is_hidden_app(ladish_studio_get_virtualizer(), app_name)) + { + log_info("Waiting '%s' client disappear (%s)...", app_name, cmd_ptr->target_state_description); return true; } if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) { - ladish_app_supervisor_stop_app(supervisor, app); - cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING; - return true; + log_info("App %s is already stopped (%s)", app_name, cmd_ptr->target_state_description); } - log_info("Waiting '%s' process termination (stop)...", ladish_app_get_name(app)); - - return true; -} - -static bool run_target_kill(struct ladish_command_change_app_state * cmd_ptr, ladish_app_supervisor_handle supervisor, ladish_app_handle app) -{ - if (!ladish_app_is_running(app)) - { - if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) - { - log_info("App %s is already stopped (kill)", ladish_app_get_name(app)); - } - cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; - return true; - } - - if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) - { - ladish_app_supervisor_kill_app(supervisor, app); - cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING; - return true; - } - - log_info("Waiting '%s' process termination(kill)...", ladish_app_get_name(app)); - + cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; return true; } @@ -120,37 +114,16 @@ static bool run(void * context) { ladish_app_supervisor_handle supervisor; ladish_app_handle app; - const char * target_state_description; - bool (* run_target)(struct ladish_command_change_app_state *, ladish_app_supervisor_handle, ladish_app_handle); - - switch (cmd_ptr->target_state) - { - case LADISH_APP_STATE_STARTED: - target_state_description = "start"; - run_target = run_target_start; - break; - case LADISH_APP_STATE_STOPPED: - target_state_description = "stopped"; - run_target = run_target_stop; - break; - case LADISH_APP_STATE_KILL: - target_state_description = "kill"; - run_target = run_target_kill; - break; - default: - ASSERT_NO_PASS; - return false; - } if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) { - log_info("%s app command. opath='%s'", target_state_description, cmd_ptr->opath); + log_info("%s app command. opath='%s'", cmd_ptr->target_state_description, cmd_ptr->opath); } supervisor = ladish_studio_find_app_supervisor(cmd_ptr->opath); if (supervisor == NULL) { - log_error("cannot find supervisor '%s' to %s app", cmd_ptr->opath, target_state_description); + log_error("cannot find supervisor '%s' to %s app", cmd_ptr->opath, cmd_ptr->target_state_description); ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Cannot change app state because of internal error (unknown supervisor)", NULL); return false; } @@ -158,12 +131,12 @@ static bool run(void * context) app = ladish_app_supervisor_find_app_by_id(supervisor, cmd_ptr->id); if (app == NULL) { - log_error("App with ID %"PRIu64" not found (%s)", cmd_ptr->id, target_state_description); + log_error("App with ID %"PRIu64" not found (%s)", cmd_ptr->id, cmd_ptr->target_state_description); ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Cannot change app state because it is not found", NULL); return false; } - return run_target(cmd_ptr, supervisor, app); + return cmd_ptr->run_target(cmd_ptr, supervisor, app); } static void destructor(void * context) @@ -199,6 +172,29 @@ bool ladish_command_change_app_state(void * call_ptr, struct ladish_cqueue * que cmd_ptr->id = id; cmd_ptr->target_state = target_state; + switch (target_state) + { + case LADISH_APP_STATE_STARTED: + cmd_ptr->target_state_description = "start"; + cmd_ptr->run_target = run_target_start; + cmd_ptr->initiate_stop = NULL; + break; + case LADISH_APP_STATE_STOPPED: + cmd_ptr->target_state_description = "stop"; + cmd_ptr->run_target = run_target_stop; + cmd_ptr->initiate_stop = ladish_app_supervisor_stop_app; + break; + case LADISH_APP_STATE_KILL: + cmd_ptr->target_state_description = "kill"; + cmd_ptr->run_target = run_target_stop; + cmd_ptr->initiate_stop = ladish_app_supervisor_kill_app; + break; + default: + ASSERT_NO_PASS; + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Invalid target state (internal error).", opath); + goto fail_destroy_command; + } + if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command)) { lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed."); diff --git a/daemon/graph.c b/daemon/graph.c index ffcc2c2c..b3570d0a 100644 --- a/daemon/graph.c +++ b/daemon/graph.c @@ -1910,6 +1910,20 @@ bool ladish_graph_client_looks_empty(ladish_graph_handle graph_handle, ladish_cl return false; } +bool ladish_graph_client_is_hidden(ladish_graph_handle graph_handle, ladish_client_handle client_handle) +{ + struct ladish_graph_client * client_ptr; + + client_ptr = ladish_graph_find_client(graph_ptr, client_handle); + if (client_ptr != NULL) + { + return client_ptr->hidden; + } + + ASSERT_NO_PASS; + return true; +} + void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle) { struct list_head * node_ptr; diff --git a/daemon/graph.h b/daemon/graph.h index 4d6b7936..59cbd743 100644 --- a/daemon/graph.h +++ b/daemon/graph.h @@ -148,6 +148,7 @@ const char * ladish_graph_get_client_name(ladish_graph_handle graph_handle, ladi const char * ladish_graph_get_port_name(ladish_graph_handle graph, ladish_port_handle port); bool ladish_graph_client_is_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle); bool ladish_graph_client_looks_empty(ladish_graph_handle graph_handle, ladish_client_handle client_handle); +bool ladish_graph_client_is_hidden(ladish_graph_handle graph_handle, ladish_client_handle client_handle); bool ladish_graph_is_port_present(ladish_graph_handle graph_handle, ladish_port_handle port_handle); void ladish_graph_show_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle); void ladish_graph_hide_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle); diff --git a/daemon/studio.c b/daemon/studio.c index 7d4ace9c..0db58775 100644 --- a/daemon/studio.c +++ b/daemon/studio.c @@ -649,6 +649,11 @@ struct ladish_cqueue * ladish_studio_get_cmd_queue(void) return &g_studio.cmd_queue; } +ladish_virtualizer_handle ladish_studio_get_virtualizer(void) +{ + return g_studio.virtualizer; +} + struct ladish_studio_app_supervisor_match_context { const char * opath; diff --git a/daemon/studio.h b/daemon/studio.h index d7010834..b91d0c58 100644 --- a/daemon/studio.h +++ b/daemon/studio.h @@ -30,6 +30,7 @@ #include "app_supervisor.h" #include "graph.h" #include "room.h" +#include "virtualizer.h" bool ladish_studio_init(void); void ladish_studio_uninit(void); @@ -53,6 +54,7 @@ ladish_studio_iterate_virtual_graphs( void ladish_studio_stop_app_supervisors(void); ladish_app_supervisor_handle ladish_studio_find_app_supervisor(const char * opath); struct ladish_cqueue * ladish_studio_get_cmd_queue(void); +ladish_virtualizer_handle ladish_studio_get_virtualizer(void); void ladish_studio_emit_room_appeared(ladish_room_handle room); void ladish_studio_emit_room_disappeared(ladish_room_handle room); diff --git a/daemon/virtualizer.c b/daemon/virtualizer.c index 10b43e74..ed4381ba 100644 --- a/daemon/virtualizer.c +++ b/daemon/virtualizer.c @@ -1035,6 +1035,113 @@ ladish_virtualizer_get_our_clients_count( return virtualizer_ptr->our_clients_count; } +bool +ladish_virtualizer_is_hidden_app( + ladish_virtualizer_handle handle, + const char * app_name) +{ + ladish_client_handle jclient; + ladish_graph_handle vgraph; + uuid_t vclient_uuid; + ladish_client_handle vclient; + + //ladish_graph_dump(g_studio.jack_graph); + + jclient = ladish_graph_find_client_by_name(virtualizer_ptr->jack_graph, app_name); + if (jclient == NULL) + { + ASSERT_NO_PASS; + return true; + } + + vgraph = ladish_client_get_vgraph(jclient); + if (vgraph == NULL) + { + ASSERT_NO_PASS; + return true; + } + + //ladish_graph_dump(vgraph); + + if (!ladish_graph_client_looks_empty(virtualizer_ptr->jack_graph, jclient) || + !ladish_graph_client_is_hidden(virtualizer_ptr->jack_graph, jclient)) + { + return false; + } + + if (!ladish_client_get_interlink(jclient, vclient_uuid)) + { + log_error("jack client of app '%s' has no interlinked vgraph client", app_name); + ASSERT_NO_PASS; + return true; + } + + vclient = ladish_graph_find_client_by_uuid(vgraph, vclient_uuid); + if (vclient == NULL) + { + ASSERT_NO_PASS; + return true; + } + + if (!ladish_graph_client_looks_empty(vgraph, vclient)) + { + return false; + } + + ASSERT(ladish_graph_client_is_hidden(vgraph, vclient)); /* vclients are automatically hidden when they start looking empty (on port disappear) */ + return true; +} + +void +ladish_virtualizer_remove_app( + ladish_virtualizer_handle handle, + const char * app_name) +{ + ladish_client_handle jclient; + ladish_graph_handle vgraph; + uuid_t vclient_uuid; + ladish_client_handle vclient; + + //ladish_graph_dump(g_studio.jack_graph); + + jclient = ladish_graph_find_client_by_name(virtualizer_ptr->jack_graph, app_name); + if (jclient == NULL) + { + ASSERT_NO_PASS; + return; + } + + vgraph = ladish_client_get_vgraph(jclient); + if (vgraph == NULL) + { + ASSERT_NO_PASS; + return; + } + + //ladish_graph_dump(vgraph); + + ladish_graph_remove_client(virtualizer_ptr->jack_graph, jclient); + if (!ladish_client_get_interlink(jclient, vclient_uuid)) + { + log_error("jack client of app '%s' has no interlinked vgraph client", app_name); + ladish_graph_dump(g_studio.jack_graph); + ladish_graph_dump(vgraph); + ASSERT_NO_PASS; + return; + } + + vclient = ladish_graph_find_client_by_uuid(vgraph, vclient_uuid); + if (vclient == NULL) + { + ASSERT_NO_PASS; + return; + } + + ladish_graph_remove_client(vgraph, vclient); + ladish_graph_dump(g_studio.jack_graph); + ladish_graph_dump(vgraph); +} + void ladish_virtualizer_destroy( ladish_virtualizer_handle handle) diff --git a/daemon/virtualizer.h b/daemon/virtualizer.h index 3d4357b0..eb4b5d1b 100644 --- a/daemon/virtualizer.h +++ b/daemon/virtualizer.h @@ -48,6 +48,16 @@ unsigned int ladish_virtualizer_get_our_clients_count( ladish_virtualizer_handle handle); +bool +ladish_virtualizer_is_hidden_app( + ladish_virtualizer_handle handle, + const char * app_name); + +void +ladish_virtualizer_remove_app( + ladish_virtualizer_handle handle, + const char * app_name); + void ladish_virtualizer_destroy( ladish_virtualizer_handle handle);