From ffbede3137d3d2dda97293dff1d0b17b8c4de8f1 Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Tue, 8 May 2018 18:54:55 +0900 Subject: [PATCH 01/16] Destroy cmd list after use Change-Id: I3c2473cde20de094eafff87b4406ccaae015714d Signed-off-by: Wonnam Jang --- server/vcd_server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/vcd_server.c b/server/vcd_server.c index 5ac1869..baee35e 100644 --- a/server/vcd_server.c +++ b/server/vcd_server.c @@ -751,11 +751,12 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c // There are more than one result. if (false == vcd_client_manager_get_exclusive()) { + vc_cmd_list_h temp_list = NULL; + /* Foreground, Widget, Background, System, System-Background */ if (top_priority >= VC_COMMAND_PRIORITY_BACKGROUND) { vc_cmd_list_h widget_cmd_list = NULL; vc_cmd_list_h foreground_cmd_list = NULL; - vc_cmd_list_h temp_list = NULL; int cnt = 0; if (0 != vc_cmd_list_create(&temp_list)) { @@ -815,7 +816,6 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_destroy(foreground_cmd_list, true); } vc_cmd_list_destroy(widget_cmd_list, true); - vc_cmd_list_destroy(temp_list, true); } int pid = vcd_client_widget_get_foreground_pid(); @@ -825,6 +825,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c } vc_info_parser_set_result(all_result, event, msg, vc_cmd_list, false); + vc_cmd_list_destroy(vc_cmd_list, true); if (-1 != vcd_client_manager_get_pid()) { /* Manager client is available */ @@ -838,6 +839,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c } else { /* exclusive command */ vc_info_parser_set_result(all_result, event, msg, vc_cmd_list, true); + vc_cmd_list_destroy(vc_cmd_list, true); if (-1 != vcd_client_manager_get_pid()) { /* Manager client is available */ @@ -851,8 +853,6 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vcd_client_manager_set_exclusive(false); } - vc_cmd_list_destroy(vc_cmd_list, true); - if (VCD_RECOGNITION_MODE_RESTART_AFTER_REJECT == recognition_mode) { if (VCE_RESULT_EVENT_REJECTED == event) { SLOG(LOG_DEBUG, TAG_VCD, "[Server] Restart by no or rejected result"); -- 2.7.4 From 7f3e13f65ad8eae50d0c7fde8c4470e210ac913f Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Fri, 18 May 2018 14:18:45 +0900 Subject: [PATCH 02/16] Do not return error when vc feature is disabled Change-Id: I42123b6108212320497f7e2d4a048091fe2f88e6 Signed-off-by: Wonnam Jang --- client/vc_widget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/vc_widget.c b/client/vc_widget.c index 46d68ac..6e5ea93 100644 --- a/client/vc_widget.c +++ b/client/vc_widget.c @@ -152,7 +152,7 @@ int vc_widget_initialize(vc_h* vc_w) if (0 != __vc_widget_get_feature_enabled()) { SLOG(LOG_ERROR, TAG_VCW, "@@@ [Widget] not supported"); - return VC_ERROR_NOT_SUPPORTED; + return VC_ERROR_NONE; } if (NULL == vc_w) { @@ -370,7 +370,7 @@ static Eina_Bool __vc_widget_connect_daemon(void *data) ecore_main_loop_thread_safe_call_async(__vc_widget_notify_error, vc_w); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return EINA_FALSE; + return EINA_TRUE; } vc_widget_client_set_service_state(vc_w, (vc_service_state_e)service_state); -- 2.7.4 From 60e86d06347726c1516f2d16281ac9e152236b6c Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Mon, 21 May 2018 11:02:31 +0900 Subject: [PATCH 03/16] No error when pid is already added on vc server Change-Id: I5ec883ede970b65d77555ebb40070cf269bc6bbb Signed-off-by: Wonnam Jang --- server/vcd_server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/vcd_server.c b/server/vcd_server.c index baee35e..0a9b9e9 100644 --- a/server/vcd_server.c +++ b/server/vcd_server.c @@ -2090,8 +2090,8 @@ int vcd_server_initialize(int pid) /* check if pid is valid */ if (true == vcd_client_is_available(pid)) { - SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] The pid is already exist"); - return VCD_ERROR_INVALID_PARAMETER; + SLOG(LOG_WARN, TAG_VCD, "[Server WARNING] The pid is already exist"); + return VCD_ERROR_NONE; } /* Add client information to client manager */ -- 2.7.4 From f1b1491ea447fa6e881dd80c98a1eec0f220ba61 Mon Sep 17 00:00:00 2001 From: sungrae jo Date: Mon, 21 May 2018 18:59:29 +0900 Subject: [PATCH 04/16] Remove daemon reset for web TC Change-Id: I9b815897b8c98101c27daf2cddd0addbab54e01b Signed-off-by: sungrae jo --- client/vc_dbus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/vc_dbus.c b/client/vc_dbus.c index cab1bcb..51714b3 100644 --- a/client/vc_dbus.c +++ b/client/vc_dbus.c @@ -170,7 +170,8 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle SLOG(LOG_ERROR, TAG_VCC, "Match Error (%s)", err.message); dbus_error_free(&err); } - __vc_cb_error(VC_ERROR_SERVICE_RESET, -1, "Daemon Reset"); + //FIXME + //__vc_cb_error(VC_ERROR_SERVICE_RESET, -1, "Daemon Reset"); SLOG(LOG_DEBUG, TAG_VCC, "@@@"); } /* NameOwnerChanged */ -- 2.7.4 From 01776134e70dac60ab9c2b20d8c52ccadb49b9c9 Mon Sep 17 00:00:00 2001 From: sungrae jo Date: Mon, 21 May 2018 21:48:18 +0900 Subject: [PATCH 05/16] Fixed thread unsafe bug when deinitialize as soon as initialize Change-Id: Ia8a615696212f69472e915c4489dd8a86331db70 Signed-off-by: sungrae jo --- client/vc_widget.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/client/vc_widget.c b/client/vc_widget.c index 6e5ea93..ea0d2cf 100644 --- a/client/vc_widget.c +++ b/client/vc_widget.c @@ -262,6 +262,21 @@ int vc_widget_deinitialize(vc_h vc_w) return VC_ERROR_INVALID_STATE; } + + int thread_count = ecore_thread_active_get(); + int count = 0; + while (0 < thread_count) { + usleep(50000); + count++; + if (100 == count) { + SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is blocked, cnt(%d), thread count(%d)", count, thread_count); + break; + } else if (0 == count % 5) { + SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is alive, cnt(%d), thread count(%d)", count, thread_count); + } + thread_count = ecore_thread_active_get(); + } + vc_state_e state; vc_widget_client_get_state(vc_w, &state); vc_widget_s* widget = widget_get(vc_w); @@ -338,7 +353,7 @@ static Eina_Bool __focus_changed_cb(void *data, int type, void *event) return ECORE_CALLBACK_RENEW; } -static Eina_Bool __vc_widget_connect_daemon(void *data) +static void __vc_widget_connect_daemon(void *data) { vc_h vc_w = (vc_h)data; @@ -359,7 +374,7 @@ static Eina_Bool __vc_widget_connect_daemon(void *data) ecore_main_loop_thread_safe_call_async(__vc_widget_notify_error, vc_w); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return EINA_FALSE; + return; } else if (VC_ERROR_INVALID_PARAMETER == ret) { SLOG(LOG_WARN, TAG_VCW, "[WARNING] Invalid Parameter"); @@ -370,19 +385,17 @@ static Eina_Bool __vc_widget_connect_daemon(void *data) ecore_main_loop_thread_safe_call_async(__vc_widget_notify_error, vc_w); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return EINA_TRUE; + return; } vc_widget_client_set_service_state(vc_w, (vc_service_state_e)service_state); SLOG(LOG_INFO, TAG_VCW, "@@@ [Widget] Connect daemon"); - ecore_thread_main_loop_begin(); if (NULL == g_focus_in_handler) g_focus_in_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, __focus_changed_cb, NULL); if (NULL == g_focus_out_handler) g_focus_out_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, __focus_changed_cb, NULL); - ecore_thread_main_loop_end(); char appid[1024] = {'\0',}; aul_app_get_appid_bypid(getpid(), appid, sizeof(appid) - 1); @@ -419,7 +432,7 @@ static Eina_Bool __vc_widget_connect_daemon(void *data) SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return EINA_FALSE; + return; } static void __start_prepare_thread(void *data, Ecore_Thread *thread) @@ -444,6 +457,7 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread) } } +#if 0 ret = -1; retry_count = 0; while (0 != ret) { @@ -457,6 +471,9 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread) else retry_count++; } +#endif + + ecore_main_loop_thread_safe_call_async(__vc_widget_connect_daemon, vc_w); return; } -- 2.7.4 From b1521796d5d40d5270ea973cff9e7b2d2feaefef Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Wed, 23 May 2018 16:10:03 +0900 Subject: [PATCH 06/16] Move 'dbus_bus_add_match' to vc_dbus_request_initialize Change-Id: I8e446a807b7919f37878e70154661a35e961e23a Signed-off-by: sooyeon.kim --- client/vc.c | 1 + client/vc_dbus.c | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/vc.c b/client/vc.c index b3c9b24..9a893f3 100644 --- a/client/vc.c +++ b/client/vc.c @@ -1631,6 +1631,7 @@ int __vc_cb_error(int reason, int daemon_pid, char* msg) /* check state */ if (state != VC_STATE_READY) { + SLOG(LOG_DEBUG, TAG_VCC, "[DEBUG] State is not READY"); if (VC_ERROR_SERVICE_RESET != reason) { SLOG(LOG_ERROR, TAG_VCC, "[ERROR] not connected client yet"); return -1; diff --git a/client/vc_dbus.c b/client/vc_dbus.c index 51714b3..186d259 100644 --- a/client/vc_dbus.c +++ b/client/vc_dbus.c @@ -170,8 +170,8 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle SLOG(LOG_ERROR, TAG_VCC, "Match Error (%s)", err.message); dbus_error_free(&err); } - //FIXME - //__vc_cb_error(VC_ERROR_SERVICE_RESET, -1, "Daemon Reset"); + + __vc_cb_error(VC_ERROR_SERVICE_RESET, -1, "Daemon Reset"); SLOG(LOG_DEBUG, TAG_VCC, "@@@"); } /* NameOwnerChanged */ @@ -286,17 +286,6 @@ int vc_dbus_open_connection() return VC_ERROR_OPERATION_FAILED; } - /* add a rule for daemon error */ - snprintf(rule, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", VC_SERVER_SERVICE_INTERFACE); - dbus_bus_add_match(g_conn_listener, rule, &err); - - if (dbus_error_is_set(&err)) { - SLOG(LOG_ERROR, TAG_VCC, "Match Error (%s)", err.message); - dbus_error_free(&err); - __vc_dbus_connection_free(); - return VC_ERROR_OPERATION_FAILED; - } - int fd = 0; if (1 != dbus_connection_get_unix_fd(g_conn_listener, &fd)) { SLOG(LOG_ERROR, TAG_VCC, "fail to get fd from dbus "); @@ -496,6 +485,16 @@ int vc_dbus_request_initialize(int pid, int* mgr_pid, int* service_state, int* d *service_state = tmp_service_state; *daemon_pid = tmp_daemon_pid; + /* add a rule for daemon error */ + char rule[256] = {0, }; + snprintf(rule, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", VC_SERVER_SERVICE_INTERFACE); + dbus_bus_add_match(g_conn_listener, rule, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCC, "Match Error (%s)", err.message); + dbus_error_free(&err); + } + SLOG(LOG_DEBUG, TAG_VCC, "@@ vc initialize : result = %d mgr = %d service = %d daemon_pid = %d", result, *mgr_pid, *service_state, *daemon_pid); } else { SLOG(LOG_ERROR, TAG_VCC, "@@ vc initialize : result = %d", result); -- 2.7.4 From 6a3d144029eb9b73afaeca49f1fdea6ffb4ec16f Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Thu, 24 May 2018 08:40:00 +0900 Subject: [PATCH 07/16] Fix coverity issues Change-Id: I46e33c4e2d2425055c5a0540575f56e828654ce4 Signed-off-by: Wonnam Jang --- client/vc_mgr_dbus.c | 6 +++--- common/vc_cmd_db.c | 26 +++++++++++++++++--------- server/vcd_dbus.c | 36 ++++++++++++++++++++++++++++-------- server/vcd_recorder.c | 8 ++++---- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/client/vc_mgr_dbus.c b/client/vc_mgr_dbus.c index 2277fa9..0935452 100644 --- a/client/vc_mgr_dbus.c +++ b/client/vc_mgr_dbus.c @@ -286,12 +286,12 @@ static Eina_Bool vc_mgr_listener_event_callback(void* data, Ecore_Fd_Handler *fd int pid = 0; int ret = -1; char* key = NULL; - char* data = NULL; + char* private_data = NULL; dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &pid, DBUS_TYPE_STRING, &key, - DBUS_TYPE_STRING, &data, + DBUS_TYPE_STRING, &private_data, DBUS_TYPE_INVALID); if (dbus_error_is_set(&err)) { @@ -301,7 +301,7 @@ static Eina_Bool vc_mgr_listener_event_callback(void* data, Ecore_Fd_Handler *fd if (pid > 0) { SLOG(LOG_DEBUG, TAG_VCM, "@@ vc mgr get request set private data : pid(%d) ", pid); - ret = __vc_mgr_cb_private_data_set(key, data); + ret = __vc_mgr_cb_private_data_set(key, private_data); } else { SLOG(LOG_ERROR, TAG_VCM, "@@ vc mgr get requset set private data : invalid pid "); } diff --git a/common/vc_cmd_db.c b/common/vc_cmd_db.c index 7c74a97..928dfac 100644 --- a/common/vc_cmd_db.c +++ b/common/vc_cmd_db.c @@ -692,6 +692,10 @@ static int __vc_db_extract_unfixed_command(char* command, char* fixed, char** te } char* temp = (char*)calloc(256, sizeof(char)); + if (NULL == temp) { + SLOG(LOG_ERROR, vc_db_tag(), "[ERROR] Fail to allocate memory"); + return VC_DB_ERROR_OUT_OF_MEMORY; + } if (0 == strncasecmp(command, fixed, strlen(fixed))) { strncpy(temp, command + strlen(fixed) + 1, strlen(command) - strlen(fixed) - 1); SLOG(LOG_WARN, vc_db_tag(), "@@@"); @@ -1610,17 +1614,21 @@ static int __vc_db_generate_command(vc_cmd_s* cmd, char** fixed_cmd, GSList** cm // extract fixed command and remove space in front of '{' char *tok_ptr = NULL; temp = strtok_r(src_cmd, "{", &tok_ptr); - __vc_db_remove_space(&temp); - *fixed_cmd = strdup(temp); - - // merge command with fixed and vfixed - while (NULL != (temp = strtok_r(NULL, "|", &tok_ptr))) { + if (NULL != temp) { __vc_db_remove_space(&temp); + *fixed_cmd = strdup(temp); - snprintf(merge_cmd, 256, "%s %s", *fixed_cmd, temp); - dst_cmd = strdup(merge_cmd); - temp_list = g_slist_append(temp_list, dst_cmd); - SLOG(LOG_ERROR, vc_db_tag(), "New generated cmd: %s", dst_cmd); + // merge command with fixed and vfixed + while (NULL != (temp = strtok_r(NULL, "|", &tok_ptr))) { + __vc_db_remove_space(&temp); + + snprintf(merge_cmd, 256, "%s %s", *fixed_cmd, temp); + dst_cmd = strdup(merge_cmd); + temp_list = g_slist_append(temp_list, dst_cmd); + SLOG(LOG_ERROR, vc_db_tag(), "New generated cmd: %s", dst_cmd); + } + } else { + *fixed_cmd = strdup(cmd->command); } } else if (VC_CMD_FORMAT_VFIXED_AND_FIXED == cmd->format) { // check string validation diff --git a/server/vcd_dbus.c b/server/vcd_dbus.c index 5d37055..250e5a0 100755 --- a/server/vcd_dbus.c +++ b/server/vcd_dbus.c @@ -1049,6 +1049,20 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle return ECORE_CALLBACK_RENEW; } +static void __vcd_dbus_connection_free() +{ + if (NULL != g_conn_listener) { + dbus_connection_close(g_conn_listener); + dbus_connection_unref(g_conn_listener); + g_conn_listener = NULL; + } + if (NULL != g_conn_sender) { + dbus_connection_close(g_conn_sender); + dbus_connection_unref(g_conn_sender); + g_conn_sender = NULL; + } +} + int vcd_dbus_open_connection() { DBusError err; @@ -1081,6 +1095,7 @@ int vcd_dbus_open_connection() if (NULL == g_conn_listener) { SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Fail to get dbus connection"); + __vcd_dbus_connection_free(); return VCD_ERROR_OPERATION_FAILED; } @@ -1092,12 +1107,14 @@ int vcd_dbus_open_connection() if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { printf("Fail to be primary owner in dbus request."); SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Fail to be primary owner"); + __vcd_dbus_connection_free(); return VCD_ERROR_OPERATION_FAILED; } if (dbus_error_is_set(&err)) { SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] dbus_bus_request_name() : %s", err.message); dbus_error_free(&err); + __vcd_dbus_connection_free(); return VCD_ERROR_OPERATION_FAILED; } @@ -1111,16 +1128,25 @@ int vcd_dbus_open_connection() if (dbus_error_is_set(&err)) { SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] dbus_bus_add_match() : %s", err.message); dbus_error_free(&err); + __vcd_dbus_connection_free(); return VCD_ERROR_OPERATION_FAILED; } int fd = 0; - dbus_connection_get_unix_fd(g_conn_listener, &fd); + if (1 != dbus_connection_get_unix_fd(g_conn_listener, &fd)) { + SLOG(LOG_ERROR, TAG_VCD, "fail to get fd from dbus "); + __vcd_dbus_connection_free(); + return VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCD, "Get fd from dbus : %d", fd); + } + g_dbus_fd_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, (Ecore_Fd_Cb)listener_event_callback, g_conn_listener, NULL, NULL); if (NULL == g_dbus_fd_handler) { SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Fail to get fd handler"); + __vcd_dbus_connection_free(); return VCD_ERROR_OPERATION_FAILED; } @@ -1144,13 +1170,7 @@ int vcd_dbus_close_connection() dbus_error_free(&err); } - dbus_connection_close(g_conn_listener); - dbus_connection_unref(g_conn_listener); - dbus_connection_close(g_conn_sender); - dbus_connection_unref(g_conn_sender); - - g_conn_listener = NULL; - g_conn_sender = NULL; + __vcd_dbus_connection_free(); return 0; } diff --git a/server/vcd_recorder.c b/server/vcd_recorder.c index eea8f50..5d1f689 100644 --- a/server/vcd_recorder.c +++ b/server/vcd_recorder.c @@ -574,7 +574,7 @@ int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, in audio_in_destroy(g_audio_h); audio_channel_e audio_ch; - audio_sample_type_e audio_type; + audio_sample_type_e audio_sample_type; switch (channel) { case 1: audio_ch = AUDIO_CHANNEL_MONO; break; @@ -586,15 +586,15 @@ int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, in } switch (type) { - case VCE_AUDIO_TYPE_PCM_S16_LE: audio_type = AUDIO_SAMPLE_TYPE_S16_LE; break; - case VCE_AUDIO_TYPE_PCM_U8: audio_type = AUDIO_SAMPLE_TYPE_U8; break; + case VCE_AUDIO_TYPE_PCM_S16_LE: audio_sample_type = AUDIO_SAMPLE_TYPE_S16_LE; break; + case VCE_AUDIO_TYPE_PCM_U8: audio_sample_type = AUDIO_SAMPLE_TYPE_U8; break; default: SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Invalid Audio Type"); return VCD_ERROR_OPERATION_FAILED; break; } - ret = audio_in_create(rate, audio_ch, audio_type, &g_audio_h); + ret = audio_in_create(rate, audio_ch, audio_sample_type, &g_audio_h); if (AUDIO_IO_ERROR_NONE != ret) { SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to create audio handle : %d", ret); g_is_valid_audio_in = false; -- 2.7.4 From c92dccc4912de8666b6c73dd6129c6cceb516585 Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Wed, 23 May 2018 22:36:46 +0900 Subject: [PATCH 08/16] Fix vc_widget_unprepare Change-Id: Ica2f4dde4da7a3e9d17ce8d24d8826913f3f7cf8 Signed-off-by: sooyeon.kim --- client/vc_widget.c | 92 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/client/vc_widget.c b/client/vc_widget.c index ea0d2cf..0dcca65 100644 --- a/client/vc_widget.c +++ b/client/vc_widget.c @@ -45,6 +45,7 @@ static int g_feature_enabled = -1; static Eina_Bool __vc_widget_notify_state_changed(void *data); static void __vc_widget_notify_error(void *data); +static void __vc_widget_delete_focus_event_handler(void *data); static int __vc_widget_get_feature_enabled() { @@ -213,14 +214,7 @@ static void __vc_widget_internal_unprepare(vc_h vc_w) SLOG(LOG_WARN, TAG_VCW, "[ERROR] Fail to request finalize : %s", __vc_widget_get_error_code(ret)); } - if (NULL != g_focus_in_handler) { - ecore_event_handler_del(g_focus_in_handler); - g_focus_in_handler = NULL; - } - if (NULL != g_focus_out_handler) { - ecore_event_handler_del(g_focus_out_handler); - g_focus_out_handler = NULL; - } + __vc_widget_delete_focus_event_handler(NULL); ret = vc_cmd_parser_delete_file(getpid(), VC_COMMAND_TYPE_WIDGET); if (0 != ret) @@ -262,21 +256,6 @@ int vc_widget_deinitialize(vc_h vc_w) return VC_ERROR_INVALID_STATE; } - - int thread_count = ecore_thread_active_get(); - int count = 0; - while (0 < thread_count) { - usleep(50000); - count++; - if (100 == count) { - SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is blocked, cnt(%d), thread count(%d)", count, thread_count); - break; - } else if (0 == count % 5) { - SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is alive, cnt(%d), thread count(%d)", count, thread_count); - } - thread_count = ecore_thread_active_get(); - } - vc_state_e state; vc_widget_client_get_state(vc_w, &state); vc_widget_s* widget = widget_get(vc_w); @@ -353,7 +332,35 @@ static Eina_Bool __focus_changed_cb(void *data, int type, void *event) return ECORE_CALLBACK_RENEW; } -static void __vc_widget_connect_daemon(void *data) +static void __vc_widget_add_focus_event_handler(void *data) +{ + SLOG(LOG_INFO, TAG_VCW, "@@@ [Widget] add focus event handler"); + + if (NULL == g_focus_in_handler) + g_focus_in_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, __focus_changed_cb, NULL); + if (NULL == g_focus_out_handler) + g_focus_out_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, __focus_changed_cb, NULL); + + return; +} + +static void __vc_widget_delete_focus_event_handler(void *data) +{ + SLOG(LOG_INFO, TAG_VCW, "@@@ [Widget] delete focus event handler"); + + if (NULL != g_focus_in_handler) { + ecore_event_handler_del(g_focus_in_handler); + g_focus_in_handler = NULL; + } + if (NULL != g_focus_out_handler) { + ecore_event_handler_del(g_focus_out_handler); + g_focus_out_handler = NULL; + } + + return; +} + +static Eina_Bool __vc_widget_connect_daemon(void *data) { vc_h vc_w = (vc_h)data; @@ -374,7 +381,7 @@ static void __vc_widget_connect_daemon(void *data) ecore_main_loop_thread_safe_call_async(__vc_widget_notify_error, vc_w); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return; + return EINA_FALSE; } else if (VC_ERROR_INVALID_PARAMETER == ret) { SLOG(LOG_WARN, TAG_VCW, "[WARNING] Invalid Parameter"); @@ -385,18 +392,13 @@ static void __vc_widget_connect_daemon(void *data) ecore_main_loop_thread_safe_call_async(__vc_widget_notify_error, vc_w); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return; + return EINA_TRUE; } vc_widget_client_set_service_state(vc_w, (vc_service_state_e)service_state); SLOG(LOG_INFO, TAG_VCW, "@@@ [Widget] Connect daemon"); - if (NULL == g_focus_in_handler) - g_focus_in_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, __focus_changed_cb, NULL); - if (NULL == g_focus_out_handler) - g_focus_out_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, __focus_changed_cb, NULL); - char appid[1024] = {'\0',}; aul_app_get_appid_bypid(getpid(), appid, sizeof(appid) - 1); @@ -432,7 +434,7 @@ static void __vc_widget_connect_daemon(void *data) SLOG(LOG_DEBUG, TAG_VCW, "@@@"); - return; + return EINA_FALSE; } static void __start_prepare_thread(void *data, Ecore_Thread *thread) @@ -445,6 +447,7 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread) while (0 != ret) { if (retry_count == 30) { SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Fail to request hello !!"); + ecore_main_loop_thread_safe_call_async(__vc_widget_delete_focus_event_handler, NULL); return; } @@ -457,12 +460,12 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread) } } -#if 0 ret = -1; retry_count = 0; while (0 != ret) { if (retry_count == 10) { SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Fail to connect daemon !!"); + ecore_main_loop_thread_safe_call_async(__vc_widget_delete_focus_event_handler, NULL); return; } ret = __vc_widget_connect_daemon((void*)vc_w); @@ -471,9 +474,8 @@ static void __start_prepare_thread(void *data, Ecore_Thread *thread) else retry_count++; } -#endif - ecore_main_loop_thread_safe_call_async(__vc_widget_connect_daemon, vc_w); + SLOG(LOG_DEBUG, TAG_VCW, "@@@"); return; } @@ -513,6 +515,9 @@ int vc_widget_prepare(vc_h vc_w) return VC_ERROR_INVALID_STATE; } + // Add focus event handler before start sub thread. If connection fails, event handler will be deleted. + __vc_widget_add_focus_event_handler(NULL); + ecore_thread_run(__start_prepare_thread, __end_prepare_thread, NULL, (void*)vc_w); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); @@ -529,6 +534,21 @@ int vc_widget_unprepare(vc_h vc_w) return VC_ERROR_NONE; } + int thread_count = ecore_thread_active_get(); + int count = 0; + SLOG(LOG_INFO, TAG_VCW, "[Widget] Thread count(%d)", thread_count); + while (0 < thread_count) { + usleep(50000); + if (100 == count) { + SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is blocked, cnt(%d), thread count(%d)", count, thread_count); + break; + } else if (0 == count % 5) { + SLOG(LOG_WARN, TAG_VCW, "[WARNING!!] Thread is alive, cnt(%d), thread count(%d)", count, thread_count); + } + count++; + thread_count = ecore_thread_active_get(); + } + vc_state_e state; if (0 != vc_widget_client_get_state(vc_w, &state)) { SLOG(LOG_ERROR, TAG_VCW, "[ERROR] A handle is not available"); @@ -538,7 +558,7 @@ int vc_widget_unprepare(vc_h vc_w) /* check state */ if (state != VC_STATE_READY) { - SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Invalid State: Current state is not 'READY'"); + SLOG(LOG_ERROR, TAG_VCW, "[ERROR] Invalid State: Current state is not 'READY', state(%d)", state); SLOG(LOG_DEBUG, TAG_VCW, "@@@"); return VC_ERROR_INVALID_STATE; } -- 2.7.4 From 5d84fa5d582936a2938f3357e6b23879ef4c4cec Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Tue, 29 May 2018 21:17:06 +0900 Subject: [PATCH 09/16] Change partial match level to word Change-Id: Ia3110f87da01bac30720c91f7ef4ada86ae98972 Signed-off-by: Wonnam Jang --- server/vcd_server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/vcd_server.c b/server/vcd_server.c index 0a9b9e9..89a58d1 100644 --- a/server/vcd_server.c +++ b/server/vcd_server.c @@ -683,7 +683,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(widget_cmd_list, &cnt); if (0 < cnt) { /* Matched with widget command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, vc_cmd_list, VC_SEARCH_CHAR_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, vc_cmd_list, VC_SEARCH_WORD_LEVEL); vc_cmd_list_get_count(vc_cmd_list, &cnt); if (0 < cnt) { top_priority = VC_COMMAND_PRIORITY_WIDGET; @@ -702,7 +702,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(foreground_cmd_list, &cnt); if (0 < cnt) { /* Matched with foreground command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, vc_cmd_list, VC_SEARCH_CHAR_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, vc_cmd_list, VC_SEARCH_WORD_LEVEL); vc_cmd_list_get_count(vc_cmd_list, &cnt); if (0 < cnt) { top_priority = VC_COMMAND_PRIORITY_FOREGROUND; @@ -777,7 +777,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(widget_cmd_list, &cnt); if (0 < cnt) { /* Matched with widget command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, temp_list, VC_SEARCH_CHAR_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, temp_list, VC_SEARCH_WORD_LEVEL); vc_cmd_list_get_count(temp_list, &cnt); if (0 < cnt) { if (0 != vc_cmd_list_destroy(vc_cmd_list, true)) { @@ -801,7 +801,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(foreground_cmd_list, &cnt); if (0 < cnt) { /* Matched with foreground command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, temp_list, VC_SEARCH_CHAR_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, temp_list, VC_SEARCH_WORD_LEVEL); vc_cmd_list_get_count(temp_list, &cnt); if (0 < cnt) { if (0 != vc_cmd_list_destroy(vc_cmd_list, true)) { -- 2.7.4 From 96889b116efb6c717376ee51c451ff530dfcaad3 Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Thu, 31 May 2018 16:22:47 +0900 Subject: [PATCH 10/16] Not use partial match Change-Id: Ica25f29ae0be807863d4b4831e0a9c2523be1dcd Signed-off-by: Wonnam Jang --- include/voice_control_command_expand.h | 1 + server/vcd_server.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/voice_control_command_expand.h b/include/voice_control_command_expand.h index 7947fa5..c188e77 100755 --- a/include/voice_control_command_expand.h +++ b/include/voice_control_command_expand.h @@ -42,6 +42,7 @@ typedef enum { VC_CMD_FORMAT_PARTIAL /**< Partial matched command */ } vc_cmd_format_e; +#define VC_SEARCH_NONE_LEVEL 0 #define VC_SEARCH_TEXT_LEVEL 1 #define VC_SEARCH_WORD_LEVEL 2 #define VC_SEARCH_CHAR_LEVEL 3 diff --git a/server/vcd_server.c b/server/vcd_server.c index 89a58d1..ef9dc76 100644 --- a/server/vcd_server.c +++ b/server/vcd_server.c @@ -683,7 +683,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(widget_cmd_list, &cnt); if (0 < cnt) { /* Matched with widget command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, vc_cmd_list, VC_SEARCH_WORD_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, vc_cmd_list, VC_SEARCH_NONE_LEVEL); vc_cmd_list_get_count(vc_cmd_list, &cnt); if (0 < cnt) { top_priority = VC_COMMAND_PRIORITY_WIDGET; @@ -702,7 +702,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(foreground_cmd_list, &cnt); if (0 < cnt) { /* Matched with foreground command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, vc_cmd_list, VC_SEARCH_WORD_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, vc_cmd_list, VC_SEARCH_NONE_LEVEL); vc_cmd_list_get_count(vc_cmd_list, &cnt); if (0 < cnt) { top_priority = VC_COMMAND_PRIORITY_FOREGROUND; @@ -777,7 +777,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(widget_cmd_list, &cnt); if (0 < cnt) { /* Matched with widget command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, temp_list, VC_SEARCH_WORD_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, widget_cmd_list, temp_list, VC_SEARCH_NONE_LEVEL); vc_cmd_list_get_count(temp_list, &cnt); if (0 < cnt) { if (0 != vc_cmd_list_destroy(vc_cmd_list, true)) { @@ -801,7 +801,7 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c vc_cmd_list_get_count(foreground_cmd_list, &cnt); if (0 < cnt) { /* Matched with foreground command partially */ - vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, temp_list, VC_SEARCH_WORD_LEVEL); + vc_cmd_get_partially_matched_cmd_list(all_result, foreground_cmd_list, temp_list, VC_SEARCH_NONE_LEVEL); vc_cmd_list_get_count(temp_list, &cnt); if (0 < cnt) { if (0 != vc_cmd_list_destroy(vc_cmd_list, true)) { -- 2.7.4 From 3c6c8fcee27573f0e2f0e2e495e4b8a7543329a7 Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Mon, 4 Jun 2018 23:21:49 +0900 Subject: [PATCH 11/16] Add feedback and server dialog APIs Change-Id: I7a4bfe718206b21f723fe693940185a5e18916c2 Signed-off-by: sooyeon.kim --- client/CMakeLists.txt | 3 + client/vc.c | 183 +++++++++++++- client/vc_dbus.c | 69 ++++++ client/vc_dbus.h | 2 + client/vc_mgr.c | 519 +++++++++++++++++++++++++++++++++++----- client/vc_mgr_client.c | 101 +++++++- client/vc_mgr_client.h | 13 + client/vc_mgr_data.cpp | 126 ++++++++++ client/vc_mgr_data.h | 63 +++++ client/vc_mgr_dbus.c | 92 +++++++ client/vc_mgr_dbus.h | 6 + client/vc_mgr_player.c | 413 ++++++++++++++++++++++++++++++++ client/vc_mgr_player.h | 25 ++ common/vc_defs.h | 9 + common/vc_info_parser.h | 1 + doc/uix_vc_doc.h | 5 + doc/uix_vc_engine_main_doc.h | 4 + include/vce.h | 136 +++++++++++ include/voice_control.h | 43 ++++ include/voice_control_common.h | 29 +++ include/voice_control_manager.h | 202 ++++++++++++++++ server/vcd_client_data.c | 33 +++ server/vcd_client_data.h | 5 + server/vcd_dbus.c | 132 ++++++++++ server/vcd_dbus.h | 8 + server/vcd_dbus_server.c | 201 +++++++++++++++- server/vcd_dbus_server.h | 10 + server/vcd_engine_agent.c | 66 ++++- server/vcd_engine_agent.h | 5 + server/vcd_main.h | 39 +-- server/vcd_server.c | 169 ++++++++++++- server/vcd_server.h | 18 ++ server/vce.c | 73 ++++++ 33 files changed, 2692 insertions(+), 111 deletions(-) create mode 100644 client/vc_mgr_data.cpp create mode 100644 client/vc_mgr_data.h create mode 100644 client/vc_mgr_player.c create mode 100644 client/vc_mgr_player.h mode change 100755 => 100644 common/vc_defs.h mode change 100755 => 100644 server/vcd_dbus.c mode change 100755 => 100644 server/vcd_dbus_server.c diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index fcc4c43..0380cc0 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -34,6 +34,8 @@ SET(WIDGET_SRCS SET(MANAGER_SRCS vc_mgr.c vc_mgr_client.c + vc_mgr_data.cpp + vc_mgr_player.c vc_mgr_dbus.c ../common/vc_cmd_db.c ../common/vc_command.c @@ -52,6 +54,7 @@ FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") ## voice control library ## ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) diff --git a/client/vc.c b/client/vc.c index 9a893f3..14bdf8b 100644 --- a/client/vc.c +++ b/client/vc.c @@ -2146,6 +2146,187 @@ int vc_set_invocation_name(const char* name) return ret; } +int vc_set_server_dialog(const char* app_id, const char* credential) +{ + vc_state_e state; + int ret = -1; + + SLOG(LOG_DEBUG, TAG_VCC, "@@@ Set server dialog, pid(%d), app_id(%s)", getpid(), app_id); + if (0 != __vc_get_feature_enabled()) { + return VC_ERROR_NOT_SUPPORTED; + } + if (0 != __vc_check_privilege()) { + return VC_ERROR_PERMISSION_DENIED; + } + + if (NULL == credential) { + SLOG(LOG_DEBUG, TAG_VCC, "[ERROR] Credential is NULL"); + return VC_ERROR_INVALID_PARAMETER; + } + + if (0 != vc_client_get_client_state(g_vc, &state)) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] A handle is not valid"); + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != VC_STATE_READY) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Invalid State: Current state(%d) is not 'READY'", state); + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + /* Check service state */ + vc_service_state_e service_state = -1; + vc_client_get_service_state(g_vc, &service_state); + if (service_state != VC_SERVICE_STATE_READY) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Invalid State: service state(%d) is not 'READY'", service_state); + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + char* tmp_appid = NULL; + if (NULL == app_id) { + ret = app_manager_get_app_id(getpid(), &tmp_appid); + if (0 != ret || NULL == tmp_appid) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] app_id is NULL"); + if (NULL != tmp_appid) + free(tmp_appid); + return VC_ERROR_INVALID_PARAMETER; + } + } else { + tmp_appid = strdup(app_id); + } + int pid = getpid(); + + SLOG(LOG_DEBUG, TAG_VCC, "Set server dialog : pid(%d), app_id(%s)", pid, tmp_appid); + + int count = 0; + bool is_prepared = false; + do { + ret = vc_dbus_set_server_dialog(pid, tmp_appid, credential); + if (0 != ret) { + if (VC_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + vc_client_set_client_state(g_vc, VC_STATE_INITIALIZED); + if (0 == vc_prepare_sync()) { + is_prepared = true; + SLOG(LOG_INFO, TAG_VCC, "[INFO] Success vc_prepare_sync"); + } + } else if (VC_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to request set server dialog to vc service : %s", __vc_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_VCC, "[WARNING] retry request set server dialog : %s", __vc_get_error_code(ret)); + usleep(10000); + count++; + if (VC_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to request"); + break; + } + } + } + } while (0 != ret); + + + if (NULL != tmp_appid) + free(tmp_appid); + + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + + return ret; +} + +int vc_unset_server_dialog(const char* app_id) +{ + vc_state_e state; + int ret = -1; + + SLOG(LOG_DEBUG, TAG_VCC, "@@@ Unset server dialog, pid(%d), app_id(%s)", getpid(), app_id); + if (0 != __vc_get_feature_enabled()) { + return VC_ERROR_NOT_SUPPORTED; + } + if (0 != __vc_check_privilege()) { + return VC_ERROR_PERMISSION_DENIED; + } + + if (0 != vc_client_get_client_state(g_vc, &state)) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] A handle is not valid"); + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != VC_STATE_READY) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Invalid State: Current state(%d) is not 'READY'", state); + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + /* Check service state */ + vc_service_state_e service_state = -1; + vc_client_get_service_state(g_vc, &service_state); + if (service_state != VC_SERVICE_STATE_READY) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Invalid State: service state(%d) is not 'READY'", service_state); + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + char* tmp_appid = NULL; + if (NULL == app_id) { + ret = app_manager_get_app_id(getpid(), &tmp_appid); + if (0 != ret || NULL == tmp_appid) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] app_id is NULL"); + if (NULL != tmp_appid) + free(tmp_appid); + return VC_ERROR_INVALID_PARAMETER; + } + } else { + tmp_appid = strdup(app_id); + } + int pid = getpid(); + + SLOG(LOG_DEBUG, TAG_VCC, "Unset server dialog : pid(%d), app_id(%s)", pid, tmp_appid); + + int count = 0; + bool is_prepared = false; + char* credential = strdup("#NULL"); + do { + ret = vc_dbus_set_server_dialog(pid, tmp_appid, credential); + if (0 != ret) { + if (VC_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + vc_client_set_client_state(g_vc, VC_STATE_INITIALIZED); + if (0 == vc_prepare_sync()) { + is_prepared = true; + SLOG(LOG_INFO, TAG_VCC, "[INFO] Success vc_prepare_sync"); + } + } else if (VC_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to request unset server dialog to vc service : %s", __vc_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_VCC, "[WARNING] retry request unset server dialog : %s", __vc_get_error_code(ret)); + usleep(10000); + count++; + if (VC_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to request"); + break; + } + } + } + } while (0 != ret); + + + if (NULL != tmp_appid) + free(tmp_appid); + if (NULL != credential) + free(credential); + + SLOG(LOG_DEBUG, TAG_VCC, "@@@"); + + return ret; +} + + int vc_request_dialog(const char* disp_text, const char* utt_text, bool auto_start) { vc_state_e state; @@ -2183,7 +2364,7 @@ int vc_request_dialog(const char* disp_text, const char* utt_text, bool auto_sta SLOG(LOG_DEBUG, TAG_VCC, "Request dialog : pid(%d) disp_text(%s), utt_text(%s), auto_start(%d)", getpid(), disp_text, utt_text, auto_start); int ret = vc_dbus_request_dialog(getpid(), disp_text, utt_text, auto_start); if (0 != ret) { - SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to set foreground (true) : %d", ret); + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to request dialog, ret(%d)", ret); return VC_ERROR_OPERATION_FAILED; } diff --git a/client/vc_dbus.c b/client/vc_dbus.c index 186d259..dfe0228 100644 --- a/client/vc_dbus.c +++ b/client/vc_dbus.c @@ -851,6 +851,75 @@ int vc_dbus_set_foreground(int pid, bool value) return 0; } +int vc_dbus_set_server_dialog(int pid, const char* app_id, const char* credential) +{ + if (NULL == g_conn_sender) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] NULL connection"); + if (0 != vc_dbus_reconnect()) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to reconnect"); + } + } + + DBusMessage* msg; + msg = dbus_message_new_method_call( + VC_SERVER_SERVICE_NAME, + VC_SERVER_SERVICE_OBJECT_PATH, + VC_SERVER_SERVICE_INTERFACE, + VC_METHOD_SET_SERVER_DIALOG); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_VCC, "@@ vc set server dialog : Fail to make message"); + return VC_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCC, "@@ vc set server dialog : pid(%d), app_id(%s)", pid, app_id); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &app_id, + DBUS_TYPE_STRING, &credential, + DBUS_TYPE_INVALID); + + DBusError err; + dbus_error_init(&err); + + DBusMessage* result_msg; + int result = VC_ERROR_OPERATION_FAILED; + + result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, g_waiting_time, &err); + dbus_message_unref(msg); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + if (NULL != result_msg) { + dbus_message_get_args(result_msg, &err, + DBUS_TYPE_INT32, &result, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCC, "@@ Get arguments error (%s)", err.message); + dbus_error_free(&err); + result = VC_ERROR_OPERATION_FAILED; + } + dbus_message_unref(result_msg); + + if (0 == result) { + SLOG(LOG_DEBUG, TAG_VCC, "@@ vc set server dialog : result = %d", result); + } else { + SLOG(LOG_ERROR, TAG_VCC, "@@ vc set server dialog : result = %d", result); + } + } else { + SLOG(LOG_ERROR, TAG_VCC, "@@ Result message is NULL"); + vc_dbus_reconnect(); + result = VC_ERROR_TIMED_OUT; + } + + return result; +} + int vc_dbus_request_dialog(int pid, const char* disp_text, const char* utt_text, bool continuous) { if (NULL == g_conn_sender) { diff --git a/client/vc_dbus.h b/client/vc_dbus.h index b5db90b..e7f7512 100644 --- a/client/vc_dbus.h +++ b/client/vc_dbus.h @@ -42,6 +42,8 @@ int vc_dbus_request_unset_command(int pid, vc_cmd_type_e cmd_type); int vc_dbus_set_foreground(int pid, bool value); +int vc_dbus_set_server_dialog(int pid, const char* app_id, const char* credential); + int vc_dbus_request_dialog(int pid, const char* disp_text, const char* utt_text, bool continuous); int vc_dbus_request_is_system_command_valid(int pid, bool* is_sys_cmd_valid); diff --git a/client/vc_mgr.c b/client/vc_mgr.c index e56205e..ab8d584 100644 --- a/client/vc_mgr.c +++ b/client/vc_mgr.c @@ -28,6 +28,8 @@ #include "vc_main.h" #include "vc_mgr_client.h" #include "vc_mgr_dbus.h" +#include "vc_mgr_data.h" +#include "vc_mgr_player.h" #include "voice_control.h" #include "voice_control_command.h" #include "voice_control_command_expand.h" @@ -61,6 +63,12 @@ static cynara *p_cynara = NULL; static bool g_err_callback_status = false; +/* for TTS feedback */ +static int g_feedback_rate = 16000; +static vc_audio_channel_e g_feedback_audio_channel = 0; +static vc_audio_type_e g_feedback_audio_type = 0; + + static Eina_Bool __vc_mgr_notify_state_changed(void *data); static void __vc_mgr_notify_error(void *data); static Eina_Bool __vc_mgr_notify_result(void *data); @@ -262,6 +270,12 @@ int vc_mgr_initialize(void) return ret; } + /* for TTS feedback */ +/* ret = vc_mgr_player_init(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to initialize VC mgr player : %d", ret); + } +*/ SLOG(LOG_ERROR, TAG_VCM, "[Success] pid(%d)", g_vc_m->handle); SLOG(LOG_DEBUG, TAG_VCM, "@@@"); @@ -339,6 +353,12 @@ int vc_mgr_deinitialize(void) SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to finalize DB, ret(%d)", ret); } + /* for TTS feedback */ +/* ret = vc_mgr_player_release(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to release VC mgr player(%d)", ret); + } +*/ if (0 != vc_mgr_dbus_close_connection()) { SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to close connection"); } @@ -1700,26 +1720,14 @@ int vc_mgr_set_private_data(const char* key, const char* data) } int ret = -1; - int count = 0; - while (0 != ret) { - ret = vc_mgr_dbus_request_set_private_data(g_vc_m->handle, key, data); - if (0 != ret) { - if (VC_ERROR_TIMED_OUT != ret) { - SLOG(LOG_DEBUG, TAG_VCM, "[ERROR] Fail to set private data request : %s", __vc_mgr_get_error_code(ret)); - break; - } else { - SLOG(LOG_WARN, TAG_VCM, "[WARNING] retry set private data request : %s", __vc_mgr_get_error_code(ret)); - usleep(10000); - count++; - if (VC_RETRY_COUNT == count) { - SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to request"); - break; - } - } - } else { - SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Set domain"); - } + ret = vc_mgr_dbus_request_set_private_data(g_vc_m->handle, key, data); + if (0 != ret) { + SLOG(LOG_DEBUG, TAG_VCM, "[ERROR] Fail to set private data : %s", __vc_mgr_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Set private data"); } + SLOG(LOG_DEBUG, TAG_VCM, "@@@"); return 0; @@ -1910,25 +1918,61 @@ int vc_mgr_do_action(vc_send_event_type_e type, char* send_event) } int ret = -1; - int count = 0; - while (0 != ret) { - ret = vc_mgr_dbus_request_do_action(g_vc_m->handle, type, send_event); - if (0 != ret) { - if (VC_ERROR_TIMED_OUT != ret) { - SLOG(LOG_DEBUG, TAG_VCM, "[ERROR] Fail to do action request : %s", __vc_mgr_get_error_code(ret)); - break; - } else { - SLOG(LOG_WARN, TAG_VCM, "[WARNING] retry do action request : %s", __vc_mgr_get_error_code(ret)); - usleep(10000); - count++; - if (VC_RETRY_COUNT == count) { - SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to request"); - break; - } - } - } else { - SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] do action"); - } + ret = vc_mgr_dbus_request_do_action(g_vc_m->handle, type, send_event); + if (0 != ret) { + SLOG(LOG_DEBUG, TAG_VCM, "[ERROR] Fail to do action request : %s", __vc_mgr_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] do action"); + } + SLOG(LOG_DEBUG, TAG_VCM, "@@@"); + + return 0; +} + +int vc_mgr_send_specific_engine_request(const char* engine_app_id, const char* event, const char* request) +{ + SLOG(LOG_DEBUG, TAG_VCM, "@@@ [Manager] specific engine request. engine app id(%s), event(%s), request(%s)", engine_app_id, event, request); + + if (NULL == engine_app_id || NULL == event) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Invalid parameter"); + return VC_ERROR_INVALID_PARAMETER; + } + + if (NULL == request) { + SLOG(LOG_ERROR, TAG_VCM, "[INFO] Input parameter is NULL. (no request)"); + } + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] A handle is not available"); + SLOG(LOG_DEBUG, TAG_VCM, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != VC_STATE_READY) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Invalid State: Current state(%d) is not 'READY'", state); + SLOG(LOG_DEBUG, TAG_VCM, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + /* Check service state */ + vc_service_state_e service_state = -1; + vc_mgr_client_get_service_state(g_vc_m, &service_state); + if (service_state != VC_SERVICE_STATE_READY) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Invalid State: service state(%d) is not 'READY'", service_state); + SLOG(LOG_DEBUG, TAG_VCM, "@@@"); + return VC_ERROR_INVALID_STATE; + } + + int ret = -1; + ret = vc_mgr_dbus_send_specific_engine_request(g_vc_m->handle, engine_app_id, event, request); + if (0 != ret) { + SLOG(LOG_DEBUG, TAG_VCM, "[ERROR] Fail to specific engine request : %s", __vc_mgr_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] specific engine request"); } SLOG(LOG_DEBUG, TAG_VCM, "@@@"); @@ -2332,30 +2376,14 @@ int vc_mgr_set_selected_results(vc_cmd_list_h vc_cmd_list) } } - int ret; - int count = 0; - /* Request */ - ret = -1; - count = 0; - while (0 != ret) { - ret = vc_mgr_dbus_send_result_selection(g_vc_m->handle); - if (0 != ret) { - if (VC_ERROR_TIMED_OUT != ret) { - SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to send result selection : %s", __vc_mgr_get_error_code(ret)); - break; - } else { - SLOG(LOG_WARN, TAG_VCM, "[WARNING] retry send result selection : %s", __vc_mgr_get_error_code(ret)); - usleep(10000); - count++; - if (VC_RETRY_COUNT == count) { - SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to request"); - break; - } - } - } else { - SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] result selection"); - } + int ret = -1; + ret = vc_mgr_dbus_send_result_selection(g_vc_m->handle); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to send result selection : %s", __vc_mgr_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] result selection"); } vc_mgr_client_unset_all_result(g_vc_m); @@ -3272,6 +3300,81 @@ int __vc_mgr_cb_private_data_requested(const char* key, char** data) return ret; } +/* for TTS feedback */ +int __vc_mgr_cb_feedback_audio_format(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type) +{ + vc_mgr_feedback_audio_format_cb callback = NULL; + void* user_data = NULL; + + /* set global audio formats */ + g_feedback_rate = rate; + g_feedback_audio_channel = channel; + g_feedback_audio_type = audio_type; + + vc_mgr_client_get_feedback_audio_format_cb(g_vc_m, &callback, &user_data); + + if (NULL != callback) { + vc_mgr_client_use_callback(g_vc_m); + callback(rate, channel, audio_type, user_data); + vc_mgr_client_not_use_callback(g_vc_m); + SLOG(LOG_DEBUG, TAG_VCM, "TTS feedback audio format callback is called"); + } else { + SLOG(LOG_WARN, TAG_VCM, "[WARNING] TTS feedback audio format callback is null"); + } + + return VC_ERROR_NONE; +} + +int __vc_mgr_cb_feedback_streaming(vc_feedback_event_e event, char* buffer, int len) +{ + /* add feedback data */ + vc_feedback_data_s* temp_feedback_data = NULL; + temp_feedback_data = (vc_feedback_data_s*)calloc(1, sizeof(vc_feedback_data_s)); + if (NULL == temp_feedback_data) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Out of memory"); + return VC_ERROR_OUT_OF_MEMORY; + } + + temp_feedback_data->data = NULL; + temp_feedback_data->rate = g_feedback_rate; + temp_feedback_data->data_size = 0; + + if (0 < len) { + temp_feedback_data->data = (char*)calloc(len + 5, sizeof(char)); + if (NULL != temp_feedback_data->data) { + memcpy(temp_feedback_data->data, buffer, len); + temp_feedback_data->data_size = len; + SLOG(LOG_DEBUG, TAG_VCM, "[DEBUG][memcpy] data(%p) size(%d)", + temp_feedback_data->data, temp_feedback_data->data_size); + } else { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] fail to allocate memory"); + } + } else { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] feedback data is NULL"); + } + + temp_feedback_data->event = event; + temp_feedback_data->audio_type = g_feedback_audio_type; + temp_feedback_data->channel = g_feedback_audio_channel; + + int ret = vc_mgr_data_add_feedback_data(temp_feedback_data); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to add feedback data"); + if (NULL != temp_feedback_data->data) { + free(temp_feedback_data->data); + temp_feedback_data->data = NULL; + } + if (NULL != temp_feedback_data) { + free(temp_feedback_data); + temp_feedback_data = NULL; + } + + return ret; + } + + return VC_ERROR_NONE; +} + int vc_mgr_set_dialog_request_cb(vc_mgr_dialog_request_cb callback, void* user_data) { if (0 != __vc_mgr_get_feature_enabled()) { @@ -3631,3 +3734,297 @@ int __vc_mgr_request_auth_cancel(int pid) return 0; } + +int vc_mgr_set_specific_engine_result_cb(vc_mgr_specific_engine_result_cb callback, void* user_data) +{ + if (0 != __vc_mgr_get_feature_enabled()) { + return VC_ERROR_NOT_SUPPORTED; + } + + if (NULL == callback) + return VC_ERROR_INVALID_PARAMETER; + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Set specific engine result callback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != VC_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Set specific engine result callback : Current state(%d) is not 'Initialized'", state); + return VC_ERROR_INVALID_STATE; + } + + vc_mgr_client_set_specific_engine_result_cb(g_vc_m, callback, user_data); + + return 0; +} +int vc_mgr_unset_specific_engine_result_cb(void) +{ + if (0 != __vc_mgr_get_feature_enabled()) { + return VC_ERROR_NOT_SUPPORTED; + } + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Unset specific engine result callback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != VC_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Unset specific engine result callback : Current state(%d) is not 'Initialize'", state); + return VC_ERROR_INVALID_STATE; + } + + vc_mgr_client_set_specific_engine_result_cb(g_vc_m, NULL, NULL); + + return 0; +} + +void __vc_mgr_cb_specific_engine_result(const char* engine_app_id, const char* event, const char* result) +{ + vc_mgr_specific_engine_result_cb callback = NULL; + void* user_data = NULL; + + vc_mgr_client_get_specific_engine_result_cb(g_vc_m, &callback, &user_data); + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Client specific engine result callback is NULL"); + return; + } + + vc_mgr_client_use_callback(g_vc_m); + callback(engine_app_id, event, result, user_data); + vc_mgr_client_not_use_callback(g_vc_m); + SLOG(LOG_DEBUG, TAG_VCM, "Specific engine result callback is called, engine app id(%s), event(%s), result(%s)", engine_app_id, event, result); + + return; +} + +/* for TTS feedback */ +int vc_mgr_set_feedback_audio_format_cb(vc_mgr_feedback_audio_format_cb callback, void* user_data) +{ + if (NULL == callback) + return VC_ERROR_INVALID_PARAMETER; + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Set feedback audio format callback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (VC_STATE_INITIALIZED != state) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Set feedback audio format callback : Current state is not 'Initialized' (%d)", state); + return VC_ERROR_INVALID_STATE; + } + + vc_mgr_client_set_feedback_audio_format_cb(g_vc_m, callback, user_data); + + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Set feedback audio format callback"); + + return 0; +} + +int vc_mgr_unset_feedback_audio_format_cb() +{ + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Unset feedback audio format callback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (VC_STATE_INITIALIZED != state) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Unset feedback audio format callback : Current state is not 'Initialized' (%d)", state); + return VC_ERROR_INVALID_STATE; + } + + vc_mgr_client_set_feedback_audio_format_cb(g_vc_m, NULL, NULL); + + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Unset feedback audio format callback"); + + return 0; +} + +int vc_mgr_set_feedback_streaming_cb(vc_mgr_feedback_streaming_cb callback, void* user_data) +{ + if (NULL == callback) + return VC_ERROR_INVALID_PARAMETER; + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Set feedback streaming callback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (VC_STATE_INITIALIZED != state) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Set feedback streaming callback : Current state is not 'Initialized' (%d)", state); + return VC_ERROR_INVALID_STATE; + } + + vc_mgr_client_set_feedback_streaming_cb(g_vc_m, callback, user_data); + + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Set feedback streaming callback"); + + return 0; +} + +int vc_mgr_unset_feedback_streaming_cb() +{ + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Unset feedback streaming callback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (VC_STATE_INITIALIZED != state) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Unset feedback streaming callback : Current state is not 'Initialized' (%d)", state); + return VC_ERROR_INVALID_STATE; + } + + vc_mgr_client_set_feedback_streaming_cb(g_vc_m, NULL, NULL); + + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Unset feedback streaming callback"); + + return 0; +} + +static void __tts_feedback_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] Start thread"); + + vc_feedback_data_s* feedback_data = NULL; + vc_mgr_feedback_streaming_cb callback = NULL; + void* user_data = NULL; + + vc_mgr_client_get_feedback_streaming_cb(g_vc_m, &callback, &user_data); + if (NULL == callback) { + SLOG(LOG_WARN, TAG_VCM, "[WARNING] TTS feedback streaming callback is null"); + return; + } + + while (1) { + int ret = -1; + int cnt = 0; + + /* get feedback data */ + ret = vc_mgr_data_get_feedback_data(&feedback_data); + if (0 != ret || NULL == feedback_data) { + /* empty queue */ + SLOG(LOG_DEBUG, TAG_VCM, "[DEBUG] No feedback data. Waiting mode"); + + /* waiting */ + while (1) { + usleep(10000); + if (0 < vc_mgr_data_get_feedback_data_size()) { + SLOG(LOG_INFO, TAG_VCM, "[INFO] Resume thread"); + break; + } + if (200 < cnt) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Wrong request, there's no pcm data"); + return; + } + cnt++; + } + SLOG(LOG_INFO, TAG_VCM, "[INFO] Finish to wait for new feedback data come"); + + /* resume feedback thread */ + continue; + } + + SLOG(LOG_DEBUG, TAG_VCM, "TTS feedback streaming callback is called"); + vc_mgr_client_use_callback(g_vc_m); + callback(feedback_data->event, feedback_data->data, feedback_data->data_size, user_data); + vc_mgr_client_not_use_callback(g_vc_m); + + /* If no feedback data and EVENT_FINISH */ + if (0 >= vc_mgr_data_get_feedback_data_size() && VC_FEEDBACK_EVENT_FINISH == feedback_data->event) { + SLOG(LOG_INFO, TAG_VCM, "[INFO] Finish feedback"); + break; + } + } +} + +static void __end_tts_feedback_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_DEBUG, TAG_VCM, "[SUCCESS] End thread"); +} + +int vc_mgr_start_feedback(void) +{ + SLOG(LOG_DEBUG, TAG_VCM, "@@@ [Manager] Request start TTS feedback"); + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Start feedback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (VC_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Start feedback : Current state is not 'Ready' (%d)", state); + return VC_ERROR_INVALID_STATE; + } + +#if 1 + ecore_thread_run(__tts_feedback_thread, __end_tts_feedback_thread, NULL, NULL); +#else + /* start playing TTS feedback */ + int ret = -1; + ret = vc_mgr_player_play(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to player play, ret(%d)", ret); + } +#endif + return 0; +} + +int vc_mgr_stop_feedback(void) +{ + SLOG(LOG_DEBUG, TAG_VCM, "@@@ [Manager] Request stop TTS feedback"); + + vc_state_e state; + if (0 != vc_mgr_client_get_client_state(g_vc_m, &state)) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Stop feedback : A handle is not available"); + return VC_ERROR_INVALID_STATE; + } + + /* check state */ + if (VC_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Stop feedback : Current state is not 'Ready' (%d)", state); + return VC_ERROR_INVALID_STATE; + } + +#if 1 + int ret = -1; + + while (1) { + vc_feedback_data_s* feedback_data = NULL; + + /* get feedback data */ + ret = vc_mgr_data_get_feedback_data(&feedback_data); + if (0 != ret || NULL == feedback_data) { + /* empty queue */ + SLOG(LOG_INFO, TAG_VCM, "[INFO] No feedback data to stop any more"); + return 0; + } + ret = vc_mgr_data_clear_feedback_data(&feedback_data); + if (0 != ret) { + SLOG(LOG_INFO, TAG_VCM, "[ERROR] Fail to clear data, ret(%d)", ret); + break; + } + } +#else + /* request to stop playing TTS feedback */ + int ret = -1; + ret = vc_mgr_player_stop(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[ERROR] Fail to player stop, ret(%d)", ret); + } +#endif + return ret; +} diff --git a/client/vc_mgr_client.c b/client/vc_mgr_client.c index 985f460..18120ed 100644 --- a/client/vc_mgr_client.c +++ b/client/vc_mgr_client.c @@ -46,7 +46,15 @@ typedef struct { vc_mgr_private_data_set_cb private_data_set_cb; void* private_data_set_user_data; vc_mgr_private_data_requested_cb private_data_requested_cb; - void* private_data_requested_user_data; + void* private_data_requested_user_data; + vc_mgr_specific_engine_result_cb specific_engine_result_cb; + void* specific_engine_result_user_data; + + /* for TTS feedback */ + vc_mgr_feedback_audio_format_cb feedback_audio_format_cb; + void* feedback_audio_format_user_data; + vc_mgr_feedback_streaming_cb feedback_streaming_cb; + void* feedback_streaming_user_data; /* All result */ vc_result_event_e all_result_event; @@ -174,6 +182,13 @@ int vc_mgr_client_create(vc_h* vc) client->private_data_set_user_data = NULL; client->private_data_requested_cb = NULL; client->private_data_requested_user_data = NULL; + client->specific_engine_result_cb = NULL; + client->specific_engine_result_user_data = NULL; + + client->feedback_audio_format_cb = NULL; + client->feedback_audio_format_user_data = NULL; + client->feedback_streaming_cb = NULL; + client->feedback_streaming_user_data = NULL; client->exclusive_cmd_option = false; @@ -645,6 +660,62 @@ int vc_mgr_client_get_private_data_requested_cb(vc_h vc, vc_mgr_private_data_req return 0; } +int vc_mgr_client_set_feedback_audio_format_cb(vc_h vc, vc_mgr_feedback_audio_format_cb callback, void* user_data) +{ + vc_mgr_client_s* client = __mgr_client_get(vc); + + /* check handle */ + if (NULL == client) + return VC_ERROR_INVALID_PARAMETER; + + client->feedback_audio_format_cb = callback; + client->feedback_audio_format_user_data = user_data; + + return 0; +} + +int vc_mgr_client_get_feedback_audio_format_cb(vc_h vc, vc_mgr_feedback_audio_format_cb* callback, void** user_data) +{ + vc_mgr_client_s* client = __mgr_client_get(vc); + + /* check handle */ + if (NULL == client) + return VC_ERROR_INVALID_PARAMETER; + + *callback = client->feedback_audio_format_cb; + *user_data = client->feedback_audio_format_user_data; + + return 0; +} + +int vc_mgr_client_set_feedback_streaming_cb(vc_h vc, vc_mgr_feedback_streaming_cb callback, void* user_data) +{ + vc_mgr_client_s* client = __mgr_client_get(vc); + + /* check handle */ + if (NULL == client) + return VC_ERROR_INVALID_PARAMETER; + + client->feedback_streaming_cb = callback; + client->feedback_streaming_user_data = user_data; + + return 0; +} + +int vc_mgr_client_get_feedback_streaming_cb(vc_h vc, vc_mgr_feedback_streaming_cb* callback, void** user_data) +{ + vc_mgr_client_s* client = __mgr_client_get(vc); + + /* check handle */ + if (NULL == client) + return VC_ERROR_INVALID_PARAMETER; + + *callback = client->feedback_streaming_cb; + *user_data = client->feedback_streaming_user_data; + + return 0; +} + /* set/get option */ int vc_mgr_client_set_service_state(vc_h vc, vc_service_state_e state) { @@ -1191,3 +1262,31 @@ int vc_mgr_client_get_start_by_client(vc_h vc, bool* option) return 0; } + +int vc_mgr_client_set_specific_engine_result_cb(vc_h vc, vc_mgr_specific_engine_result_cb callback, void* user_data) +{ + vc_mgr_client_s* client = __mgr_client_get(vc); + + /* check handle */ + if (NULL == client) + return VC_ERROR_INVALID_PARAMETER; + + client->specific_engine_result_cb = callback; + client->specific_engine_result_user_data = user_data; + + return 0; +} + +int vc_mgr_client_get_specific_engine_result_cb(vc_h vc, vc_mgr_specific_engine_result_cb* callback, void** user_data) +{ + vc_mgr_client_s* client = __mgr_client_get(vc); + + /* check handle */ + if (NULL == client) + return VC_ERROR_INVALID_PARAMETER; + + *callback = client->specific_engine_result_cb; + *user_data = client->specific_engine_result_user_data; + + return 0; +} diff --git a/client/vc_mgr_client.h b/client/vc_mgr_client.h index 4c91392..e8104c0 100644 --- a/client/vc_mgr_client.h +++ b/client/vc_mgr_client.h @@ -95,6 +95,19 @@ int vc_mgr_client_set_private_data_requested_cb(vc_h vc, vc_mgr_private_data_req int vc_mgr_client_get_private_data_requested_cb(vc_h vc, vc_mgr_private_data_requested_cb* callback, void** user_data); +int vc_mgr_client_set_specific_engine_result_cb(vc_h vc, vc_mgr_specific_engine_result_cb callback, void* user_data); + +int vc_mgr_client_get_specific_engine_result_cb(vc_h vc, vc_mgr_specific_engine_result_cb* callback, void** user_data); + +int vc_mgr_client_set_feedback_audio_format_cb(vc_h vc, vc_mgr_feedback_audio_format_cb callback, void* user_data); + +int vc_mgr_client_get_feedback_audio_format_cb(vc_h vc, vc_mgr_feedback_audio_format_cb* callback, void** user_data); + +int vc_mgr_client_set_feedback_streaming_cb(vc_h vc, vc_mgr_feedback_streaming_cb callback, void* user_data); + +int vc_mgr_client_get_feedback_streaming_cb(vc_h vc, vc_mgr_feedback_streaming_cb* callback, void** user_data); + + /* * set/get option */ diff --git a/client/vc_mgr_data.cpp b/client/vc_mgr_data.cpp new file mode 100644 index 0000000..fa455cd --- /dev/null +++ b/client/vc_mgr_data.cpp @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the License); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +#include "vc_mgr_data.h" + +using namespace std; + +std::list g_feedback_data; + +static pthread_mutex_t g_feedback_data_mutex = PTHREAD_MUTEX_INITIALIZER; + +int vc_mgr_data_add_feedback_data(vc_feedback_data_s* data) +{ + if (NULL == data) { + SLOG(LOG_ERROR, TAG_VCM, "[DATA ERROR] feedback data is NULL"); + return VC_ERROR_INVALID_PARAMETER; + } + + pthread_mutex_lock(&g_feedback_data_mutex); + + std::list::iterator iter; + + try { + iter = g_feedback_data.insert(g_feedback_data.end(), data); + } catch (const std::bad_alloc&) { + SLOG(LOG_ERROR, TAG_VCM, "[DATA ERROR] Fail to insert feedback data (bad alloc)"); + pthread_mutex_unlock(&g_feedback_data_mutex); + + return VC_ERROR_OUT_OF_MEMORY; + } + + pthread_mutex_unlock(&g_feedback_data_mutex); + + return VC_ERROR_NONE; +} + +int vc_mgr_data_get_feedback_data(vc_feedback_data_s** data) +{ + SLOG(LOG_DEBUG, TAG_VCM, "[DATA] feedback_data : %p", *data); + + pthread_mutex_lock(&g_feedback_data_mutex); + + if (0 == g_feedback_data.size()) { + SLOG(LOG_DEBUG, TAG_VCM, "[DATA] There is no feedback data"); + *data = NULL; + pthread_mutex_unlock(&g_feedback_data_mutex); + + return -1; + } + + std::list::iterator iter; + + if (!g_feedback_data.empty()) { + iter = g_feedback_data.begin(); + *data = *iter; + g_feedback_data.pop_front(); + } + + pthread_mutex_unlock(&g_feedback_data_mutex); + + return VC_ERROR_NONE; +} + +int vc_mgr_data_get_feedback_data_size() +{ + SLOG(LOG_DEBUG, TAG_VCM, "[DATA] get feedback data size"); + + int data_size = 0; + + pthread_mutex_lock(&g_feedback_data_mutex); + data_size = g_feedback_data.size(); + + pthread_mutex_unlock(&g_feedback_data_mutex); + + return data_size; +} + +int vc_mgr_data_clear_feedback_data(vc_feedback_data_s** data) +{ + SLOG(LOG_DEBUG, TAG_VCM, "[DATA] clear feedback data"); + + pthread_mutex_lock(&g_feedback_data_mutex); + + if (!g_feedback_data.empty()) { + SLOG(LOG_DEBUG, TAG_VCM, "[DEBUG] data(%p) size(%d) rate(%d)", (*data)->data, (*data)->data_size, (*data)->rate); + + if (NULL != (*data)->data) { + free((*data)->data); + (*data)->data = NULL; + } + + free(*data); + *data = NULL; + } + + pthread_mutex_unlock(&g_feedback_data_mutex); + + return VC_ERROR_NONE; +} + +int vc_mgr_data_get_pid() +{ +// SLOG(LOG_DEBUG, TAG_VCM, "[DATA] get VC mgr pid"); + + return getpid(); +} diff --git a/client/vc_mgr_data.h b/client/vc_mgr_data.h new file mode 100644 index 0000000..3e2960f --- /dev/null +++ b/client/vc_mgr_data.h @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the License); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef __VC_MGR_DATA_H__ +#define __VC_MGR_DATA_H__ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define TAG_VCM "vcm" /* Manager client log tag */ + +typedef enum { + VC_FEEDBACK_STATE_CREATED = 0, + VC_FEEDBACK_STATE_READY, + VC_FEEDBACK_STATE_PLAYING +} vc_feedback_state_e; + +typedef struct { + int utt_id; + void* data; + unsigned int data_size; + + vc_feedback_event_e event; + vc_audio_type_e audio_type; + vc_audio_channel_e channel; + int rate; +} vc_feedback_data_s; + + +int vc_mgr_data_add_feedback_data(vc_feedback_data_s* data); + +int vc_mgr_data_get_feedback_data(vc_feedback_data_s** data); + +int vc_mgr_data_get_feedback_data_size(); + +int vc_mgr_data_clear_feedback_data(vc_feedback_data_s** data); + +int vc_mgr_data_get_pid(); + +#ifdef __cplusplus +} +#endif + +#endif /* __VC_MGR_DATA_H__ */ diff --git a/client/vc_mgr_dbus.c b/client/vc_mgr_dbus.c index 0935452..040ebcb 100644 --- a/client/vc_mgr_dbus.c +++ b/client/vc_mgr_dbus.c @@ -51,6 +51,11 @@ extern int __vc_mgr_cb_private_data_set(const char* key, const char* data); extern int __vc_mgr_cb_private_data_requested(const char* key, char** data); +/* for TTS feedback */ +extern int __vc_mgr_cb_feedback_audio_format(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type); + +extern int __vc_mgr_cb_feedback_streaming(vc_feedback_event_e event, char* buffer, int len); + /* Authority */ extern int __vc_mgr_request_auth_enable(int pid); @@ -64,6 +69,8 @@ extern int __vc_mgr_request_auth_cancel(int pid); extern int __vc_mgr_cb_dialog(int pid, const char* disp_text, const char* utt_text, bool continuous); +extern void __vc_mgr_cb_specific_engine_result(const char* engine_app_id, const char* event, const char* result); + static Eina_Bool vc_mgr_listener_event_callback(void* data, Ecore_Fd_Handler *fd_handler) { if (NULL == g_m_conn_listener) return ECORE_CALLBACK_RENEW; @@ -195,7 +202,20 @@ static Eina_Bool vc_mgr_listener_event_callback(void* data, Ecore_Fd_Handler *fd SLOG(LOG_DEBUG, TAG_VCM, "@@@"); } /* VCD_MANAGER_METHOD_PRE_RESULT */ + else if (dbus_message_is_method_call(msg, if_name, VCD_MANAGER_METHOD_SPECIFIC_ENGINE_RESULT)) { + SLOG(LOG_DEBUG, TAG_VCM, "@@@ Get specific engine result"); + char* engine_app_id = NULL; + char* event = NULL; + char* result = NULL; + + dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &engine_app_id, DBUS_TYPE_STRING, &event, DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID); + if (NULL != result) { + __vc_mgr_cb_specific_engine_result(engine_app_id, event, result); + } + + SLOG(LOG_DEBUG, TAG_VCM, "@@@"); + } /* VCD_MANAGER_METHOD_SPECIFIC_ENGINE_RESULT */ else if (dbus_message_is_method_call(msg, if_name, VCD_MANAGER_METHOD_RESULT)) { SLOG(LOG_DEBUG, TAG_VCM, "@@@ Get System Result"); @@ -372,6 +392,40 @@ static Eina_Bool vc_mgr_listener_event_callback(void* data, Ecore_Fd_Handler *fd SLOG(LOG_DEBUG, TAG_VCM, "@@@"); } /* VCD_MANAGER_METHOD_GET_PRIVATE_DATA */ + else if (dbus_message_is_method_call(msg, if_name, VCD_MANAGER_METHOD_FEEDBACK_AUDIO_FORMAT)) { + SLOG(LOG_INFO, TAG_VCM, "@@@ Get TTS feedback audio format"); + int rate; + vc_audio_channel_e channel; + vc_audio_type_e audio_type; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &rate, + DBUS_TYPE_INT32, &channel, + DBUS_TYPE_INT32, &audio_type, + DBUS_TYPE_INVALID); + + __vc_mgr_cb_feedback_audio_format(rate, channel, audio_type); + + SLOG(LOG_INFO, TAG_VCM, "@@@"); + } /* VCD_MANAGER_METHOD_FEEDBACK_AUDIO_FORMAT */ + + else if (dbus_message_is_method_call(msg, if_name, VCD_MANAGER_METHOD_FEEDBACK_STREAMING)) { + SLOG(LOG_INFO, TAG_VCM, "@@@ Get TTS feedback streaming"); + vc_feedback_event_e event; + char* buffer = NULL; + int len; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &event, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &buffer, &len, + DBUS_TYPE_INVALID); + + __vc_mgr_cb_feedback_streaming(event, buffer, len); + + SLOG(LOG_INFO, TAG_VCM, "@@@"); + } /* VCD_MANAGER_METHOD_FEEDBACK_STREAMING */ + /* Authority */ else if (dbus_message_is_method_call(msg, if_name, VC_METHOD_AUTH_ENABLE)) { SLOG(LOG_DEBUG, TAG_VCM, "@@@ Get request auth enable"); @@ -2200,3 +2254,41 @@ int vc_mgr_dbus_send_result_selection(int pid) return 0; } + +int vc_mgr_dbus_send_specific_engine_request(int pid, const char* engine_app_id, const char* event, const char* request) +{ + DBusMessage* msg; + + /* create a signal & check for errors */ + msg = dbus_message_new_method_call( + VC_SERVER_SERVICE_NAME, + VC_SERVER_SERVICE_OBJECT_PATH, /* object name of the signal */ + VC_SERVER_SERVICE_INTERFACE, /* interface name of the signal */ + VC_MANAGER_METHOD_SPECIFIC_ENGINE_REQUEST); /* name of the signal */ + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_VCM, "@@ vc send specific engine : Fail to make message"); + return VC_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "@@ vc send specific engine : pid(%d), engine_app_id(%s), event(%s), request(%s)", pid, engine_app_id, event, request); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &engine_app_id, + DBUS_TYPE_STRING, &event, + DBUS_TYPE_STRING, &request, + DBUS_TYPE_INVALID); + + dbus_message_set_no_reply(msg, TRUE); + + if (1 != dbus_connection_send(g_m_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_VCM, "[Dbus ERROR] Fail to Send"); + return -1; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[Dbus] SUCCESS Send"); + dbus_connection_flush(g_m_conn_sender); + } + + return 0; +} diff --git a/client/vc_mgr_dbus.h b/client/vc_mgr_dbus.h index 267aa05..26789e8 100644 --- a/client/vc_mgr_dbus.h +++ b/client/vc_mgr_dbus.h @@ -64,10 +64,16 @@ int vc_mgr_dbus_send_result(int pid, int cmd_type, int result_id); int vc_mgr_dbus_send_result_selection(int pid); +int vc_mgr_dbus_send_specific_engine_request(int pid, const char* engine_app_id, const char* event, const char* request); + int vc_mgr_dbus_request_enable_command_type(int pid, int cmd_type); int vc_mgr_dbus_request_disable_command_type(int pid, int cmd_type); +int vc_mgr_dbus_request_start_feedback(int pid); + +int vc_mgr_dbus_request_stop_feedback(int pid); + #ifdef __cplusplus } #endif diff --git a/client/vc_mgr_player.c b/client/vc_mgr_player.c new file mode 100644 index 0000000..06915f9 --- /dev/null +++ b/client/vc_mgr_player.c @@ -0,0 +1,413 @@ +/* +* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the License); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +#include "vc_main.h" +#include "vc_mgr_player.h" +#include "vc_mgr_data.h" + +typedef enum { + AUDIO_STATE_NONE = 0, + AUDIO_STATE_READY, + AUDIO_STATE_PLAY +} audio_state_e; + +typedef struct { + vc_feedback_state_e state; + + vc_feedback_event_e event; + int idx; +} player_s; + +#define SOUND_BUFFER_LENGTH 2048 + +static bool g_player_init = false; + +static player_s* g_playing_info; + +static audio_state_e g_audio_state; + +static vc_audio_type_e g_audio_type; + +static vc_audio_channel_e g_audio_channel; + +static int g_sampling_rate; + +static audio_out_h g_audio_h; + + +static int __create_audio_out(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type) +{ + int ret = -1; + audio_channel_e sample_channel = 0; + audio_sample_type_e sample_type = 0; + + if (VC_AUDIO_CHANNEL_MONO == channel) { + sample_channel = AUDIO_CHANNEL_MONO; + } else if (VC_AUDIO_CHANNEL_STEREO == channel) { + sample_channel = AUDIO_CHANNEL_STEREO; + } + + if (VC_AUDIO_TYPE_PCM_S16_LE == audio_type) { + sample_type = AUDIO_SAMPLE_TYPE_S16_LE; + } else { + sample_type = AUDIO_SAMPLE_TYPE_U8; + } + + /* create audio_out new */ + ret = audio_out_create_new(rate, sample_channel, sample_type, &g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + g_audio_state = AUDIO_STATE_NONE; + g_audio_h = NULL; + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to create audio"); + return -1; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Create audio"); + } + + g_audio_channel = channel; + g_audio_type = audio_type; + g_sampling_rate = rate; + + g_audio_state = AUDIO_STATE_READY; + + return 0; +} + +static int __destroy_audio_out() +{ + if (NULL == g_audio_h) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Current handle is not valid"); + return -1; + } + + int ret = -1; + ret = audio_out_destroy(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to destroy audio"); + return -1; + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Destroy audio"); + } + + g_audio_channel = 0; + g_audio_type = 0; + g_sampling_rate = 0; + + g_audio_state = AUDIO_STATE_NONE; + g_audio_h = NULL; + + return 0; +} + +int vc_mgr_player_init(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type) +{ + g_audio_state = AUDIO_STATE_NONE; + g_audio_h = NULL; + + ecore_thread_max_set(1); + + int ret = -1; + + + ret = __create_audio_out(rate, channel, audio_type); + if (0 != ret) { + return -1; + } + + g_player_init = true; + + return 0; +} + +int vc_mgr_player_release() +{ + if (false == g_player_init) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Not initialized"); + return VC_ERROR_OPERATION_FAILED; + } + + int ret = -1; + + int thread_count = ecore_thread_active_get(); + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Active thread count : %d", thread_count); + int count = 0; + while (0 < thread_count) { + usleep(10000); + + count++; + if (20 == count) { + SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Thread is blocked. Player release continue"); + break; + } + + thread_count = ecore_thread_active_get(); + } + + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Thread is release"); + + ret = __destroy_audio_out(); + if (0 != ret) { + return -1; + } + + g_player_init = false; + + return 0; +} + +static void __play_feedback_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Start thread"); + + if (NULL == g_playing_info) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] No current player"); + return; + } + + player_s* player = g_playing_info; + vc_feedback_data_s* feedback_data = NULL; + + int ret = -1; + int len = SOUND_BUFFER_LENGTH; + int idx = 0; + + while (1) { + /* get feedback data */ + ret = vc_mgr_data_get_feedback_data(&feedback_data); + if (0 != ret || NULL == feedback_data) { + /* empty queue */ + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] No feedback data. Waiting mode"); + + /* waiting */ + while (1) { + usleep(10000); + if (0 < vc_mgr_data_get_feedback_data_size()) { + SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Resume thread"); + break; + } + + if (AUDIO_STATE_PLAY == g_audio_state) { + /* release audio & recover session */ + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio"); + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Unprepare audio"); + } + g_audio_state = AUDIO_STATE_READY; + } + } + + SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Finish to wait for new feedback data come"); + + /* resume play thread */ + player->state = VC_FEEDBACK_STATE_PLAYING; + continue; + } + + if (VC_FEEDBACK_EVENT_START == feedback_data->event || + (VC_FEEDBACK_EVENT_FINISH == player->event && VC_FEEDBACK_EVENT_FINISH == feedback_data->event)) { + int pid = vc_mgr_data_get_pid(); + SLOG(LOG_INFO, TAG_VCM, "[Player DEBUG] Start utterance (%d)", pid); + } + + player->event = feedback_data->event; + idx = 0; + /* If no feedback data and EVENT_FINISH */ + if (NULL == feedback_data->data || 0 >= feedback_data->data_size) { + if (VC_FEEDBACK_EVENT_FINISH == feedback_data->event) { + int pid = vc_mgr_data_get_pid(); + if (pid <= 0) { + return; + } + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] No sound data"); + } + SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Finish utterance"); + vc_mgr_data_clear_feedback_data(&feedback_data); + continue; + } + + if (g_sampling_rate != feedback_data->rate || g_audio_type != feedback_data->audio_type || g_audio_channel != feedback_data->channel) { + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] change audio handle"); + if (NULL != g_audio_h) { + __destroy_audio_out(); + } + + if (0 > __create_audio_out(feedback_data->rate, feedback_data->channel, feedback_data->audio_type)) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to create audio out"); + vc_mgr_data_clear_feedback_data(&feedback_data); + + return; + } + } + + while (VC_FEEDBACK_STATE_PLAYING == player->state) { + if ((unsigned int)idx >= feedback_data->data_size) + break; + + if ((unsigned int)idx + SOUND_BUFFER_LENGTH > feedback_data->data_size) { + len = feedback_data->data_size - idx; + } else { + len = SOUND_BUFFER_LENGTH; + } + + if (AUDIO_STATE_READY == g_audio_state) { + /* request prepare */ + ret = audio_out_prepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to prepare audio"); + vc_mgr_data_clear_feedback_data(&feedback_data); + return; + } + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Prepare audio"); + g_audio_state = AUDIO_STATE_PLAY; + } + + char* temp_data = feedback_data->data; + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] data(%p), idx(%d), len(%d)", temp_data, idx, len); + + ret = audio_out_write(g_audio_h, &temp_data[idx], len); + if (0 > ret) { + SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Fail to audio write - %d", ret); + } else { + idx += len; + } + + if (NULL == g_playing_info) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Current player is NULL"); + g_audio_state = AUDIO_STATE_READY; + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio"); + } + + vc_mgr_data_clear_feedback_data(&feedback_data); + + return; + } + } + + if (NULL == g_playing_info && VC_FEEDBACK_STATE_READY == player->state) { + /* player stop */ + g_audio_state = AUDIO_STATE_READY; + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Stop play thread"); + + /* request to unprepare audio */ + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio"); + } else { + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Unprepare audio"); + } + + vc_mgr_data_clear_feedback_data(&feedback_data); + return; + } + + if ((VC_FEEDBACK_STATE_PLAYING == player->state) && (VC_FEEDBACK_EVENT_FINISH == feedback_data->event)) { + int pid = vc_mgr_data_get_pid(); + if (pid <= 0) { + return; + } + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Finish utterance"); + } + + vc_mgr_data_clear_feedback_data(&feedback_data); + + if (NULL == g_playing_info) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Current player is NULL"); + g_audio_state = AUDIO_STATE_READY; + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio"); + } + + return; + } + + } + +} + +static void __end_play_feedback_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] End thread"); +} + +int vc_mgr_player_play() +{ + if (false == g_player_init) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Not initialized"); + return VC_ERROR_OPERATION_FAILED; + } + + if (NULL != g_playing_info) { + SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Stop old player"); + vc_mgr_player_stop(); + } + + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] start play"); + + /* check sound queue size */ + int data_size = vc_mgr_data_get_feedback_data_size(); + if (0 == data_size) { + SLOG(LOG_WARN, TAG_VCM, "[Player WARN] A sound queue of current player is empty"); + } else if (0 < data_size) { + SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Run thread"); + ecore_thread_run(__play_feedback_thread, __end_play_feedback_thread, NULL, NULL); + } + + return 0; +} + +int vc_mgr_player_stop() +{ + if (false == g_player_init) { + SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Not initialized"); + return VC_ERROR_OPERATION_FAILED; + } + + if (NULL != g_playing_info) { + g_playing_info = NULL; + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] No more current playing"); + } + + SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] stop play"); + + int thread_count = ecore_thread_active_get(); + int count = 0; + + while (0 < thread_count) { + usleep(10000); + + count++; + if (30 == count) { + SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Thread is blocked. Player release continue"); + break; + } + + thread_count = ecore_thread_active_get(); + } + + return 0; +} diff --git a/client/vc_mgr_player.h b/client/vc_mgr_player.h new file mode 100644 index 0000000..6cf550c --- /dev/null +++ b/client/vc_mgr_player.h @@ -0,0 +1,25 @@ + +#ifndef __VC_MGR_PLAYER_H__ +#define __VC_MGR_PLAYER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int vc_mgr_player_init(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type); + +int vc_mgr_player_release(); + +int vc_mgr_player_play(); + +int vc_mgr_player_stop(); + + +#ifdef __cplusplus +} +#endif + +#endif /* __VC_MGR_PLAYER_H__ */ diff --git a/common/vc_defs.h b/common/vc_defs.h old mode 100755 new mode 100644 index 0299485..096aa4f --- a/common/vc_defs.h +++ b/common/vc_defs.h @@ -66,6 +66,7 @@ extern "C" { #define VC_METHOD_SET_COMMAND "vc_method_set_command" #define VC_METHOD_UNSET_COMMAND "vc_method_unset_command" #define VC_METHOD_SET_FOREGROUND "vc_method_set_foreground" +#define VC_METHOD_SET_SERVER_DIALOG "vc_method_set_server_dialog" #define VC_METHOD_DIALOG "vc_method_dialog" #define VC_METHOD_IS_SYS_COMMAND_VALID "vc_method_is_system_command_valid" @@ -139,6 +140,10 @@ extern "C" { #define VC_MANAGER_METHOD_RESULT_SELECTION "vc_manager_method_result_selection" #define VC_MANAGER_METHOD_SET_DOMAIN "vc_manager_method_set_domain" #define VC_MANAGER_METHOD_DO_ACTION "vc_manager_method_do_action" +#define VC_MANAGER_METHOD_SPECIFIC_ENGINE_REQUEST "vcd_manager_method_specific_engine_request" + +#define VC_MANAGER_METHOD_START_FEEDBACK "vc_manager_method_request_start_feedback" +#define VC_MANAGER_METHOD_STOP_FEEDBACK "vc_manager_method_request_stop_feedback" #define VCD_MANAGER_METHOD_HELLO "vcd_manager_method_hello" #define VCD_MANAGER_METHOD_SPEECH_DETECTED "vcd_manager_method_speech_detected" @@ -150,9 +155,13 @@ extern "C" { #define VCD_MANAGER_METHOD_DIALOG "vcd_manager_method_dialog" #define VCD_MANAGER_METHOD_SET_PRIVATE_DATA "vcd_manager_set_private_data" #define VCD_MANAGER_METHOD_GET_PRIVATE_DATA "vcd_manager_get_private_data" +#define VCD_MANAGER_METHOD_SPECIFIC_ENGINE_RESULT "vcd_manager_method_specific_engine_result" #define VCD_MANAGER_METHOD_ERROR "vcd_manager_method_error" +#define VCD_MANAGER_METHOD_FEEDBACK_AUDIO_FORMAT "vcd_manager_method_feedback_audio_format" +#define VCD_MANAGER_METHOD_FEEDBACK_STREAMING "vcd_manager_method_feedback_streaming" + #define VCC_MANAGER_METHOD_SET_FOREGROUND "vcd_manager_method_set_foreground" diff --git a/common/vc_info_parser.h b/common/vc_info_parser.h index d1532a6..45b7a1e 100644 --- a/common/vc_info_parser.h +++ b/common/vc_info_parser.h @@ -37,6 +37,7 @@ typedef struct _client_s { bool fg_cmd; bool bg_cmd; bool exclusive_cmd; + bool server_dialog; } vc_client_info_s; diff --git a/doc/uix_vc_doc.h b/doc/uix_vc_doc.h index 771f326..d9c6fc9 100644 --- a/doc/uix_vc_doc.h +++ b/doc/uix_vc_doc.h @@ -169,6 +169,11 @@ * * * + * vc_set_server_dialog() + * Ready + * + * + * * vc_request_dialog() * Ready * diff --git a/doc/uix_vc_engine_main_doc.h b/doc/uix_vc_engine_main_doc.h index 6c01165..e81a1fd 100644 --- a/doc/uix_vc_engine_main_doc.h +++ b/doc/uix_vc_engine_main_doc.h @@ -93,6 +93,10 @@ * Called when the engine service user sets audio recording type. * * + * vce_set_server_dialog_cb() + * Called when the engine service user sets app id which is want to ask server dialog. + * + * * vce_set_domain_cb() * Called when the engine service user sets domain (agent or device type). * diff --git a/include/vce.h b/include/vce.h index d37ffbe..c735acd 100644 --- a/include/vce.h +++ b/include/vce.h @@ -18,6 +18,7 @@ #ifndef __VCE_H__ #define __VCE_H__ +#include /** * @addtogroup CAPI_UIX_VOICE_CONTROL_ENGINE_MODULE @@ -101,6 +102,27 @@ typedef enum { } vce_asr_result_event_e; /** + * @brief Enumerations of audio channels + * @since_tizen 5.0 + */ +typedef enum { + VCE_AUDIO_CHANNEL_MONO = 0, /**< 1 channel, mono */ + VCE_AUDIO_CHANNEL_STEREO = 1 /**< 2 channels, stereo */ +} vce_audio_channel_e; + +/** + * @brief Enumeration for TTS feedback events + * @since_tizen 5.0 + */ +typedef enum { + VCE_FEEDBACK_EVENT_FAIL = -1, /**< Failed */ + VCE_FEEDBACK_EVENT_START = 1, /**< Start event */ + VCE_FEEDBACK_EVENT_CONTINUE = 2, /**< Continue event */ + VCE_FEEDBACK_EVENT_FINISH = 3 /**< Finish event */ +} vce_feedback_event_e; + + +/** * @brief A structure of handle for VC command. * @since_tizen 5.0 */ @@ -373,6 +395,19 @@ typedef int (*vce_cancel_cb)(void); typedef int (*vce_set_audio_type_cb)(const char* audio_type); /** +* @brief Called when the engine service user sets app id which is want to ask server dialog. +* @since_tizen 5.0 +* @remarks The @a app_id and @a credential can be used only in the callback. To use outside, make a copy. +* @param[in] app_id App id which is to want to ask server dialog. +* @param[in] credential Credential key. +* @return 0 on success, otherwise a negative error value. +* @retval #VCE_ERROR_NONE Successful. +* @retval #VCE_ERROR_NOT_SUPPORTED_FEATURE Not supported feature. +* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied. +*/ +typedef int (*vce_set_server_dialog_cb)(const char* app_id, const char* credential); + +/** * @brief Called when the engine service user sets domain (agent or device type). * @since_tizen 5.0 * @remarks The @a domain can be used only in the callback. To use outside, make a copy. @@ -396,6 +431,26 @@ typedef int (*vce_set_domain_cb)(const char* domain); typedef int (*vce_nlu_base_info_requested_cb)(const char* key, char** value); /** +* @brief Called when client gets the specific engine's request from the engine service user. +* @since_tizen 5.0 +* +* @param[in] engine_app_id The specific engine's app id +* @param[in] event The specific engine event type +* @param[in] request The specific engine request +* +* @return 0 on success, otherwise a negative error value. +* @retval #VCE_ERROR_NONE Successful +* @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VCE_ERROR_OPERATION_FAILED Operation failure +* +* @pre An application registers callback function using vce_set_specific_engine_request_cb(). +* +* @see vce_set_specific_engine_request_cb() +* @see vce_unset_specific_engine_request_cb() +*/ +typedef int (*vce_specific_engine_request_cb)(const char* engine_app_id, const char* event, const char* request); + +/** * @brief Called when the engine service user sets private data between app and engine. * @since_tizen 5.0 * @remarks The @a key, @a data can be used only in the callback. To use outside, make a copy. @@ -519,11 +574,18 @@ typedef struct { vce_cancel_cb cancel; /**< Cancel recording and processing */ vce_set_audio_type_cb set_audio_type; /**< Set audio type */ + vce_set_server_dialog_cb set_server_dialog; /**< Set server dialog */ vce_set_domain_cb set_domain; /**< Set domain */ vce_process_text_cb process_text; /**< Request to process text */ vce_process_list_event_cb process_list_event; /**< Request to process list event */ vce_process_haptic_event_cb process_haptic_event; /**< Request to process haptic event */ + + /* Optional callbacks */ + vce_private_data_set_cb private_data_set; + vce_private_data_requested_cb private_data_request; + vce_nlu_base_info_requested_cb nlu_base_info_request; + vce_specific_engine_request_cb specific_engine_request; } vce_request_callback_s; /** @@ -693,6 +755,24 @@ int vce_send_asr_result(vce_asr_result_event_e event, const char* asr_result, vo int vce_send_nlg_result(const char* nlg_result, void* user_data); /** +* @brief Sends the specific engine result to the engine service user. +* @since_tizen 5.0 +* +* @param[in] engine_app_id A specific engine's app id +* @param[in] event A specific engine result event +* @param[in] result A specific engine result text +* @param[in] user_data The user data passed from the start +* +* @return 0 on success, otherwise a negative error value +* @retval #VCE_ERROR_NONE Successful +* @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VCE_ERROR_OUT_OF_MEMORY Out of Memory +* @retval #VCE_ERROR_OPERATION_FAILED Operation failure +* @pre The vce_main() function should be invoked before this function is called. +*/ +int vce_send_specific_engine_result(const char* engine_app_id, const char* event, const char* result, void *user_info); + +/** * @brief Sends the error to the engine service user. * @details The following error codes can be delivered. \n * #VCE_ERROR_NONE, \n @@ -771,6 +851,36 @@ int vce_set_private_data_requested_cb(vce_private_data_requested_cb callback_fun int vce_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_func); /** +* @brief Registers a callback function for getting the engine service request. +* @since_tizen 5.0 +* +* @param[in] callback Callback function to register +* @param[in] user_data The user data to be passed to the callback function +* +* @return 0 on success, otherwise a negative error value +* @retval #VCE_ERROR_NONE Successful +* @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied +* @retval #VCE_ERROR_NOT_SUPPORTED Not supported +* +* @see vce_unset_specific_engine_request_cb() +*/ +int vce_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func); + +/** +* @brief Unregisters the engine service request callback function. +* @since_tizen 5.0 +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_PERMISSION_DENIED Permission denied +* @retval #VC_ERROR_NOT_SUPPORTED Not supported +* +* @see vce_set_specific_engine_request_cb() +*/ +int vce_unset_specific_engine_request_cb(void); + +/** * @brief Retrieves all commands using callback function. * @since_tizen 5.0 * @param[in] vce_command The handle to be passed to the vce_set_commands() function @@ -879,6 +989,32 @@ int vce_start_recording(void); */ int vce_stop_recording(void); +/* for TTS feeadback */ +/** +* @brief Sends audio formats necessary for playing TTS feedback. +* @since_tizen 5.0 +* @return 0 on success, otherwise a negative error value. +* @retval #VCE_ERROR_NONE Successful +* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied +* @retval #VCE_ERROR_NOT_SUPPORTED Not supported +* @retval #VCE_ERROR_OPERATION_FAILED Operation failure +* @retval #VCE_ERROR_OUT_OF_MEMORY Out of Memory +*/ +int vce_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_audio_type_e audio_type); + +/** +* @brief Sends audio streaming necessary for playing TTS feedback. +* @since_tizen 5.0 +* @return 0 on success, otherwise a negative error value. +* @retval #VCE_ERROR_NONE Successful +* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied +* @retval #VCE_ERROR_NOT_SUPPORTED Not supported +* @retval #VCE_ERROR_OPERATION_FAILED Operation failure +* @retval #VCE_ERROR_OUT_OF_MEMORY Out of Memory +*/ +int vce_send_feedback_streaming(vce_feedback_event_e event, char* buffer, int len); + + #ifdef __cplusplus } #endif diff --git a/include/voice_control.h b/include/voice_control.h index 9dfe6e0..f46b5c0 100644 --- a/include/voice_control.h +++ b/include/voice_control.h @@ -289,6 +289,49 @@ int vc_set_invocation_name(const char* name); /** + * @brief Requests to set app id which is to want to ask the server dialogue. + * @details Using this function, the developer can request registering the application on vc framework. + * If developer requests to register @a app_id with @a credential which is valid, the application will be set on vc framework. + * and then, when the developer requests the dialogue using vc_request_dialog(), dialog from specific engine server will be played by vc framework. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * @param[in] app_id App id which is to want to ask server dialog. + * @param[in] credential Credential key. + * @return @c 0 on success, + * otherwise a negative error value + * @retval #VC_ERROR_NONE Successful + * @retval #VC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #VC_ERROR_INVALID_STATE Invalid state + * @retval #VC_ERROR_PERMISSION_DENIED Permission denied + * @retval #VC_ERROR_NOT_SUPPORTED Not supported + * @pre The service state should be #VC_SERVICE_STATE_READY. + * @see vc_unset_server_dialog() + */ +int vc_set_server_dialog(const char* app_id, const char* credential); + + +/** + * @brief Requests to unset app id which is to not want to ask the server dialogue. + * @details Using this function, the developer can disable function to ask dialog based on server. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * @param[in] app_id App id which is to not want to ask server dialog. + * @return @c 0 on success, + * otherwise a negative error value + * @retval #VC_ERROR_NONE Successful + * @retval #VC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #VC_ERROR_INVALID_STATE Invalid state + * @retval #VC_ERROR_PERMISSION_DENIED Permission denied + * @retval #VC_ERROR_NOT_SUPPORTED Not supported + * @pre The service state should be #VC_SERVICE_STATE_READY. + * @see vc_set_server_dialog() + */ +int vc_unset_server_dialog(const char* app_id); + + +/** * @brief Requests to start the dialogue. * @details Using this function, the developer can request starting the dialogue to the framework. * When the developer requests the dialogue, two types of texts, @a disp_text and @a utt_text, can be sent by this function. diff --git a/include/voice_control_common.h b/include/voice_control_common.h index b979562..5ae1ffa 100644 --- a/include/voice_control_common.h +++ b/include/voice_control_common.h @@ -93,6 +93,35 @@ typedef enum { VC_STATE_READY = 2 /**< 'Ready' state */ } vc_state_e; +/** +* @brief Enumerations of audio types. +* @since_tizen 5.0 +*/ +typedef enum { + VC_AUDIO_TYPE_PCM_S16_LE = 0, /**< Signed 16bit audio type, Little endian */ + VC_AUDIO_TYPE_PCM_U8 /**< Unsigned 8bit audio type */ +} vc_audio_type_e; + +/** + * @brief Enumerations for audio channels + * @since_tizen 5.0 + */ +typedef enum { + VC_AUDIO_CHANNEL_MONO = 0, /**< 1 channel, mono */ + VC_AUDIO_CHANNEL_STEREO = 1 /**< 2 channels, stereo */ +} vc_audio_channel_e; + +/** + * @brief Enumeration for TTS feedback events + * @since_tizen 5.0 + */ +typedef enum { + VC_FEEDBACK_EVENT_FAIL = -1, /**< Failed */ + VC_FEEDBACK_EVENT_START = 1, /**< Start event */ + VC_FEEDBACK_EVENT_CONTINUE = 2, /**< Continue event */ + VC_FEEDBACK_EVENT_FINISH = 3 /**< Finish event */ +} vc_feedback_event_e; + /** * @brief Called when client gets the recognition result. diff --git a/include/voice_control_manager.h b/include/voice_control_manager.h index cdd8af3..a1aab2b 100644 --- a/include/voice_control_manager.h +++ b/include/voice_control_manager.h @@ -164,6 +164,22 @@ typedef bool (*vc_mgr_all_result_cb)(vc_result_event_e event, vc_cmd_list_h vc_c typedef void (*vc_mgr_pre_result_cb)(vc_pre_result_event_e event, const char *result, void *user_data); /** +* @brief Called when client gets the specific engine's result from vc-service. +* @since_tizen 5.0 +* +* @param[in] engine_app_id The specific engine's app id +* @param[in] event The specific engine event type +* @param[in] result The specific engine result +* @param[in] user_data The user data passed from the callback registration function +* +* @pre An application registers callback function using vc_mgr_set_specific_engine_result_cb(). +* +* @see vc_mgr_set_specific_engine_result_cb() +* @see vc_mgr_unset_specific_engine_result_cb() +*/ +typedef void (*vc_mgr_specific_engine_result_cb)(const char* engine_app_id, const char* event, const char* result, void *user_data); + +/** * @brief Called when user speaking is detected. * @since_tizen 5.0 * @@ -230,6 +246,38 @@ typedef int (*vc_mgr_private_data_set_cb)(const char *key, const char *data, voi */ typedef int (*vc_mgr_private_data_requested_cb)(const char *key, char **data, void *user_data); +/* for TTS feedback */ +/** +* @brief Called when engine sends audio formats necessary for playing TTS feedback +* +* @param[in] rate Audio sampling rate +* @param[in] channel Audio channel (e.g. #VC_AUDIO_CHANNEL_MONO, #VC_AUDIO_CHANNEL_STEREO) +* @param[in] audio_type Audio type (e.g. #VC_AUDIO_TYPE_PCM_S16_LE, #VC_AUDIO_TYPE_PCM_U8) +* @param[in] user_data The user data passed from the callback registration function +* +* @pre An application registers callback function using vc_mgr_set_feedback_audio_format_cb(). +* +* @see vc_mgr_set_feedback_audio_format_cb() +* @see vc_mgr_unset_feedback_audio_format_cb() +*/ +typedef void (*vc_mgr_feedback_audio_format_cb)(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type, void *user_data); + +/** +* @brief Called when engine sends audio streaming for TTS feedback +* +* @param[in] event TTS feedback event (e.g. #VC_FEEDBACK_EVENT_START, #VC_FEEDBACK_EVENT_CONTINUE) +* @param[in] buffer Audio streaming data +* @param[in] len Length of the audio streaming data +* @param[in] user_data The user data passed from the callback registration function +* +* @pre An application registers callback function using vc_mgr_set_feedback_streaming_cb(). +* +* @see vc_mgr_set_feedback_streaming_cb() +* @see vc_mgr_unset_feedback_streaming_cb() +*/ +typedef void (*vc_mgr_feedback_streaming_cb)(vc_feedback_event_e event, char* buffer, int len, void *user_data); + + /** * @platform * @brief Initializes the voice control manager. @@ -745,6 +793,23 @@ int vc_mgr_get_private_data(const char *key, char **data); int vc_mgr_do_action(vc_send_event_type_e type, char *send_event); /** +* @brief Sends the specific engine request to the vc-service. +* @since_tizen 5.0 +* +* @param[in] engine_app_id A specific engine's app id +* @param[in] event A engine service user request event +* @param[in] request A engine service user request text +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_OUT_OF_MEMORY Not enough memory +* @retval #VC_ERROR_INVALID_STATE Invalid state +* @retval #VC_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VC_ERROR_OPERATION_FAILED Operation failure +*/ +int vc_mgr_send_specific_engine_request(const char* engine_app_id, const char* event, const char* request); + +/** * @platform * @brief Starts recognition. * @since_tizen 5.0 @@ -975,6 +1040,42 @@ int vc_mgr_set_pre_result_cb(vc_mgr_pre_result_cb callback, void *user_data); int vc_mgr_unset_pre_result_cb(void); /** +* @brief Registers a callback function for getting specific engine result. +* @since_tizen 5.0 +* +* @param[in] callback Callback function to register +* @param[in] user_data The user data to be passed to the callback function +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VC_ERROR_INVALID_STATE Invalid state +* @retval #VC_ERROR_PERMISSION_DENIED Permission denied +* @retval #VC_ERROR_NOT_SUPPORTED Not supported +* +* @pre The state should be #VC_STATE_INITIALIZED. +* +* @see vc_mgr_unset_specific_engine_result_cb() +*/ +int vc_mgr_set_specific_engine_result_cb(vc_mgr_specific_engine_result_cb callback, void* user_data); + +/** +* @brief Unregisters the specific engine result callback function. +* @since_tizen 5.0 +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_STATE Invalid state +* @retval #VC_ERROR_PERMISSION_DENIED Permission denied +* @retval #VC_ERROR_NOT_SUPPORTED Not supported +* +* @pre The state should be #VC_STATE_INITIALIZED. +* +* @see vc_mgr_set_specific_engine_result_cb() +*/ +int vc_mgr_unset_specific_engine_result_cb(void); + +/** * @platform * @brief Sets a callback function for getting all types of recognition results. * @since_tizen 5.0 @@ -1451,6 +1552,107 @@ int vc_mgr_set_private_data_requested_cb(vc_mgr_private_data_requested_cb callba */ int vc_mgr_unset_private_data_requested_cb(void); +/* for TTS feedback */ +/** +* @brief Sets a callback function to be called when engine sends audio formats necessary for playing TTS feedback. +* +* @param[in] callback Callback function to set +* @param[in] user_data The user data to be passed to the callback function +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VC_ERROR_INVALID_STATE Invalid state +* +* @pre The state should be #VC_STATE_INITIALIZED. +* +* @see vc_mgr_feedback_audio_format_cb() +* @see vc_mgr_unset_feedback_audio_format_cb() +*/ +int vc_mgr_set_feedback_audio_format_cb(vc_mgr_feedback_audio_format_cb callback, void* user_data); + +/** +* @brief Unsets a callback function to be called when engine sends audio formats necessary for playing TTS feedback. +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_STATE Invalid state +* +* @pre The state should be #VC_STATE_INITIALIZED. +* +* @see vc_mgr_feedback_audio_format_cb() +* @see vc_mgr_set_feedback_audio_format_cb() +*/ +int vc_mgr_unset_feedback_audio_format_cb(void); + +/** +* @brief Sets a callback function to be called when engine sends audio streaming for TTS feedback. +* +* @param[in] callback Callback function to set +* @param[in] user_data The user data to be passed to the callback function +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #VC_ERROR_INVALID_STATE Invalid state +* +* @pre The state should be #VC_STATE_INITIALIZED. +* +* @see vc_mgr_feedback_streaming_cb() +* @see vc_mgr_unset_feedback_streaming_cb() +*/ +int vc_mgr_set_feedback_streaming_cb(vc_mgr_feedback_streaming_cb callback, void* user_data); + +/** +* @brief Unsets a callback function to be called when engine sends audio streaming for TTS feedback. +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_STATE Invalid state +* +* @pre The state should be #VC_STATE_INITIALIZED. +* +* @see vc_mgr_feedback_streaming_cb() +* @see vc_mgr_set_feedback_streaming_cb() +*/ +int vc_mgr_unset_feedback_streaming_cb(void); + +/** +* @brief Starts getting TTS feedback streaming data from the buffer. +* +* @remarks In order to get TTS feedback streaming data, the application should set 'vc_mgr_feedback_streaming_cb()' using vc_mgr_set_feedback_streaming_cb(). +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_STATE Invalid state +* +* @pre The state should be #VC_STATE_READY. \n +* 'vc_mgr_feedback_streaming_cb()' should be registered. +* +* @see vc_mgr_feedback_streaming_cb() +* @see vc_mgr_set_feedback_streaming_cb() +* @see vc_mgr_unset_feedback_streaming_cb() +* @see vc_mgr_stop_feedback() +*/ +int vc_mgr_start_feedback(void); + +/** +* @brief Stops getting and removes TTS feedback streaming data from the buffer. +* +* @return 0 on success, otherwise a negative error value +* @retval #VC_ERROR_NONE Successful +* @retval #VC_ERROR_INVALID_STATE Invalid state +* +* @pre The state should be #VC_STATE_READY. +* +* @see vc_mgr_feedback_streaming_cb() +* @see vc_mgr_set_feedback_streaming_cb() +* @see vc_mgr_unset_feedback_streaming_cb() +* @see vc_mgr_start_feedback() +*/ +int vc_mgr_stop_feedback(void); + + #ifdef __cplusplus } #endif diff --git a/server/vcd_client_data.c b/server/vcd_client_data.c index 4ae7bb3..6953e17 100644 --- a/server/vcd_client_data.c +++ b/server/vcd_client_data.c @@ -769,6 +769,38 @@ vcd_recognition_mode_e vcd_client_get_recognition_mode() return g_recognition_mode; } +int vcd_client_set_server_dialog(int pid, bool is_server_dialog) +{ + vc_client_info_s* client_info = NULL; + + client_info = __client_get_element(pid); + if (NULL == client_info) { + SLOG(LOG_ERROR, TAG_VCD, "[Client Data ERROR] vcd_client_get_pid : pid(%d) is not found", pid); + return VCD_ERROR_INVALID_PARAMETER; + } + + client_info->server_dialog = is_server_dialog; + + SLOG(LOG_DEBUG, TAG_VCD, "[Client Data] Set server dialog, client pid(%d), server_dialog(%d)", pid, client_info->server_dialog); + return 0; +} + +int vcd_client_get_server_dialog(int pid, bool* is_server_dialog) +{ + vc_client_info_s* client_info = NULL; + + client_info = __client_get_element(pid); + if (NULL == client_info) { + SLOG(LOG_ERROR, TAG_VCD, "[Client Data ERROR] vcd_client_get_pid : pid(%d) is not found", pid); + return VCD_ERROR_INVALID_PARAMETER; + } + + *is_server_dialog = client_info->server_dialog; + + SLOG(LOG_DEBUG, TAG_VCD, "[Client Data] Get server dialog, client pid(%d), server_dialog(%d)", pid, *is_server_dialog); + return 0; +} + int vcd_client_append_cmd_from_type(int type, vc_cmd_list_h list) { GSList *item = NULL; @@ -998,6 +1030,7 @@ int vcd_client_add(int pid) info->fg_cmd = false; info->bg_cmd = false; info->exclusive_cmd = false; + info->server_dialog = false; /* Add item to global list */ g_client_list = g_slist_append(g_client_list, info); diff --git a/server/vcd_client_data.h b/server/vcd_client_data.h index 3ee5f0d..6060c81 100644 --- a/server/vcd_client_data.h +++ b/server/vcd_client_data.h @@ -155,6 +155,11 @@ int vcd_client_unset_exclusive_command(int pid); int vcd_client_save_client_info(); void vcd_client_update_foreground_pid(); + +int vcd_client_set_server_dialog(int pid, bool is_server_dialog); + +int vcd_client_get_server_dialog(int pid, bool* is_server_dialog); + /* * widget API */ diff --git a/server/vcd_dbus.c b/server/vcd_dbus.c old mode 100755 new mode 100644 index 250e5a0..5b3d4ee --- a/server/vcd_dbus.c +++ b/server/vcd_dbus.c @@ -405,6 +405,42 @@ int vcdc_send_pre_result_to_manager(int manager_pid, int event, const char* pre_ return 0; } +int vcdc_send_specific_engine_result_to_manager(int manager_pid, const char* engine_app_id, const char* event, const char* result) +{ + SLOG(LOG_DEBUG, TAG_VCD, "[VCDC] send specific engine result to manager, mgr pid(%d), engine app id(%s), event(%s), result(%s),", + manager_pid, engine_app_id, event, result); + + if (0 != __dbus_check()) { + return VCD_ERROR_OPERATION_FAILED; + } + + DBusError err; + dbus_error_init(&err); + + DBusMessage* msg = NULL; + + msg = __get_message(manager_pid, VCD_MANAGER_METHOD_SPECIFIC_ENGINE_RESULT, VCD_CLIENT_TYPE_MANAGER); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Message is NULL"); + return VCD_ERROR_OUT_OF_MEMORY; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &engine_app_id, DBUS_TYPE_STRING, &event, DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID); + + dbus_message_set_no_reply(msg, TRUE); + + if (1 != dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Fail to Send"); + return VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCD, "[Dbus] SUCCESS Send"); + dbus_connection_flush(g_conn_sender); + } + + return 0; +} + int vcdc_send_result_to_manager(int manger_pid, int result_type) { if (0 != __dbus_check()) { @@ -902,6 +938,90 @@ int vcdc_send_request_get_private_data(int pid, const char* key, char** data) return result; } +int vcdc_send_feedback_audio_format_to_manager(int manager_pid, int rate, vc_audio_channel_e channel, vce_audio_type_e audio_type) +{ + SLOG(LOG_INFO, TAG_VCD, "[Dbus] Send TTS feedback audio format : manager_pid(%d), rate(%d), audio channel(%d), audio type(%d)", manager_pid, rate, channel, audio_type); + + if (0 != __dbus_check()) { + return VCD_ERROR_OPERATION_FAILED; + } + + DBusError err; + dbus_error_init(&err); + + /* make dbus message */ + DBusMessage* msg = NULL; + msg = __get_message(manager_pid, VCD_MANAGER_METHOD_FEEDBACK_AUDIO_FORMAT, VCD_CLIENT_TYPE_MANAGER); + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Message is NULL"); + return VCD_ERROR_OUT_OF_MEMORY; + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &rate, + DBUS_TYPE_INT32, &channel, + DBUS_TYPE_INT32, &audio_type, + DBUS_TYPE_INVALID); + + dbus_message_set_no_reply(msg, TRUE); + + int ret = VCD_ERROR_NONE; + + if (1 != dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Fail to Send"); + ret = VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_INFO, TAG_VCD, "[Dbus] SUCCESS Send"); + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + + return ret; +} + +int vcdc_send_feedback_streaming_to_manager(int manager_pid, vc_feedback_event_e event, char* buffer, int len) +{ + SLOG(LOG_INFO, TAG_VCD, "[Dbus] Send TTS feedback streaming : manager_pid(%d), feedback event(%d), buffer(%p), length(%d)", manager_pid, event, buffer, len); + + if (0 != __dbus_check()) { + return VCD_ERROR_OPERATION_FAILED; + } + + DBusError err; + dbus_error_init(&err); + + /* make dbus message */ + DBusMessage* msg = NULL; + msg = __get_message(manager_pid, VCD_MANAGER_METHOD_FEEDBACK_STREAMING, VCD_CLIENT_TYPE_MANAGER); + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Message is NULL"); + return VCD_ERROR_OUT_OF_MEMORY; + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &event, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &buffer, len, + DBUS_TYPE_INVALID); + + dbus_message_set_no_reply(msg, TRUE); + + int ret = VCD_ERROR_NONE; + + if (1 != dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_VCD, "[Dbus ERROR] Fail to Send"); + ret = VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_INFO, TAG_VCD, "[Dbus] SUCCESS Send"); + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + + return ret; +} + static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handler) { if (NULL == g_conn_listener) return ECORE_CALLBACK_RENEW; @@ -970,12 +1090,21 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_MANAGER_METHOD_DO_ACTION)) vcd_dbus_server_mgr_do_action(g_conn_listener, msg); + else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_MANAGER_METHOD_SPECIFIC_ENGINE_REQUEST)) + vcd_dbus_server_mgr_send_specific_engine_request(g_conn_listener, msg); + else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_MANAGER_METHOD_ENABLE_COMMAND_TYPE)) vcd_dbus_server_mgr_enable_command_type(g_conn_listener, msg); else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_MANAGER_METHOD_DISABLE_COMMAND_TYPE)) vcd_dbus_server_mgr_disable_command_type(g_conn_listener, msg); + else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_MANAGER_METHOD_START_FEEDBACK)) + vcd_dbus_server_mgr_start_feedback(g_conn_listener, msg); + + else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_MANAGER_METHOD_STOP_FEEDBACK)) + vcd_dbus_server_mgr_stop_feedback(g_conn_listener, msg); + /* client event */ else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_METHOD_INITIALIZE)) vcd_dbus_server_initialize(g_conn_listener, msg); @@ -995,6 +1124,9 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_METHOD_SET_FOREGROUND)) vcd_dbus_server_set_foreground(g_conn_listener, msg); + else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_METHOD_SET_SERVER_DIALOG)) + vcd_dbus_server_set_server_dialog(g_conn_listener, msg); + else if (dbus_message_is_method_call(msg, VC_SERVER_SERVICE_INTERFACE, VC_METHOD_DIALOG)) vcd_dbus_server_dialog(g_conn_listener, msg); diff --git a/server/vcd_dbus.h b/server/vcd_dbus.h index d4674ec..0dbe188 100644 --- a/server/vcd_dbus.h +++ b/server/vcd_dbus.h @@ -48,6 +48,8 @@ int vcdc_send_asr_result(int pid, int event, const char* asr_result, int cmd_typ int vcdc_send_pre_result_to_manager(int manager_pid, int event, const char* pre_result); +int vcdc_send_specific_engine_result_to_manager(int manager_pid, const char* engine_app_id, const char* event, const char* result); + int vcdc_send_result_to_manager(int manger_pid, int result_type); int vcdc_send_speech_detected(int manger_pid); @@ -66,6 +68,12 @@ int vcdc_send_request_set_private_data(int pid, const char* key, const char* dat int vcdc_send_request_get_private_data(int pid, const char* key, char** data); +/* for TTS feedback */ +int vcdc_send_feedback_audio_format_to_manager(int manager_pid, int rate, vc_audio_channel_e channel, vce_audio_type_e audio_type); + +int vcdc_send_feedback_streaming_to_manager(int manager_pid, vc_feedback_event_e event, char* buffer, int len); + + #ifdef __cplusplus } #endif diff --git a/server/vcd_dbus_server.c b/server/vcd_dbus_server.c old mode 100755 new mode 100644 index 6a6a15d..297ef13 --- a/server/vcd_dbus_server.c +++ b/server/vcd_dbus_server.c @@ -620,6 +620,39 @@ int vcd_dbus_server_mgr_get_private_data(DBusConnection* conn, DBusMessage* msg) return 0; } +int vcd_dbus_server_mgr_send_specific_engine_request(DBusConnection* conn, DBusMessage* msg) +{ + DBusError err; + dbus_error_init(&err); + + int pid = 0; + char* engine_app_id = NULL; + char* event = NULL; + char* request = NULL; + + int ret = VCD_ERROR_OPERATION_FAILED; + + SLOG(LOG_DEBUG, TAG_VCD, "@@@ VCD Manager specific engine request"); + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &engine_app_id, + DBUS_TYPE_STRING, &event, + DBUS_TYPE_STRING, &request, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCD, "[IN ERROR] vcd mgr specific engine request : get arguments error (%s)", err.message); + dbus_error_free(&err); + ret = VCD_ERROR_OPERATION_FAILED; + } else { + ret = vcd_server_mgr_send_specific_engine_request(pid, engine_app_id, event, request); + SLOG(LOG_DEBUG, TAG_VCD, "[IN] vcd mgr specific engine request : pid(%d), engine_app_id(%s), event(%s), request(%s), ret(%d)", pid, engine_app_id, event, request, ret); + } + + return 0; +} + int vcd_dbus_server_mgr_set_domain(DBusConnection* conn, DBusMessage* msg) { DBusError err; @@ -630,7 +663,7 @@ int vcd_dbus_server_mgr_set_domain(DBusConnection* conn, DBusMessage* msg) int ret = VCD_ERROR_OPERATION_FAILED; - SLOG(LOG_DEBUG, TAG_VCD, "@@@ VCD Manager set audio type"); + SLOG(LOG_DEBUG, TAG_VCD, "@@@ VCD Manager set domain type"); dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &pid, @@ -1033,6 +1066,114 @@ int vcd_dbus_server_mgr_result_selection(DBusConnection* conn, DBusMessage* msg) */ } +/* for TTS feedback */ +int vcd_dbus_server_mgr_start_feedback(DBusConnection* conn, DBusMessage* msg) +{ + DBusError err; + dbus_error_init(&err); + + int pid = 0; + + int ret = VCD_ERROR_OPERATION_FAILED; + + SLOG(LOG_DEBUG, TAG_VCD, "@@@ VCD Manager start TTS feedback"); + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] vcd mgr start TTS feedback : get arguments error (%s)", err.message); + dbus_error_free(&err); + ret = VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCD, "[DEBUG] vcd mgr start TTS feedback : pid(%d)", pid); + ret = vcd_server_mgr_start_feedback(); + } + + DBusMessage* reply; + reply = dbus_message_new_method_return(msg); + + if (NULL != reply) { + dbus_message_append_args(reply, + DBUS_TYPE_INT32, &ret, + DBUS_TYPE_INVALID); + + if (0 == ret) { + SLOG(LOG_DEBUG, TAG_VCD, "[SUCCESS] Result(%d)", ret); + } else { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Result(%d)", ret); + } + + if (!dbus_connection_send(conn, reply, NULL)) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Out of Memory"); + } + + dbus_connection_flush(conn); + dbus_message_unref(reply); + } else { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to create reply message"); + } + + SLOG(LOG_DEBUG, TAG_VCD, "@@@"); + + return 0; +} + +int vcd_dbus_server_mgr_stop_feedback(DBusConnection* conn, DBusMessage* msg) +{ + DBusError err; + dbus_error_init(&err); + + int pid = 0; + + int ret = VCD_ERROR_OPERATION_FAILED; + + SLOG(LOG_DEBUG, TAG_VCD, "@@@ VCD Manager stop TTS feedback"); + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] vcd mgr stop TTS feedback : get arguments error (%s)", err.message); + dbus_error_free(&err); + ret = VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCD, "[DEBUG] vcd mgr stop TTS feedback : pid(%d)", pid); + ret = vcd_server_mgr_stop_feedback(); + } + + DBusMessage* reply; + reply = dbus_message_new_method_return(msg); + + if (NULL != reply) { + dbus_message_append_args(reply, + DBUS_TYPE_INT32, &ret, + DBUS_TYPE_INVALID); + + if (0 == ret) { + SLOG(LOG_DEBUG, TAG_VCD, "[SUCCESS] Result(%d)", ret); + } else { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Result(%d)", ret); + } + + if (!dbus_connection_send(conn, reply, NULL)) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Out of Memory"); + } + + dbus_connection_flush(conn); + dbus_message_unref(reply); + } else { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to create reply message"); + } + + SLOG(LOG_DEBUG, TAG_VCD, "@@@"); + + return 0; +} + + /* * Dbus Server functions for client */ @@ -1330,6 +1471,64 @@ int vcd_dbus_server_set_foreground(DBusConnection* conn, DBusMessage* msg) return 0; } +int vcd_dbus_server_set_server_dialog(DBusConnection* conn, DBusMessage* msg) +{ + DBusError err; + dbus_error_init(&err); + + int pid = -1; + char* app_id = NULL; + char* credential = NULL; + int ret = VCD_ERROR_OPERATION_FAILED; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &app_id, + DBUS_TYPE_STRING, &credential, + DBUS_TYPE_INVALID); + + SLOG(LOG_DEBUG, TAG_VCD, "@@@ VCD set server dialog"); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_VCD, "[IN ERROR] vcd set server dialog : get arguments error (%s)", err.message); + dbus_error_free(&err); + ret = VCD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_VCD, "[IN] vcd set server dialog : pid(%d), app_id(%s)", pid, app_id); + ret = vcd_server_set_server_dialog(pid, app_id, credential); + } + + DBusMessage* reply; + reply = dbus_message_new_method_return(msg); + + if (NULL != reply) { + if (0 == ret) { + /* Append result and language */ + dbus_message_append_args(reply, DBUS_TYPE_INT32, &ret, DBUS_TYPE_INVALID); + + SLOG(LOG_DEBUG, TAG_VCD, "[OUT SUCCESS] Result(%d)", ret); + } else { + dbus_message_append_args(reply, DBUS_TYPE_INT32, &ret, DBUS_TYPE_INVALID); + + SLOG(LOG_ERROR, TAG_VCD, "[OUT ERROR] Result(%d)", ret); + } + + if (!dbus_connection_send(conn, reply, NULL)) { + SLOG(LOG_ERROR, TAG_VCD, "[OUT ERROR] Out Of Memory!"); + } + + dbus_connection_flush(conn); + dbus_message_unref(reply); + } else { + SLOG(LOG_ERROR, TAG_VCD, "[OUT ERROR] Fail to create reply message!!"); + } + + SLOG(LOG_DEBUG, TAG_VCD, "@@@"); + + return 0; + +} + int vcd_dbus_server_dialog(DBusConnection* conn, DBusMessage* msg) { DBusError err; diff --git a/server/vcd_dbus_server.h b/server/vcd_dbus_server.h index caa87df..1456536 100644 --- a/server/vcd_dbus_server.h +++ b/server/vcd_dbus_server.h @@ -67,6 +67,14 @@ int vcd_dbus_server_mgr_enable_command_type(DBusConnection* conn, DBusMessage* m int vcd_dbus_server_mgr_disable_command_type(DBusConnection* conn, DBusMessage* msg); +int vcd_dbus_server_mgr_send_specific_engine_request(DBusConnection* conn, DBusMessage* msg); + +/* for TTS feedback */ +int vcd_dbus_server_mgr_start_feedback(DBusConnection* conn, DBusMessage* msg); + +int vcd_dbus_server_mgr_stop_feedback(DBusConnection* conn, DBusMessage* msg); + + /* * Dbus Server functions for client */ @@ -85,6 +93,8 @@ int vcd_dbus_server_unset_command(DBusConnection* conn, DBusMessage* msg); int vcd_dbus_server_set_foreground(DBusConnection* conn, DBusMessage* msg); +int vcd_dbus_server_set_server_dialog(DBusConnection* conn, DBusMessage* msg); + int vcd_dbus_server_dialog(DBusConnection* conn, DBusMessage* msg); int vcd_dbus_server_is_system_command_valid(DBusConnection* conn, DBusMessage* msg); diff --git a/server/vcd_engine_agent.c b/server/vcd_engine_agent.c index bd3ecea..da79346 100644 --- a/server/vcd_engine_agent.c +++ b/server/vcd_engine_agent.c @@ -42,7 +42,7 @@ typedef struct { bool use_network; void *handle; - vc_engine_callback_s* callbacks; + vce_request_callback_s* callbacks; } vcengine_s; typedef struct _vcengine_info { @@ -94,7 +94,7 @@ int vcd_engine_agent_init() g_dynamic_engine.handle = NULL; g_dynamic_engine.is_command_ready = false; - g_dynamic_engine.callbacks = (vc_engine_callback_s*)calloc(1, sizeof(vc_engine_callback_s)); + g_dynamic_engine.callbacks = (vce_request_callback_s*)calloc(1, sizeof(vce_request_callback_s)); if (NULL == g_dynamic_engine.callbacks) { SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent] Fail to allocate memory"); return VCD_ERROR_OUT_OF_MEMORY; @@ -186,7 +186,7 @@ int __internal_get_engine_info(vce_request_callback_s* callback) free(g_dynamic_engine.callbacks); g_dynamic_engine.callbacks = NULL; } - g_dynamic_engine.callbacks = (vc_engine_callback_s*)calloc(1, sizeof(vc_engine_callback_s)); + g_dynamic_engine.callbacks = (vce_request_callback_s*)calloc(1, sizeof(vce_request_callback_s)); if (NULL == g_dynamic_engine.callbacks) { SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Fail to allocate memory"); return VCD_ERROR_OUT_OF_MEMORY; @@ -208,6 +208,7 @@ int __internal_get_engine_info(vce_request_callback_s* callback) g_dynamic_engine.callbacks->cancel = callback->cancel; g_dynamic_engine.callbacks->set_domain = callback->set_domain; g_dynamic_engine.callbacks->set_audio_type = callback->set_audio_type; + g_dynamic_engine.callbacks->set_server_dialog = callback->set_server_dialog; g_dynamic_engine.callbacks->process_text = callback->process_text; g_dynamic_engine.callbacks->process_list_event = callback->process_list_event; g_dynamic_engine.callbacks->process_haptic_event = callback->process_haptic_event; @@ -215,6 +216,7 @@ int __internal_get_engine_info(vce_request_callback_s* callback) g_dynamic_engine.callbacks->private_data_set = NULL; g_dynamic_engine.callbacks->private_data_request = NULL; g_dynamic_engine.callbacks->nlu_base_info_request = NULL; + g_dynamic_engine.callbacks->specific_engine_request = NULL; SLOG(LOG_DEBUG, TAG_VCD, "@@@ Valid Engine"); SLOG(LOG_DEBUG, TAG_VCD, "Engine uuid : %s", g_dynamic_engine.engine_uuid); @@ -266,6 +268,7 @@ int vcd_engine_agent_load_current_engine(vce_request_callback_s* callback) NULL == g_dynamic_engine.callbacks->stop || NULL == g_dynamic_engine.callbacks->cancel || NULL == g_dynamic_engine.callbacks->set_audio_type || + NULL == g_dynamic_engine.callbacks->set_server_dialog || NULL == g_dynamic_engine.callbacks->set_domain || NULL == g_dynamic_engine.callbacks->process_text || NULL == g_dynamic_engine.callbacks->process_list_event || @@ -472,6 +475,25 @@ int vcd_engine_set_audio_type(const char* audio) return 0; } +int vcd_engine_set_server_dialog(const char* app_id, const char* credential) +{ + if (false == g_agent_init) { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Not Initialized"); + return VCD_ERROR_OPERATION_FAILED; + } + + int ret = -1; + if (true == g_dynamic_engine.is_loaded) { + ret = g_dynamic_engine.callbacks->set_server_dialog(app_id, credential); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Fail to set server dialog (%d)", ret); + return ret; + } + } + + return 0; +} + int vcd_engine_set_domain(int pid, const char* domain) { if (false == g_agent_init) { @@ -567,6 +589,28 @@ int vcd_engine_get_private_data(int pid, const char* key, char** data) return 0; } +int vcd_engine_send_specific_engine_request(const char* engine_app_id, const char* event, const char* request) +{ + if (false == g_agent_init) { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Not Initialized"); + return VCD_ERROR_OPERATION_FAILED; + } + + int ret = -1; + if (true == g_dynamic_engine.is_loaded && NULL != g_dynamic_engine.callbacks->specific_engine_request) { + ret = g_dynamic_engine.callbacks->specific_engine_request(engine_app_id, event, request); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Fail to set specific engine request (%d)", ret); + return VCD_ERROR_OPERATION_FAILED; + } + } else { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Engine is not loaded or There is no specific_engine_request callback"); + return VCD_ERROR_OPERATION_FAILED; + } + + return 0; +} + int vcd_engine_process_text(int pid, const char* text) { if (false == g_agent_init) { @@ -844,3 +888,19 @@ int vcd_engine_agent_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_ return VCD_ERROR_NONE; } +int vcd_engine_agent_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func) +{ + if (false == g_agent_init) { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Not Initialized"); + return VCD_ERROR_OPERATION_FAILED; + } + + if (false == g_dynamic_engine.is_loaded) { + SLOG(LOG_ERROR, TAG_VCD, "[Engine Agent ERROR] Not loaded engine"); + return VCD_ERROR_OPERATION_FAILED; + } + + g_dynamic_engine.callbacks->specific_engine_request = callback_func; + + return VCD_ERROR_NONE; +} diff --git a/server/vcd_engine_agent.h b/server/vcd_engine_agent.h index a327584..4dc5e25 100644 --- a/server/vcd_engine_agent.h +++ b/server/vcd_engine_agent.h @@ -66,6 +66,8 @@ int vcd_engine_recognize_cancel(); int vcd_engine_set_audio_type(const char* audio); +int vcd_engine_set_server_dialog(const char* app_id, const char* credential); + int vcd_engine_set_domain(int pid, const char* domain); int vcd_engine_get_nlu_base_info(int pid, const char* key, char** value); @@ -74,6 +76,8 @@ int vcd_engine_set_private_data(int pid, const char* key, const char* data); int vcd_engine_get_private_data(int pid, const char* key, char** data); +int vcd_engine_send_specific_engine_request(const char* engine_app_id, const char* event, const char* request); + int vcd_engine_process_text(int pid, const char* text); int vcd_engine_process_list_event(int pid, const char* event); @@ -101,6 +105,7 @@ int vcd_engine_agent_set_private_data_requested_cb(vce_private_data_requested_cb int vcd_engine_agent_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_func); +int vcd_engine_agent_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func); #ifdef __cplusplus } diff --git a/server/vcd_main.h b/server/vcd_main.h index 72e105c..a9f7943 100644 --- a/server/vcd_main.h +++ b/server/vcd_main.h @@ -32,6 +32,8 @@ #include "vc_defs.h" #include "vce.h" +#include "voice_control_common.h" + #ifdef __cplusplus extern "C" { @@ -76,43 +78,6 @@ typedef struct { int index; } vce_cmd_s; -typedef struct { - int version; /**< Version */ - - /* Mandatory callbacks */ - /* Get engine information */ - vce_get_info_cb get_info; /**< Called when the engine service user requests the basic information of VC engine */ - vce_get_recording_format_cb get_recording_format; /**< Get recording format */ - vce_foreach_supported_languages_cb foreach_langs; /**< Foreach language list */ - vce_is_language_supported_cb is_lang_supported; /**< Check language */ - - vce_initialize_cb initialize; /**< Initialize engine */ - vce_deinitialize_cb deinitialize; /**< Shutdown engine */ - - /* Set info */ - vce_set_language_cb set_language; /**< Set language */ - vce_set_commands_cb set_commands; /**< Request to set current commands */ - vce_unset_commands_cb unset_commands; /**< Request to unset current commands */ - - /* Control recognition */ - vce_start_cb start; /**< Start recognition */ - vce_set_recording_data_cb set_recording; /**< Set recording data */ - vce_stop_cb stop; /**< Stop recording for getting result */ - vce_cancel_cb cancel; /**< Cancel recording and processing */ - - vce_set_audio_type_cb set_audio_type; /**< Set audio type */ - - vce_set_domain_cb set_domain; /**< Set domain */ - vce_process_text_cb process_text; /**< Request to process text */ - vce_process_list_event_cb process_list_event; /**< Request to process list event */ - vce_process_haptic_event_cb process_haptic_event; /**< Request to process haptic event */ - - /* Optional callbacks */ - vce_private_data_set_cb private_data_set; - vce_private_data_requested_cb private_data_request; - vce_nlu_base_info_requested_cb nlu_base_info_request; -} vc_engine_callback_s; - #ifdef __cplusplus } diff --git a/server/vcd_server.c b/server/vcd_server.c index ef9dc76..d5bf69b 100644 --- a/server/vcd_server.c +++ b/server/vcd_server.c @@ -445,6 +445,21 @@ int vcd_send_asr_result(vce_asr_result_event_e event, const char* asr_result, vo return ret; } +int vcd_send_specific_engine_result(const char* engine_app_id, const char* event, const char* result, void *user_info) +{ + if (NULL != result) { + SLOG(LOG_DEBUG, TAG_VCD, "[Server] specific engine result - Event(%s), Text(%s)", event, result); + vcdc_send_specific_engine_result_to_manager(vcd_client_manager_get_pid(), engine_app_id, event, result); + } + + if (VCD_RECOGNITION_MODE_RESTART_CONTINUOUSLY != vcd_client_get_recognition_mode()) { + vcd_config_set_service_state(VCD_STATE_READY); + vcdc_send_service_state(VCD_STATE_READY); + } + + return VCD_ERROR_NONE; +} + int vcd_send_nlg_result(const char* nlg_result, void *user_data) { int ret = __vcd_server_launch_manager_app(); @@ -1078,6 +1093,36 @@ int vcd_send_error(vce_error_e error, const char* msg, void *user_data) return ret; } +/* for TTS feedback */ +int vcd_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_audio_type_e audio_type) +{ + SLOG(LOG_INFO, TAG_VCD, "[Server DEBUG] Engine - Send TTS feedback audio format"); + + /* send TTS feedback audio format to VC manager */ + int ret = VCD_ERROR_NONE; + ret = vcdc_send_feedback_audio_format_to_manager(vcd_client_manager_get_pid(), rate, channel, audio_type); + if (VCD_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to send TTS feedback audio format to VC manager"); + } + + return ret; +} + +int vcd_send_feedback_streaming(vce_feedback_event_e event, char* buffer, int len) +{ + SLOG(LOG_INFO, TAG_VCD, "[Server DEBUG] Engine - Send TTS feedback streaming"); + + /* send TTS feedback streaming to VC manager */ + int ret = VCD_ERROR_NONE; + ret = vcdc_send_feedback_streaming_to_manager(vcd_client_manager_get_pid(), event, buffer, len); + if (VCD_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to send TTS feedback streaming to VC manager"); + } + + return ret; +} + + /* * vcd server Interfaces */ @@ -1991,6 +2036,30 @@ int vcd_server_mgr_get_private_data(int pid, const char* key, char** data) return ret; } +int vcd_server_mgr_send_specific_engine_request(int pid, const char* engine_app_id, const char* event, const char* request) +{ + /* check if pid is valid */ + if (false == vcd_client_manager_is_valid(pid)) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] The manager pid(%d) is NOT valid", pid); + return VCD_ERROR_INVALID_PARAMETER; + } + vcd_state_e state = vcd_config_get_service_state(); + if (VCD_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Current state is not ready"); + return VCD_ERROR_INVALID_STATE; + } + + /* Get private data to engine */ + int ret = vcd_engine_send_specific_engine_request(engine_app_id, event, request); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to set specific engine request : %d", ret); + } else { + SLOG(LOG_DEBUG, TAG_VCD, "[Server SUCCESS] Set specific engine request "); + } + + return ret; +} + int vcd_server_mgr_do_action(int pid, int type, const char* action) { int ret = -1; @@ -2078,6 +2147,40 @@ int vcd_server_mgr_disable_command_type(int pid, int cmd_type) return ret; } +/* for TTS feedback */ +int vcd_server_mgr_start_feedback(void) +{ + /* check current state */ + /* not Recording??? */ + + if (-1 == vcd_client_manager_get_pid()) { + SLOG(LOG_ERROR, TAG_VCD, "[Server] Manager is NOT available"); + return VCD_ERROR_OPERATION_FAILED; + } + + SLOG(LOG_DEBUG, TAG_VCD, "[Server] start TTS feedback"); + + /* check there is TTS buffer to be spoken */ + + return VCD_ERROR_NONE; +} + +int vcd_server_mgr_stop_feedback(void) +{ + /* check current state */ + /* not Recording??? */ + + if (-1 == vcd_client_manager_get_pid()) { + SLOG(LOG_ERROR, TAG_VCD, "[Server] Manager is NOT available"); + return VCD_ERROR_OPERATION_FAILED; + } + + SLOG(LOG_DEBUG, TAG_VCD, "[Server] stop TTS feedback"); + + return VCD_ERROR_NONE; +} + + /* * VC Server Functions for Client */ @@ -2225,26 +2328,66 @@ static int __vcd_server_launch_manager_app() return VCD_ERROR_NONE; } -int vcd_server_dialog(int pid, const char* disp_text, const char* utt_text, int continuous) +int vcd_server_set_server_dialog(int pid, const char* app_id, const char* credential) { /* check if pid is valid */ - if (false == vcd_client_is_available(pid) && false == vcd_client_widget_is_available(pid)) { + if (false == vcd_client_is_available(pid)) { SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] pid is NOT valid "); return VCD_ERROR_INVALID_PARAMETER; } - int ret = __vcd_server_launch_manager_app(); + int ret = vcd_engine_set_server_dialog(app_id, credential); if (0 != ret) { - SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to send dialog : mgr_pid(%d), pid(%d), disp_text(%s), utt_text(%s), continue(%d)", vcd_client_manager_get_pid(), pid, disp_text, utt_text, continuous); + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to set server dialog, pid(%d), app_id(%s), ret(%d)", pid, app_id, ret); + vcd_client_set_server_dialog(pid, false); return ret; } + SLOG(LOG_ERROR, TAG_VCD, "[Success] Set server dialog, pid(%d), app_id(%s)", pid, app_id); + + if (0 != strncmp(credential, "#NULL", strlen(credential))) { + ret = vcd_client_set_server_dialog(pid, true); + if (0 != ret) + SLOG(LOG_DEBUG, TAG_VCD, "[Server] Set to true for server dialog, app_id(%s)", app_id); + } else { + ret = vcd_client_set_server_dialog(pid, false); + if (0 != ret) + SLOG(LOG_DEBUG, TAG_VCD, "[Server] Set to false for server dialog, app_id(%s)", app_id); + } + + return 0; +} + +int vcd_server_dialog(int pid, const char* disp_text, const char* utt_text, int continuous) +{ + /* check if pid is valid */ + if (false == vcd_client_is_available(pid) && false == vcd_client_widget_is_available(pid)) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] pid is NOT valid "); + return VCD_ERROR_INVALID_PARAMETER; + } - ret = vcdc_send_dialog(vcd_client_manager_get_pid(), pid, disp_text, utt_text, continuous); + bool is_server_dialog = false; + int ret = vcd_client_get_server_dialog(pid, &is_server_dialog); if (0 != ret) { - SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to send dialog : mgr_pid(%d), pid(%d), disp_text(%s), utt_text(%s), continue(%d)", vcd_client_manager_get_pid(), pid, disp_text, utt_text, continuous); - return ret; + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to get server dialog, pid(%d), ret(%d)", pid, ret); } + if (true == is_server_dialog) { + /* ++ Request tts event to engine */ + + /* -- Request tts event to engine */ + } else { + ret = __vcd_server_launch_manager_app(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to send dialog : mgr_pid(%d), pid(%d), disp_text(%s), utt_text(%s), continue(%d)", vcd_client_manager_get_pid(), pid, disp_text, utt_text, continuous); + return ret; + } + + ret = vcdc_send_dialog(vcd_client_manager_get_pid(), pid, disp_text, utt_text, continuous); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to send dialog : mgr_pid(%d), pid(%d), disp_text(%s), utt_text(%s), continue(%d)", vcd_client_manager_get_pid(), pid, disp_text, utt_text, continuous); + return ret; + } + } return 0; } @@ -2742,3 +2885,15 @@ int vcd_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_f return ret; } + +int vcd_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func) +{ + SLOG(LOG_DEBUG, TAG_VCD, "[Server] Set specific engine request cb"); + int ret = 0; + ret = vcd_engine_agent_set_specific_engine_request_cb(callback_func); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[Server ERROR] Fail to set specific engine request cb : ret(%d)", ret); + } + + return ret; +} diff --git a/server/vcd_server.h b/server/vcd_server.h index 70bc3d9..e11108f 100644 --- a/server/vcd_server.h +++ b/server/vcd_server.h @@ -80,6 +80,12 @@ int vcd_server_mgr_enable_command_type(int pid, int cmd_type); int vcd_server_mgr_disable_command_type(int pid, int cmd_type); +/* for TTS feedback */ +int vcd_server_mgr_start_feedback(void); + +int vcd_server_mgr_stop_feedback(void); + + /* * For client */ @@ -93,6 +99,8 @@ int vcd_server_unset_command(int pid, vc_cmd_type_e cmd_type); int vcd_server_set_foreground(int pid, bool value); +int vcd_server_set_server_dialog(int pid, const char* app_id, const char* credential); + int vcd_server_dialog(int pid, const char* disp_text, const char* utt_text, int continuous); int vcd_server_is_system_command_valid(int pid, int* is_sys_cmd_valid); @@ -126,6 +134,8 @@ int vcd_server_widget_enable_asr_result(int pid, bool enable); int vcd_server_set_language(const char* language); +int vcd_server_mgr_send_specific_engine_request(int pid, const char* engine_app_id, const char* event, const char* request); + /* * For engine service */ @@ -133,6 +143,8 @@ int vcd_send_result(vce_result_event_e event, int* result_id, int count, const c int vcd_send_asr_result(vce_asr_result_event_e event, const char* asr_result, void *user_data); +int vcd_send_specific_engine_result(const char* engine_app_id, const char* event, const char* result, void *user_info); + int vcd_send_nlg_result(const char* nlg_result, void *user_data); int vcd_send_error(vce_error_e error, const char* msg, void *user_data); @@ -157,6 +169,12 @@ int vcd_set_private_data_requested_cb(vce_private_data_requested_cb callback_fun int vcd_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_func); +int vcd_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func); + +int vcd_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_audio_type_e audio_type); + +int vcd_send_feedback_streaming(vce_feedback_event_e event, char* buffer, int len); + #ifdef __cplusplus } diff --git a/server/vce.c b/server/vce.c index cbb21fa..087cee8 100644 --- a/server/vce.c +++ b/server/vce.c @@ -221,6 +221,29 @@ int vce_send_asr_result(vce_asr_result_event_e event, const char* asr_result, vo return ret; } +int vce_send_specific_engine_result(const char* engine_app_id, const char* event, const char* result, void *user_info) +{ + int ret = VCE_ERROR_NONE; + + if (NULL == engine_app_id || NULL == event) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Invalid parameter"); + return VCE_ERROR_INVALID_PARAMETER; + } + + if (NULL == result) { + SLOG(LOG_ERROR, TAG_VCD, "[INFO] Input parameter is NULL. (no result)"); + } + + ret = vcd_send_specific_engine_result(engine_app_id, event, result, user_info); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to send specific engine result, ret(%d)", ret); + } else { + SLOG(LOG_INFO, TAG_VCD, "[INFO] Success to send specific engine result, event(%s), result(%s)", event, result); + } + + return ret; +} + int vce_send_nlg_result(const char* nlg_result, void *user_data) { int ret = VCE_ERROR_NONE; @@ -449,3 +472,53 @@ int vce_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_f return ret; } + +int vce_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func) +{ + if (NULL == callback_func) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Invalid parameter"); + return VCE_ERROR_INVALID_PARAMETER; + } + + int ret = vcd_set_specific_engine_request_cb(callback_func); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to set specific engine request cb"); + } + + return ret; +} + +int vce_unset_specific_engine_request_cb(void) +{ + int ret = vcd_set_specific_engine_request_cb(NULL); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to set specific engine request cb"); + } + + return ret; +} + +/* for TTS feedback */ +int vce_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_audio_type_e audio_type) +{ + int ret = VCE_ERROR_NONE; + + ret = vcd_send_feedback_audio_format(rate, channel, audio_type); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to send feedback audio format"); + } + + return ret; +} + +int vce_send_feedback_streaming(vce_feedback_event_e event, char* buffer, int len) +{ + int ret = VCE_ERROR_NONE; + + ret = vcd_send_feedback_streaming(event, buffer, len); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to send feedback streaming"); + } + + return ret; +} -- 2.7.4 From 0473475ab0c0c7095326bdbb792117450574a456 Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Thu, 7 Jun 2018 11:30:06 +0900 Subject: [PATCH 12/16] [ACR-1232][voice-control][Add] Add APIs for VCE Change-Id: Ic39e01b23aa231f88d1e1a70aedf5f8d35220323 Signed-off-by: sooyeon.kim --- include/vce.h | 189 +++++++++++++++++++++++++++++++++------------------------- server/vce.c | 15 +++++ 2 files changed, 122 insertions(+), 82 deletions(-) diff --git a/include/vce.h b/include/vce.h index c735acd..e5d917f 100644 --- a/include/vce.h +++ b/include/vce.h @@ -31,7 +31,7 @@ extern "C" { /** * @brief Enumerations of error codes. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef enum { VCE_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ @@ -50,7 +50,7 @@ typedef enum { /** * @brief Enumerations of audio type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef enum { VCE_AUDIO_TYPE_PCM_S16_LE = 0, /**< Signed 16bit audio type, Little endian */ @@ -59,7 +59,7 @@ typedef enum { /** * @brief Enumerations of callback event. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef enum { VCE_RESULT_EVENT_SUCCESS = 0, /**< Event when the recognition full result is ready */ @@ -69,7 +69,7 @@ typedef enum { /** * @brief Enumerations of command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef enum { VCE_COMMAND_FORMAT_FIXED = 0, /**< Fixed command */ @@ -83,7 +83,7 @@ typedef enum { /** * @brief Enumerations of speech detect. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef enum { VCE_SPEECH_DETECT_NONE = 0, /**< No event */ @@ -93,7 +93,7 @@ typedef enum { /** * @brief Enumerations of ASR result events. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef enum { VCE_ASR_RESULT_EVENT_FINAL_RESULT = 0, /**< Event when the ASR result is last data or ASR result is only one result */ @@ -102,8 +102,8 @@ typedef enum { } vce_asr_result_event_e; /** - * @brief Enumerations of audio channels - * @since_tizen 5.0 + * @brief Enumerations of audio channels. + * @since_tizen 4.0 */ typedef enum { VCE_AUDIO_CHANNEL_MONO = 0, /**< 1 channel, mono */ @@ -111,8 +111,8 @@ typedef enum { } vce_audio_channel_e; /** - * @brief Enumeration for TTS feedback events - * @since_tizen 5.0 + * @brief Enumeration for TTS feedback events. + * @since_tizen 4.0 */ typedef enum { VCE_FEEDBACK_EVENT_FAIL = -1, /**< Failed */ @@ -124,74 +124,74 @@ typedef enum { /** * @brief A structure of handle for VC command. -* @since_tizen 5.0 +* @since_tizen 4.0 */ typedef struct vce_cmd_s* vce_cmd_h; /** * @brief Definition for foreground command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_COMMAND_TYPE_FOREGROUND 1 /** * @brief Definition for background command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_COMMAND_TYPE_BACKGROUND 2 /** * @brief Definition for widget command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_COMMAND_TYPE_WIDGET 3 /** * @brief Definition for system command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_COMMAND_TYPE_SYSTEM 4 /** * @brief Definition for system background command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_COMMAND_TYPE_SYSTEM_BACKGROUND 5 /** * @brief Definitions for exclusive command type. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_COMMAND_TYPE_EXCLUSIVE 6 /** * @brief Definition of bluetooth audio id. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_AUDIO_ID_BLUETOOTH "VC_AUDIO_ID_BLUETOOTH" /**< Bluetooth audio id */ /** * @brief Definition of Wi-Fi audio id. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VCE_AUDIO_ID_WIFI "VC_AUDIO_ID_WIFI" /**< Wi-Fi audio id */ /** * @brief Definition for none message. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VC_RESULT_MESSAGE_NONE "vc.result.message.none" /** * @brief Definition for failed recognition because the speech is too loud to listen. -* @since_tizen 5.0 +* @since_tizen 4.0 */ #define VC_RESULT_MESSAGE_ERROR_TOO_LOUD "vc.result.message.error.too.loud" /** * @brief Called when VC engine informs the engine service user about whole supported languages. * @details This callback function is implemented by the engine service user. Therefore, the engine developer does NOT have to implement this callback function. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is called by vce_foreach_supported_languages_cb() to retrieve the whole supported language list. * The @a user_data must be transferred from vce_foreach_supported_languages_cb(). * The @a language can be used only in the callback. To use outside, make a copy. @@ -206,7 +206,7 @@ typedef bool (*vce_supported_language_cb)(const char* language, void* user_data) /** * @brief Called when the engine service user initializes Voice Control (VC) engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful @@ -219,7 +219,7 @@ typedef int (*vce_initialize_cb)(void); /** * @brief Called when the engine service user deinitializes VC engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful @@ -230,9 +230,12 @@ typedef int (*vce_deinitialize_cb)(void); /** * @brief Called when the engine service user requests the recording format of VC engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). * The @a audio_id can be used only in the callback. To use outside, make a copy. +* The @a types is managed by the platform and will be released when this callback function is completed. +* The @a rate is managed by the platform and will be released when this callback function is completed. +* The @a channels is managed by the platform and will be released when this callback function is completed. * @param[in] audio_id The audio device id. (e.g. #VCE_AUDIO_ID_BLUETOOTH or #VCE_AUDIO_ID_WIFI) * @param[out] types The format used by the recorder. * @param[out] rate The sample rate used by the recorder. @@ -245,7 +248,7 @@ typedef int (*vce_get_recording_format_cb)(const char* audio_id, vce_audio_type_ /** * @brief Called when the engine service user retrieves all supported languages of VC engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). * @param[in] callback a callback function * @param[in] user_data The user data to be passed to the callback function @@ -261,7 +264,7 @@ typedef int (*vce_foreach_supported_languages_cb)(vce_supported_language_cb call /** * @brief Called when the engine service user checks whether a language is supported or not. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). * The @a language can be used only in the callback. To use outside, make a copy. * @param[in] language A language @@ -271,7 +274,7 @@ typedef bool (*vce_is_language_supported_cb)(const char* language); /** * @brief Called when the engine service user sets language. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a language can be used only in the callback. To use outside, make a copy. * @param[in] language A language. * @return 0 on success, otherwise a negative error value @@ -284,8 +287,10 @@ typedef int (*vce_set_language_cb)(const char* language); /** * @brief Called when the engine service user sets command list before recognition. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This function should set commands via vcd_foreach_command(). +* The @a vc_command should not be released. +* The @a vc_command can be used only in the callback. To use outside, make a copy. * @param[in] vc_command command handle. The @a vc_command can be used only in the callback. To use outside, make a copy. * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful @@ -303,7 +308,7 @@ typedef int (*vce_set_commands_cb)(vce_cmd_h vc_command); /** * @brief Called when the engine service user unsets command list for reset. -* @since_tizen 5.0 +* @since_tizen 4.0 * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful * @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter @@ -316,7 +321,7 @@ typedef int (*vce_unset_commands_cb)(void); /** * @brief Called when the engine service user starts recognition. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). * @param[in] stop_by_silence Silence detection option. * @c true to detect the silence, @@ -337,9 +342,10 @@ typedef int (*vce_start_cb)(bool stop_by_silence); /** * @brief Called when the engine service user sets recording data for speech recognition from recorder. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This function should be returned immediately after recording data copy. * The @a data can be used only in the callback. To use outside, make a copy. +* The @a speech_detected should not be released. This is managed by the platform. * @param[in] data A recording data * @param[in] length A length of recording data * @param[out] speech_detected The status of speech (e.g. #VCE_SPEECH_DETECT_BEGIN or #VCE_SPEECH_DETECT_END). The @a speech_detected can be used only in the callback. To use outside, make a copy. @@ -357,7 +363,7 @@ typedef int(*vce_set_recording_data_cb)(const void* data, unsigned int length, v /** * @brief Called when the engine service user stops to get the result of recognition. -* @since_tizen 5.0 +* @since_tizen 4.0 * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful * @retval #VCE_ERROR_INVALID_STATE Invalid state @@ -373,7 +379,7 @@ typedef int (*vce_stop_cb)(void); /** * @brief Called when the engine service user cancels the recognition process. -* @since_tizen 5.0 +* @since_tizen 4.0 * @return 0 on success, otherwise a negative error value. * @retval #VCE_ERROR_NONE Successful. * @retval #VCE_ERROR_INVALID_STATE Invalid state. @@ -385,8 +391,8 @@ typedef int (*vce_cancel_cb)(void); /** * @brief Called when the engine service user sets audio recording type. -* @since_tizen 5.0 -* @remarks The @a audio can be used only in the callback. To use outside, make a copy. +* @since_tizen 4.0 +* @remarks The @a audio_type can be used only in the callback. To use outside, make a copy. * @param[in] audio_type Current audio type (e.g. #VCE_AUDIO_ID_BLUETOOTH or #VCE_AUDIO_ID_WIFI) * @return 0 on success, otherwise a negative error value. * @retval #VCE_ERROR_NONE Successful. @@ -396,7 +402,7 @@ typedef int (*vce_set_audio_type_cb)(const char* audio_type); /** * @brief Called when the engine service user sets app id which is want to ask server dialog. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a app_id and @a credential can be used only in the callback. To use outside, make a copy. * @param[in] app_id App id which is to want to ask server dialog. * @param[in] credential Credential key. @@ -409,7 +415,7 @@ typedef int (*vce_set_server_dialog_cb)(const char* app_id, const char* credenti /** * @brief Called when the engine service user sets domain (agent or device type). -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a domain can be used only in the callback. To use outside, make a copy. * @param[in] domain Agent (e.g. "music", "news", etc) or device type (e.g. "tv", "mobile", etc) corresponding to the command * @return 0 on success, otherwise a negative error value. @@ -420,8 +426,9 @@ typedef int (*vce_set_domain_cb)(const char* domain); /** * @brief Called when the engine service user requests essential value from NLU result. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a key can be used only in the callback. To use outside, make a copy. +* The @a value is managed by the platform and will be released when this callback function is completed. * @param[in] key NLU base info key. * @param[out] value NLU base info value. * @return 0 on success, otherwise a negative error value. @@ -432,7 +439,10 @@ typedef int (*vce_nlu_base_info_requested_cb)(const char* key, char** value); /** * @brief Called when client gets the specific engine's request from the engine service user. -* @since_tizen 5.0 +* @since_tizen 4.0 +* @remarks The @a engine_app_id is managed by the platform and will be released when this callback function is completed. +* The @a event is managed by the platform and will be released when this callback function is completed. +* The @a request is managed by the platform and will be released when this callback function is completed. * * @param[in] engine_app_id The specific engine's app id * @param[in] event The specific engine event type @@ -452,7 +462,7 @@ typedef int (*vce_specific_engine_request_cb)(const char* engine_app_id, const c /** * @brief Called when the engine service user sets private data between app and engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a key, @a data can be used only in the callback. To use outside, make a copy. * @param[in] key Private key. * @param[in] data Private data. @@ -464,8 +474,9 @@ typedef int (*vce_private_data_set_cb)(const char* key, const char* data); /** * @brief Called when the engine service user requests private data between app and engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a key can be used only in the callback. To use outside, make a copy. +* The @a data is managed by the platform and will be released when this callback function is completed. * @param[in] key Private key. * @param[out] data Private data. * @return 0 on success, otherwise a negative error value. @@ -476,7 +487,7 @@ typedef int (*vce_private_data_requested_cb)(const char* key, char** data); /** * @brief Called when the engine service user requests process text. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a text can be used only in the callback. To use outside, make a copy. * @param[in] text Requested text * @return 0 on success, otherwise a negative error value. @@ -487,7 +498,7 @@ typedef int (*vce_process_text_cb)(const char* text); /** * @brief Called when the engine service user requests list event. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a event can be used only in the callback. To use outside, make a copy. * @param[in] event Requested list event * @return 0 on success, otherwise a negative error value. @@ -498,7 +509,7 @@ typedef int (*vce_process_list_event_cb)(const char* event); /** * @brief Called when the engine service user requests haptic event. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a event can be used only in the callback. To use outside, make a copy. * @param[in] event Requested haptic event * @return 0 on success, otherwise a negative error value. @@ -509,9 +520,12 @@ typedef int (*vce_process_haptic_event_cb)(const char* event); /** * @brief Called when the engine service user requests the base information of VC engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks This callback function is mandatory and must be registered using vce_main(). -* The allocated @a engine_uuid, @a engine_name, and @a engine_settings_app_id will be released internally. +* The @a engine_uuid is managed by the platform and will be released when this callback function is completed. +* The @a engine_name is managed by the platform and will be released when this callback function is completed. +* The @a engine_settings_app_id is managed by the platform and will be released when this callback function is completed. +* The @a use_network is managed by the platform and will be released when this callback function is completed. * In order to upload the engine to Tizen Appstore, both the service app and the UI app (engine settings) are necessary. * Therefore, @a engine_settings_app_id should be set to the application ID of the UI application. * If there is no UI application, then @a engine_settings_app_id should be set to NULL. @@ -528,7 +542,7 @@ typedef int (*vce_get_info_cb)(char** engine_uuid, char** engine_name, char** en /** * @brief Called to retrieve the commands. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The @a command, @a param can be used only in the callback. To use outside, make a copy. * @param[in] id command id * @param[in] type command type @@ -547,7 +561,7 @@ typedef bool (*vce_command_cb)(int id, int type, int format, const char* command /** * @brief A structure for the VC engine functions. * @details This structure contains essential callback functions for operating VC engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks These functions ar mandatory for operating VC engine. Therefore, all functions MUST be implemented. */ typedef struct { @@ -582,16 +596,16 @@ typedef struct { vce_process_haptic_event_cb process_haptic_event; /**< Request to process haptic event */ /* Optional callbacks */ - vce_private_data_set_cb private_data_set; + vce_private_data_set_cb private_data_set; vce_private_data_requested_cb private_data_request; vce_nlu_base_info_requested_cb nlu_base_info_request; vce_specific_engine_request_cb specific_engine_request; } vce_request_callback_s; /** -* @brief Main function for Voice Control (VC) engine. +* @brief Starts the main function for Voice Control (VC) engine. * @details This function is the main function for operating VC engine. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @remarks The service_app_main() should be used for working the engine after this function. @@ -701,7 +715,7 @@ int vce_main(int argc, char** argv, vce_request_callback_s* callback); /** * @brief Sends the results to the engine service user. -* @since_tizen 5.0 +* @since_tizen 4.0 * @param[in] event A result event * @param[in] result_id Result ids * @param[in] count Result count @@ -718,14 +732,14 @@ int vce_main(int argc, char** argv, vce_request_callback_s* callback); * @retval #VCE_ERROR_INVALID_STATE Invalid state * @retval #VCE_ERROR_OPERATION_FAILED Operation failure * @pre The vce_main() function should be invoked before this function is called. -* vce_stop_cb() will invoke this callback. +* vce_stop_cb() will invoke this callback. * @see vce_stop_cb() */ int vce_send_result(vce_result_event_e event, int* result_id, int count, const char* all_result, const char* non_fixed_result, const char* nlu_result, const char* msg, int* user_info, void* user_data); /** * @brief Sends the ASR result to the engine service user. -* @since_tizen 5.0 +* @since_tizen 4.0 * @param[in] event A asr result event * @param[in] asr_result A asr result text * @param[in] user_data The user data passed from the start @@ -741,7 +755,7 @@ int vce_send_asr_result(vce_asr_result_event_e event, const char* asr_result, vo /** * @brief Sends the NLG (Natural Language Generation) result to the engine service user. -* @since_tizen 5.0 +* @since_tizen 4.0 * @param[in] nlg_result A nlg result * @param[in] user_data The user data passed from the start * @return @c 0 on success, otherwise a negative error value @@ -756,12 +770,12 @@ int vce_send_nlg_result(const char* nlg_result, void* user_data); /** * @brief Sends the specific engine result to the engine service user. -* @since_tizen 5.0 +* @since_tizen 4.0 * * @param[in] engine_app_id A specific engine's app id * @param[in] event A specific engine result event * @param[in] result A specific engine result text -* @param[in] user_data The user data passed from the start +* @param[in] user_info The user info passed from the start * * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful @@ -787,7 +801,7 @@ int vce_send_specific_engine_result(const char* engine_app_id, const char* event * #VCE_ERROR_OPERATION_FAILED, \n * #VCE_ERROR_PERMISSION_DENIED, \n * #VCE_ERROR_NOT_SUPPORTED_FEATURE. -* @since_tizen 5.0 +* @since_tizen 4.0 * @param[in] error Error type * @param[in] msg Error message * @param[in] user_data The user data passed from set callback function @@ -802,7 +816,7 @@ int vce_send_error(vce_error_e error, const char* msg, void* user_data); /** * @brief Sets a callback function for setting the private data to the engine service. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @remarks The vce_private_data_set_cb() function is called when the engine service user sets the private data to the engine service. @@ -821,7 +835,7 @@ int vce_set_private_data_set_cb(vce_private_data_set_cb callback_func); /** * @brief Sets a callback function for requesting the private data to the engine service. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @remarks The vce_private_data_requested_cb() function is called when the engine service user requests the private data to the engine service. @@ -838,7 +852,7 @@ int vce_set_private_data_requested_cb(vce_private_data_requested_cb callback_fun /** * @brief Sets a callback function for requesting the NLU base information to the engine service. -* @since_tizen 5.0 +* @since_tizen 4.0 * @remarks The vce_nlu_base_info_requested_cb() function is called when the engine service user requests the NLU base information to the engine service. * @param[in] callback_func vce_nlu_base_info_requested event callback function * @return @c 0 on success, otherwise a negative error value @@ -851,16 +865,14 @@ int vce_set_private_data_requested_cb(vce_private_data_requested_cb callback_fun int vce_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_func); /** -* @brief Registers a callback function for getting the engine service request. -* @since_tizen 5.0 +* @brief Sets a callback function for getting the engine service request. +* @since_tizen 4.0 * -* @param[in] callback Callback function to register -* @param[in] user_data The user data to be passed to the callback function +* @param[in] callback_func Callback function to register * * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful * @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter -* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied * @retval #VCE_ERROR_NOT_SUPPORTED Not supported * * @see vce_unset_specific_engine_request_cb() @@ -868,12 +880,11 @@ int vce_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_f int vce_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func); /** -* @brief Unregisters the engine service request callback function. -* @since_tizen 5.0 +* @brief Unsets the engine service request callback function. +* @since_tizen 4.0 * * @return 0 on success, otherwise a negative error value * @retval #VC_ERROR_NONE Successful -* @retval #VC_ERROR_PERMISSION_DENIED Permission denied * @retval #VC_ERROR_NOT_SUPPORTED Not supported * * @see vce_set_specific_engine_request_cb() @@ -882,16 +893,18 @@ int vce_unset_specific_engine_request_cb(void); /** * @brief Retrieves all commands using callback function. -* @since_tizen 5.0 +* @since_tizen 4.0 +* * @param[in] vce_command The handle to be passed to the vce_set_commands() function * @param[in] callback The callback function to invoke * @param[in] user_data The user data to be passed to the callback function +* * @return 0 on success, otherwise a negative error value * @retval #VCE_ERROR_NONE Successful * @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VCE_ERROR_OPERATION_FAILED Operation failure * @retval #VCE_ERROR_INVALID_STATE Invalid state -* @post This function invokes vce_command_cb() repeatedly for getting commands. +* @post This function invokes vce_command_cb() repeatedly for getting commands. * @see vce_foreach_command_cb() * @see vce_set_commands() */ @@ -899,9 +912,11 @@ int vce_get_foreach_command(vce_cmd_h vce_command, vce_command_cb callback, void /** * @brief Gets command length. -* @since_tizen 5.0 +* @since_tizen 4.0 +* * @param[in] vce_command The handle to be passed to the vce_set_commands() function * @param[out] count The command count value +* * @return 0 on success, otherwise a negative error value. * @retval #VCE_ERROR_NONE Successful * @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter @@ -912,7 +927,7 @@ int vce_get_command_count(vce_cmd_h vce_command, int* count); /** * @brief Gets current audio type. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @remarks The @a audio_type must be released using free() when it is no longer required. @@ -927,7 +942,7 @@ int vce_get_audio_type(char** audio_type); /** * @brief Sets private data to a voice manager client. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @param[in] key Private key @@ -945,7 +960,7 @@ int vce_set_private_data(const char* key, const char* data); /** * @brief Gets private data from a voice manager client. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @remarks The @a data must be released using free() when it is no longer required. @@ -964,7 +979,7 @@ int vce_get_private_data(const char* key, char** data); /** * @brief Starts recording voice. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @return 0 on success, otherwise a negative error value. @@ -978,7 +993,7 @@ int vce_start_recording(void); /** * @brief Stops recording voice. -* @since_tizen 5.0 +* @since_tizen 4.0 * @privlevel public * @privilege %http://tizen.org/privilege/recorder * @return 0 on success, otherwise a negative error value. @@ -992,11 +1007,16 @@ int vce_stop_recording(void); /* for TTS feeadback */ /** * @brief Sends audio formats necessary for playing TTS feedback. -* @since_tizen 5.0 +* @since_tizen 4.0 +* +* @param[in] rate A sampling rate +* @param[in] channel The audio channel +* @param[in] audio_type The audio type +* * @return 0 on success, otherwise a negative error value. * @retval #VCE_ERROR_NONE Successful -* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied * @retval #VCE_ERROR_NOT_SUPPORTED Not supported +* @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VCE_ERROR_OPERATION_FAILED Operation failure * @retval #VCE_ERROR_OUT_OF_MEMORY Out of Memory */ @@ -1004,11 +1024,16 @@ int vce_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_au /** * @brief Sends audio streaming necessary for playing TTS feedback. -* @since_tizen 5.0 +* @since_tizen 4.0 +* +* @param[in] event A feedback event +* @param[in] buffer The feedback data +* @param[in] len The length of the feedback data +* * @return 0 on success, otherwise a negative error value. * @retval #VCE_ERROR_NONE Successful -* @retval #VCE_ERROR_PERMISSION_DENIED Permission denied * @retval #VCE_ERROR_NOT_SUPPORTED Not supported +* @retval #VCE_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VCE_ERROR_OPERATION_FAILED Operation failure * @retval #VCE_ERROR_OUT_OF_MEMORY Out of Memory */ diff --git a/server/vce.c b/server/vce.c index 087cee8..36e842d 100644 --- a/server/vce.c +++ b/server/vce.c @@ -503,6 +503,16 @@ int vce_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_au { int ret = VCE_ERROR_NONE; + if (channel < VCE_AUDIO_CHANNEL_MONO || channel > VCE_AUDIO_CHANNEL_STEREO) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Invalid parameter"); + return VCE_ERROR_INVALID_PARAMETER; + } + + if (audio_type < VCE_AUDIO_TYPE_PCM_S16_LE || audio_type > VCE_AUDIO_TYPE_PCM_U8) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Invalid parameter"); + return VCE_ERROR_INVALID_PARAMETER; + } + ret = vcd_send_feedback_audio_format(rate, channel, audio_type); if (0 != ret) { SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to send feedback audio format"); @@ -515,6 +525,11 @@ int vce_send_feedback_streaming(vce_feedback_event_e event, char* buffer, int le { int ret = VCE_ERROR_NONE; + if (NULL == buffer) { + SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Input parameter is NULL"); + return VCE_ERROR_INVALID_PARAMETER; + } + ret = vcd_send_feedback_streaming(event, buffer, len); if (0 != ret) { SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to send feedback streaming"); -- 2.7.4 From 73095f23a811518ad8cb5be8cfe3fe6572cb8acb Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Tue, 26 Jun 2018 22:08:16 +0900 Subject: [PATCH 13/16] Add engine-parser Change-Id: Ib3789585acd459938a507fc2a102089e8130e460 Signed-off-by: sooyeon.kim --- CMakeLists.txt | 7 +- common/vc_config_mgr.c | 430 +++++++++++++---- common/vc_config_parser.c | 60 ++- common/vc_config_parser.h | 2 + common/vc_defs.h | 6 +- engine-parser/CMakeLists.txt | 37 ++ engine-parser/src/vc-engine-parser.c | 883 +++++++++++++++++++++++++++++++++++ packaging/voice-control.spec | 4 + 8 files changed, 1335 insertions(+), 94 deletions(-) create mode 100644 engine-parser/CMakeLists.txt create mode 100644 engine-parser/src/vc-engine-parser.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 51c98b0..8819be3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,12 +43,12 @@ INCLUDE(FindPkgConfig) IF("${_TV_PRODUCT}" STREQUAL "TRUE") pkg_check_modules(pkgs REQUIRED aul capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland - capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libtzplatform-config libxml-2.0 sqlite3 vconf msfapi + capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf msfapi ) ELSE() pkg_check_modules(pkgs REQUIRED aul capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland - capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libtzplatform-config libxml-2.0 sqlite3 vconf + capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf ) ENDIF() @@ -62,6 +62,9 @@ ADD_SUBDIRECTORY(client) ## Server daemon ## ADD_SUBDIRECTORY(server) +## Engine Parser ## +ADD_SUBDIRECTORY(engine-parser) + ## config ## INSTALL(FILES ${CMAKE_SOURCE_DIR}/vc-config.xml DESTINATION ${TZ_SYS_RO_SHARE}/voice/vc/1.0) diff --git a/common/vc_config_mgr.c b/common/vc_config_mgr.c index 296e88a..5c33189 100755 --- a/common/vc_config_mgr.c +++ b/common/vc_config_mgr.c @@ -41,6 +41,12 @@ typedef struct { vc_config_enabled_cb enabled_cb; } vc_config_client_s; +/* for engine directory monitoring */ +typedef struct { + Ecore_Fd_Handler* dir_fd_handler; + int dir_fd; + int dir_wd; +} vc_engine_inotify_s; const char* vc_config_tag() { @@ -58,10 +64,14 @@ static Ecore_Fd_Handler* g_fd_handler_lang = NULL; static int g_fd_lang; static int g_wd_lang; +static GList* g_ino_list = NULL; + static pthread_mutex_t vc_config_mgr_mutex = PTHREAD_MUTEX_INITIALIZER; -int __vc_config_mgr_print_engine_info(); +static int __vc_config_mgr_register_engine_config_updated_event(const char* path); +static int __vc_config_mgr_unregister_engine_config_updated_event(); +int __vc_config_mgr_print_engine_info(); int __vc_config_mgr_print_client_info(); int vc_config_convert_error_code(vc_config_error_e code) @@ -260,6 +270,295 @@ int __vc_config_mgr_select_lang(const char* engine_id, char** language) return VC_ERROR_OPERATION_FAILED; } +int __vc_config_release_client(int uid) +{ + GSList *iter = NULL; + vc_config_client_s* temp_client = NULL; + + if (0 < g_slist_length(g_config_client_list)) { + /* Check uid */ + iter = g_slist_nth(g_config_client_list, 0); + + while (NULL != iter) { + temp_client = iter->data; + + if (NULL != temp_client) { + if (uid == temp_client->uid) { + g_config_client_list = g_slist_remove(g_config_client_list, temp_client); + free(temp_client); + break; + } + } + + iter = g_slist_next(iter); + } + } + + SLOG(LOG_DEBUG, vc_config_tag(), "Client count (%d)", g_slist_length(g_config_client_list)); + + return g_slist_length(g_config_client_list); +} + +void __vc_config_release_engine() +{ + GSList *iter = NULL; + vc_engine_info_s *engine_info = NULL; + + if (0 < g_slist_length(g_engine_list)) { + + /* Get a first item */ + iter = g_slist_nth(g_engine_list, 0); + + while (NULL != iter) { + engine_info = iter->data; + + if (NULL != engine_info) { + g_engine_list = g_slist_remove(g_engine_list, engine_info); + + vc_parser_free_engine_info(engine_info); + } + + iter = g_slist_nth(g_engine_list, 0); + } + } + + return; +} + +int __vc_config_mgr_get_engine_info() +{ + DIR *dp = NULL; + struct dirent *dirp = NULL; + + char filepath[512] = {'\0',}; + int filesize; + vc_engine_info_s* info = NULL; + + __vc_config_release_engine(); + g_engine_list = NULL; + __vc_config_mgr_unregister_engine_config_updated_event(); + + /* Copy default info directory to download directory */ + dp = opendir(VC_DEFAULT_ENGINE_INFO); + if (NULL == dp) { + SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] No default directory : %s", VC_DEFAULT_ENGINE_INFO); + } else { + do { + dirp = readdir(dp); + + if (NULL != dirp) { + if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name)) + continue; + + filesize = strlen(VC_DEFAULT_ENGINE_INFO) + strlen(dirp->d_name) + 2; + if (filesize >= 512) { + SECURE_SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] File path is too long : %s", dirp->d_name); + closedir(dp); + return -1; + } + + memset(filepath, '\0', 512); + snprintf(filepath, 512, "%s/%s", VC_DEFAULT_ENGINE_INFO, dirp->d_name); + + SECURE_SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] Filepath(%s)", filepath); + + char dest[512] = {'\0',}; + snprintf(dest, 512, "%s/%s", VC_DOWNLOAD_ENGINE_INFO, dirp->d_name); + + if (0 != access(dest, F_OK)) { + if (0 != vc_parser_copy_xml(filepath, dest)) { + SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] Fail to copy engine info"); + } + } + } + } while (NULL != dirp); + + closedir(dp); + } + + /* Get engine info from default engine directory */ + dp = opendir(VC_DOWNLOAD_ENGINE_INFO); + if (NULL == dp) { + SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] No downloadable directory : %s", VC_DOWNLOAD_ENGINE_INFO); + } else { + do { + dirp = readdir(dp); + + if (NULL != dirp) { + if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name)) + continue; + + filesize = strlen(VC_DOWNLOAD_ENGINE_INFO) + strlen(dirp->d_name) + 2; + if (filesize >= 512) { + SECURE_SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] File path is too long : %s", dirp->d_name); + closedir(dp); + return -1; + } + + memset(filepath, '\0', 512); + snprintf(filepath, 512, "%s/%s", VC_DOWNLOAD_ENGINE_INFO, dirp->d_name); + + SECURE_SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] Filepath(%s)", filepath); + + if (0 == vc_parser_get_engine_info(filepath, &info)) { + g_engine_list = g_slist_append(g_engine_list, info); + if (0 != __vc_config_mgr_register_engine_config_updated_event(filepath)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to register engine config updated event"); + } + } + } + } while (NULL != dirp); + + closedir(dp); + } + + if (0 >= g_slist_length(g_engine_list)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] No engine"); + return -1; + } + + return 0; +} + +static Eina_Bool __vc_config_mgr_engine_config_inotify_event_callback(void* data, Ecore_Fd_Handler *fd_handler) +{ + SLOG(LOG_DEBUG, vc_config_tag(), "@@@ Engine config updated callback event"); + + vc_engine_inotify_s *ino = (vc_engine_inotify_s *)data; + int dir_fd = ino->dir_fd; + + int length; + struct inotify_event event; + memset(&event, '\0', sizeof(struct inotify_event)); + + length = read(dir_fd, &event, sizeof(struct inotify_event)); + if (0 > length) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Empty Inotify event"); + SLOG(LOG_DEBUG, vc_config_tag(), "@@@"); + return ECORE_CALLBACK_DONE; + } + + if (IN_CLOSE_WRITE == event.mask) { + int ret = __vc_config_mgr_get_engine_info(); + if (0 != ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get engine info when config updated"); + } + __vc_config_mgr_print_engine_info(); + bool support = vc_config_check_default_language_is_valid(g_config_info->language); + if (false == support) { + SLOG(LOG_DEBUG, vc_config_tag(), "[ERROR] Default language is valid"); + char* temp_lang = NULL; + ret = __vc_config_mgr_select_lang(g_config_info->engine_id, &temp_lang); + if (0 != ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get language"); + } + + ret = vc_config_mgr_set_default_language(temp_lang); + if (0 != ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to set language"); + } else { + SLOG(LOG_DEBUG, vc_config_tag(), "[DEBUG] Saved default language : lang(%s)", g_config_info->language); + } + if (NULL != temp_lang) { + free(temp_lang); + temp_lang = NULL; + } + } + } else { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Undefined event"); + } + + SLOG(LOG_DEBUG, vc_config_tag(), "@@@"); + + return ECORE_CALLBACK_PASS_ON; +} + +static int __vc_config_mgr_register_engine_config_updated_event(const char* path) +{ + if (NULL == path) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Path is NULL"); + return -1; + } + + /* For engine directory monitoring */ + vc_engine_inotify_s *ino = (vc_engine_inotify_s *)calloc(1, sizeof(vc_engine_inotify_s)); + if (NULL == ino) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to allocate memory"); + return -1; + } + + ino->dir_fd = inotify_init(); + if (ino->dir_fd < 0) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to init inotify"); + free(ino); + ino = NULL; + + return -1; + } + + ino->dir_wd = inotify_add_watch(ino->dir_fd, path, IN_CLOSE_WRITE); + SLOG(LOG_DEBUG, vc_config_tag(), "Add inotify watch(%s)", path); + if (ino->dir_wd < 0) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to add watch"); + free(ino); + ino = NULL; + return -1; + } + + ino->dir_fd_handler = ecore_main_fd_handler_add(ino->dir_fd, ECORE_FD_READ, (Ecore_Fd_Cb)__vc_config_mgr_engine_config_inotify_event_callback, (void *)ino, NULL, NULL); + if (NULL == ino->dir_fd_handler) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to add fd handler"); + free(ino); + ino = NULL; + return -1; + } + + /* Set non-blocking mode of file */ + int value; + value = fcntl(ino->dir_fd, F_GETFL, 0); + value |= O_NONBLOCK; + + if (0 > fcntl(ino->dir_fd, F_SETFL, value)) { + SLOG(LOG_WARN, vc_config_tag(), "[WARNING] Fail to set non-block mode"); + } + + g_ino_list = g_list_append(g_ino_list, ino); + + return 0; +} + +static int __vc_config_mgr_unregister_engine_config_updated_event() +{ + /* delete all inotify variable */ + if (0 < g_list_length(g_ino_list)) { + GList *iter = NULL; + iter = g_list_first(g_ino_list); + + while (NULL != iter) { + vc_engine_inotify_s *tmp = iter->data; + + if (NULL != tmp) { + ecore_main_fd_handler_del(tmp->dir_fd_handler); + inotify_rm_watch(tmp->dir_fd, tmp->dir_wd); + close(tmp->dir_fd); + + free(tmp); + tmp = NULL; + } + + g_ino_list = g_list_remove_link(g_ino_list, iter); + + iter = g_list_first(g_ino_list); + } + } + + return 0; +} + + + + + Eina_Bool vc_config_mgr_inotify_event_cb(void* data, Ecore_Fd_Handler *fd_handler) { SLOG(LOG_DEBUG, vc_config_tag(), "@@@ Config changed callback event"); @@ -529,14 +828,12 @@ int vc_config_mgr_initialize(int uid) } /* Get file name from default engine directory */ - DIR *dp = NULL; - struct dirent *dirp; - g_engine_list = NULL; if (0 != access(VC_CONFIG_BASE, F_OK)) { if (0 != mkdir(VC_CONFIG_BASE, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_CONFIG_BASE); + __vc_config_release_client(uid); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; } else { @@ -546,6 +843,7 @@ int vc_config_mgr_initialize(int uid) if (0 != access(VC_RUNTIME_INFO_ROOT, F_OK)) { if (0 != mkdir(VC_RUNTIME_INFO_ROOT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_RUNTIME_INFO_ROOT); + __vc_config_release_client(uid); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; } else { @@ -553,55 +851,49 @@ int vc_config_mgr_initialize(int uid) } } - dp = opendir(VC_DEFAULT_ENGINE_INFO); - if (NULL != dp) { - do { - dirp = readdir(dp); - - if (NULL != dirp) { - if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name)) - continue; - - vc_engine_info_s* info = NULL; - char* filepath = NULL; - int filesize = 0; - - filesize = strlen(VC_DEFAULT_ENGINE_INFO) + strlen(dirp->d_name) + 5; - filepath = (char*)calloc(filesize, sizeof(char)); - - if (NULL != filepath) { - snprintf(filepath, filesize, "%s/%s", VC_DEFAULT_ENGINE_INFO, dirp->d_name); - } else { - SLOG(LOG_ERROR, vc_config_tag(), "[Engine Agent ERROR] Memory not enough!!"); - continue; - } - - if (0 == vc_parser_get_engine_info(filepath, &info)) { - g_engine_list = g_slist_append(g_engine_list, info); - } - - if (NULL != filepath) { - free(filepath); - filepath = NULL; - } - } - } while (NULL != dirp); + if (0 != access(VC_DOWNLOAD_BASE, F_OK)) { + if (0 != mkdir(VC_DOWNLOAD_BASE, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_DOWNLOAD_BASE); + __vc_config_release_client(uid); + pthread_mutex_unlock(&vc_config_mgr_mutex); + return -1; + } else { + SLOG(LOG_DEBUG, vc_config_tag(), "Success to make directory : %s", VC_DOWNLOAD_BASE); + } + } + if (0 != access(VC_DOWNLOAD_ENGINE_INFO, F_OK)) { + if (0 != mkdir(VC_DOWNLOAD_ENGINE_INFO, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_DOWNLOAD_ENGINE_INFO); + __vc_config_release_client(uid); + pthread_mutex_unlock(&vc_config_mgr_mutex); + return -1; + } else { + SLOG(LOG_DEBUG, vc_config_tag(), "Success to make directory : %s", VC_DOWNLOAD_ENGINE_INFO); + } + } - closedir(dp); - } else { - SLOG(LOG_WARN, vc_config_tag(), "[Engine Agent WARNING] Fail to open default directory"); + if (0 != __vc_config_mgr_get_engine_info()) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get engine info"); + __vc_config_release_client(uid); + __vc_config_release_engine(); + pthread_mutex_unlock(&vc_config_mgr_mutex); + return VC_CONFIG_ERROR_ENGINE_NOT_FOUND; } __vc_config_mgr_print_engine_info(); if (0 != vc_parser_load_config(&g_config_info)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse configure information"); + __vc_config_release_client(uid); + __vc_config_release_engine(); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; } if (0 != __vc_config_mgr_check_engine_is_valid(g_config_info->engine_id)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get default engine"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return VC_CONFIG_ERROR_ENGINE_NOT_FOUND; @@ -616,6 +908,8 @@ int vc_config_mgr_initialize(int uid) char* tmp_language; if (0 != __vc_config_mgr_select_lang(g_config_info->engine_id, &tmp_language)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to select language"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; @@ -630,6 +924,8 @@ int vc_config_mgr_initialize(int uid) if (0 != vc_parser_set_language(tmp_language)) { free(tmp_language); SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to save config"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; @@ -655,6 +951,8 @@ int vc_config_mgr_initialize(int uid) temp_client = (vc_config_client_s*)calloc(1, sizeof(vc_config_client_s)); if (NULL == temp_client) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to allocate memory"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return VC_ERROR_OUT_OF_MEMORY; @@ -676,62 +974,22 @@ int vc_config_mgr_initialize(int uid) int vc_config_mgr_finalize(int uid) { - GSList *iter = NULL; - vc_config_client_s* temp_client = NULL; - SLOG(LOG_INFO, vc_config_tag(), "[WARNING] Enter critical section"); - pthread_mutex_lock(&vc_config_mgr_mutex); - if (0 < g_slist_length(g_config_client_list)) { - /* Check uid */ - iter = g_slist_nth(g_config_client_list, 0); - - while (NULL != iter) { - temp_client = iter->data; - - if (NULL != temp_client) { - if (uid == temp_client->uid) { - g_config_client_list = g_slist_remove(g_config_client_list, temp_client); - free(temp_client); - break; - } - } - - iter = g_slist_next(iter); - } - } + pthread_mutex_lock(&vc_config_mgr_mutex); - if (0 < g_slist_length(g_config_client_list)) { - SLOG(LOG_DEBUG, vc_config_tag(), "Client count (%d)", g_slist_length(g_config_client_list)); + if (0 < __vc_config_release_client(uid)) { pthread_mutex_unlock(&vc_config_mgr_mutex); - + SLOG(LOG_DEBUG, vc_config_tag(), "[WARNING] Leave critical section"); + if (0 != pthread_mutex_destroy(&vc_config_mgr_mutex)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to destroy vc_config_mgr_mutex."); } - return 0; } - vc_engine_info_s *engine_info = NULL; - - if (0 < g_slist_length(g_engine_list)) { - - /* Get a first item */ - iter = g_slist_nth(g_engine_list, 0); - - while (NULL != iter) { - engine_info = iter->data; - - if (NULL != engine_info) { - g_engine_list = g_slist_remove(g_engine_list, engine_info); - - vc_parser_free_engine_info(engine_info); - } - - iter = g_slist_nth(g_engine_list, 0); - } - } - + __vc_config_release_engine(); + vconf_ignore_key_changed(VCONFKEY_LANGSET, __vc_config_language_changed_cb); vc_parser_unload_config(g_config_info); diff --git a/common/vc_config_parser.c b/common/vc_config_parser.c index ac89c5a..a862549 100644 --- a/common/vc_config_parser.c +++ b/common/vc_config_parser.c @@ -302,12 +302,12 @@ int vc_parser_load_config(vc_config_s** config_info) bool is_default_open = false; if (0 != access(VC_CONFIG, F_OK)) { - doc = xmlParseFile(VC_CONFIG_DEFAULT); + doc = xmlParseFile(VC_DEFAULT_CONFIG); if (doc == NULL) { - SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG_DEFAULT); + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_DEFAULT_CONFIG); return -1; } - SLOG(LOG_DEBUG, vc_config_tag(), "Use default config : %s", VC_CONFIG_DEFAULT); + SLOG(LOG_DEBUG, vc_config_tag(), "Use default config : %s", VC_DEFAULT_CONFIG); is_default_open = true; } else { int retry_count = 0; @@ -322,9 +322,9 @@ int vc_parser_load_config(vc_config_s** config_info) if (VC_RETRY_COUNT == retry_count) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG); - doc = xmlParseFile(VC_CONFIG_DEFAULT); + doc = xmlParseFile(VC_DEFAULT_CONFIG); if (NULL == doc) { - SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG_DEFAULT); + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_DEFAULT_CONFIG); xmlCleanupParser(); return -1; } @@ -760,6 +760,56 @@ int vc_parser_find_config_changed(int* auto_lang, char** language, int* enabled) return 0; } +int vc_parser_copy_xml(const char* original, const char* destination) +{ + if (NULL == original || NULL == destination) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Input parameter is NULL"); + return -1; + } + + xmlDocPtr doc = NULL; + if (0 == access(original, F_OK)) { + SLOG(LOG_DEBUG, vc_config_tag(), "[DEBUG] Success to access to %s", original); + doc = xmlParseFile(original); + if (doc == NULL) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", original); + return -1; + } + } else { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to access to %s", original); + return -1; + } + + int ret = xmlSaveFile(destination, doc); + if (0 > ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Save result : %d", ret); + } else { + static FILE* pFile; + pFile = fopen(destination, "r"); + int fd = -1; + if (NULL == pFile) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to open file %s", destination); + } else { + fd = fileno(pFile); + fsync(fd); + fclose(pFile); + SLOG(LOG_INFO, vc_config_tag(), "[DEBUG] Success to fsync %s", destination); + } + SLOG(LOG_ERROR, vc_config_tag(), "[DEBUG] Success to save %s", destination); + } + + /* Set mode */ + if (0 > chmod(destination, 0600)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to change file mode : %d", ret); + } + + xmlFreeDoc(doc); + doc = NULL; + SLOG(LOG_DEBUG, vc_config_tag(), "[SUCCESS] Copying xml"); + + return 0; +} + int vc_parser_set_foreground(int pid, bool value) { int cur_pid = 0; diff --git a/common/vc_config_parser.h b/common/vc_config_parser.h index 253aa11..15635f0 100644 --- a/common/vc_config_parser.h +++ b/common/vc_config_parser.h @@ -61,6 +61,8 @@ int vc_parser_set_enabled(bool value); int vc_parser_find_config_changed(int* auto_lang, char** language, int* enabled); +int vc_parser_copy_xml(const char* original, const char* destination); + /* Set / Get foreground info */ int vc_parser_set_foreground(int pid, bool value); diff --git a/common/vc_defs.h b/common/vc_defs.h index 096aa4f..d58ed69 100644 --- a/common/vc_defs.h +++ b/common/vc_defs.h @@ -179,7 +179,7 @@ extern "C" { #define VC_DAEMON_PATH tzplatform_mkpath(tzplatform_getid("TZ_SYS_BIN"), "vc-daemon") -#define VC_CONFIG_DEFAULT tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/vc-config.xml") +#define VC_DEFAULT_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/vc-config.xml") #define VC_DEFAULT_BASE tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0") @@ -207,6 +207,10 @@ extern "C" { #define VC_RUNTIME_INFO_CLIENT tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice/vc/vc-client-info.xml") +#define VC_DOWNLOAD_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/vc/1.0") + +#define VC_DOWNLOAD_ENGINE_INFO tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/vc/1.0/engine-info") + #define VC_NO_FOREGROUND_PID -1 #define VC_BASE_LANGUAGE "en_US" #define VC_RETRY_COUNT 5 diff --git a/engine-parser/CMakeLists.txt b/engine-parser/CMakeLists.txt new file mode 100644 index 0000000..84dafbe --- /dev/null +++ b/engine-parser/CMakeLists.txt @@ -0,0 +1,37 @@ +pkg_check_modules(parser-pkgs REQUIRED + capi-base-common + dlog + glib-2.0 + libxml-2.0 + pkgmgr-info + pkgmgr-installer + capi-appfw-app-manager + libtzplatform-config +) + +FOREACH(flag ${parser-pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET (SRCS + src/vc-engine-parser.c +) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall" ) +SET(extapi "-fvisibility=hidden") + +## SET C COMPILER FLAGS +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} ${extapi}") + +## SET CPP COMPILER FLAGS +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") +#SET(CMAKE_CXX_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} ${OSP_COMPILER_FLAGS}") + +## SET LINKER FLAGS +SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + +## Create Library +ADD_LIBRARY ("${PROJECT_NAME}-engine-parser" SHARED ${SRCS}) +TARGET_LINK_LIBRARIES("${PROJECT_NAME}-engine-parser" ${parser-pkgs_LDFLAGS} ) + +INSTALL(TARGETS "${PROJECT_NAME}-engine-parser" DESTINATION "/etc/package-manager/parserlib/metadata") diff --git a/engine-parser/src/vc-engine-parser.c b/engine-parser/src/vc-engine-parser.c new file mode 100644 index 0000000..0e4a92a --- /dev/null +++ b/engine-parser/src/vc-engine-parser.c @@ -0,0 +1,883 @@ +// +// Copyright (c) 2016 Samsung Electronics Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Define EXPORT_API */ +#ifndef EXPORT_API +#define EXPORT_API __attribute__((visibility("default"))) +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "vc-engine-parser" + +#define VC_TAG_ENGINE_BASE "voice-control-engine" +#define VC_TAG_ENGINE_NAME "name" +#define VC_TAG_ENGINE_ID "id" +#define VC_TAG_ENGINE_SETTING "setting" +#define VC_TAG_ENGINE_LANGUAGE_SET "languages" +#define VC_TAG_ENGINE_LANGUAGE "lang" +#define VC_TAG_ENGINE_NON_FIXED_SUPPORT "non-fixed-support" +#define VC_TAG_ENGINE_CREDENTIAL "credential" + +#define VC_CONFIG_BASE tzplatform_mkpath(TZ_USER_HOME, "share/.voice") +#define VC_HOME tzplatform_mkpath(TZ_USER_HOME, "share/.voice/vc") +#define VC_ENGINE_BASE tzplatform_mkpath(TZ_USER_HOME, "share/.voice/vc/1.0") +#define VC_ENGINE_INFO tzplatform_mkpath(TZ_USER_SHARE, ".voice/vc/1.0/engine-info") + +#define VC_GLOBAL_CONFIG_BASE "/etc/skel/share/.voice" +#define VC_GLOBAL_HOME "/etc/skel/share/.voice/vc" +#define VC_GLOBAL_ENGINE_BASE "/etc/skel/share/.voice/vc/1.0" +#define VC_GLOBAL_ENGINE_INFO "/etc/skel/share/.voice/vc/1.0/engine-info" + +#define VC_METADATA_LANGUAGE "http://tizen.org/metadata/vc-engine/language" +#define VC_METADATA_NON_FIXED_SUPPORT "http://tizen.org/metadata/vc-engine/non-fixed-support" +#define VC_METADATA_CREDENTIAL_REQUIRED "http://tizen.org/metadata/vc-engine/credential-required" +#define VC_METADATA_ENGINE_SETTING "http://tizen.org/metadata/vc-engine/setting" +#define VC_METADATA_ENGINE_NAME "http://tizen.org/metadata/vc-engine/name" + +/* Define Macro */ +#define FREE(x) { if (NULL != x) { free(x); x = NULL; } } +#define G_FREE(x) { if (NULL != x) { g_free(x); x = NULL; } } + +typedef struct metadata { + const char *key; + const char *value; +} metadata; + +static xmlDocPtr g_doc; +GumUser *g_guser = NULL; +uid_t g_uid = 301; // app_fw +gid_t g_gid = 301; // app_fw +GumUserType g_ut = GUM_USERTYPE_NONE; +gchar *g_user_type = NULL; + +char *g_dir_config_base = NULL; +char *g_dir_home = NULL; +char *g_dir_engine_base = NULL; +char *g_dir_engine_info = NULL; + + +static int __create_engine_info_xml(const char *pkgid) +{ + LOGD("=== Create engine info doc"); + g_doc = xmlNewDoc((xmlChar*)"1.0"); + if (NULL == g_doc) { + LOGE("[ERROR] Fail to new doc"); + return -1; + } + LOGD("==="); + return 0; +} + +static int __save_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid, gid_t gid) +{ + LOGD("=== Save engine info doc"); + char *dir_config_base = NULL; + char *dir_home = NULL; + char *dir_engine_base = NULL; + char *dir_engine_info = NULL; + + if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) { + LOGE("[ERROR] Usertype is NONE"); + return -1; + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + uid_t tmp_uid = 0; + gid_t tmp_gid = 0; + LOGD("uid(%d)", uid); + + if (globalapp_uid == uid) { + /* Global app */ + dir_config_base = strdup(VC_GLOBAL_CONFIG_BASE); + dir_home = strdup(VC_GLOBAL_HOME); + dir_engine_base = strdup(VC_GLOBAL_ENGINE_BASE); + dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + tmp_uid = 301; // app_fw + tmp_gid = 301; // app_fw + } else { + /* User app, Guest app, Security app */ + if (NULL != g_dir_config_base) + dir_config_base = strdup(g_dir_config_base); + if (NULL != g_dir_home) + dir_home = strdup(g_dir_home); + if (NULL != g_dir_engine_base) + dir_engine_base = strdup(g_dir_engine_base); + if (NULL != g_dir_engine_info) + dir_engine_info = strdup(g_dir_engine_info); + tmp_uid = uid; + tmp_gid = gid; + } + + if (NULL == dir_config_base || NULL == dir_home || NULL == dir_engine_base || NULL == dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } + + LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info); + + /* Make directories */ + int fd = -1; +// if (0 != access(dir_config_base, F_OK)) { + fd = open(dir_config_base, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_config_base, errno); + if (0 != mkdir(dir_config_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_config_base, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_config_base); + if (0 != chown(dir_config_base, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + +// if (0 != access(dir_home, F_OK)) { + fd = open(dir_home, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_home, errno); + if (0 != mkdir(dir_home, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_home, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_home); + if (0 != chown(dir_home, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + +// if (0 != access(dir_engine_base, F_OK)) { + fd = open(dir_engine_base, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_engine_base, errno); + if (0 != mkdir(dir_engine_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_base, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_engine_base); + if (0 != chown(dir_engine_base, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + +// if (0 != access(dir_engine_info, F_OK)) { + fd = open(dir_engine_info, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_engine_info, errno); + if (0 != mkdir(dir_engine_info, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_info, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_engine_info); + if (0 != chown(dir_engine_info, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + + char path[256] = {'\0',}; + snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid); + int ret = xmlSaveFormatFile(path, g_doc, 1); + LOGD("xmlSaveFile (%d)", ret); + if (0 == ret) { + if (0 != chown(path, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group"); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + + LOGD("==="); + + return 0; +} + +static int __remove_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid) +{ + LOGD("=== Remove engine info doc"); + char *dir_engine_info = NULL; + + if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) { + LOGE("[ERROR] Usertype is NONE"); + return -1; + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + + LOGD("uid(%d)", uid); + + if (globalapp_uid == uid) { + /* Global app */ + dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + } else { + /* User app, Guest app, Security app */ + if (NULL != g_dir_engine_info) + dir_engine_info = strdup(g_dir_engine_info); + } + + if (NULL == dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + return -1; + } + + LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info); + + char path[256] = {'\0',}; + snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid); + if (0 == access(path, F_OK)) { + LOGD("Remove engine info xml(%s)", path); + if (0 != remove(path)) { + LOGE("[ERROR] Fail to emove engine info xml(%s)", path); + } + } + + FREE(dir_engine_info) + + LOGD("==="); + + return 0; +} + +static void __insert_language_from_metadata(xmlNodePtr root, const char *language) +{ + LOGD("==== Insert language"); + char* lang = NULL; + + if (NULL == root || NULL == language) { + LOGE("Invalid parameter, root(%p), language(%s)", root, language); + return; + } + + char *tmp_lang, *tmp_free; + tmp_free = tmp_lang = strdup(language); + xmlNodePtr languages_node = NULL; + xmlNodePtr lang_node = NULL; + + languages_node = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_LANGUAGE_SET); + + lang = strsep(&tmp_lang, ","); + while (NULL != lang) { + LOGD("lang (%s)", lang); + lang_node = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_LANGUAGE); + xmlNodeSetContent(lang_node, (const xmlChar*)lang); + xmlAddChild(languages_node, lang_node); + lang = strsep(&tmp_lang, ","); + } + xmlAddChild(root, languages_node); + + FREE(tmp_free) +} + +static int __write_metadata_inxml(const char *pkgid, const char *appid, GList *list) +{ + GList *iter = NULL; + metadata *md = NULL; + + __create_engine_info_xml(pkgid); + + xmlNodePtr root = NULL; + xmlNodePtr cur = NULL; + + root = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_BASE); + + if (NULL == root) { + LOGE("[ERROR] Fail to get new node"); +// xmlFreeDoc(g_doc); + return -1; + } + xmlDocSetRootElement(g_doc, root); + + iter = g_list_first(list); + while (NULL != iter) { + md = (metadata *)iter->data; + if (NULL != md && NULL != md->key && NULL != md->value) { + LOGD(" - key(%s) value(%s)", md->key, md->value); + if (!strcmp(md->key, VC_METADATA_LANGUAGE)) { + __insert_language_from_metadata(root, md->value); + } else if (!strcmp(md->key, VC_METADATA_NON_FIXED_SUPPORT)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_NON_FIXED_SUPPORT); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else if (!strcmp(md->key, VC_METADATA_CREDENTIAL_REQUIRED)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_CREDENTIAL); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else if (!strcmp(md->key, VC_METADATA_ENGINE_SETTING)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_SETTING); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else if (!strcmp(md->key, VC_METADATA_ENGINE_NAME)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_NAME); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else { + LOGW("[WARNING] Unknown metadata type"); + } + } + iter = g_list_next(iter); + } + + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_ID); + xmlNodeSetContent(cur, (const xmlChar*)appid); + xmlAddChild(root, cur); + + LOGD(""); + return 0; +} + +EXPORT_API +int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgid, const char *appid, GList *list) +{ + LOGD("METADATA INSTALL"); + LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list)); + + int ret = -1; + ret = pkgmgr_installer_info_get_target_uid(&g_uid); + if (ret < 0) { + LOGE("[ERROR] Fail to get target uid"); + return 0; + } else { + LOGD("uid(%d)", g_uid); + printf("[Parser Debug][DEBUG] uid(%d)", g_uid); + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + if (globalapp_uid == g_uid) { + g_user_type = g_strdup("admin"); + } else { + g_guser = gum_user_get_sync(g_uid, FALSE); + if (NULL == g_guser) { + LOGE("[ERROR] g_guser is NULL"); + return -1; + } + + g_object_get(G_OBJECT(g_guser), "gid", &g_gid, NULL); + g_object_get(G_OBJECT(g_guser), "usertype", &g_ut, NULL); + g_user_type = g_strdup(gum_user_type_to_string(g_ut)); + } + + if (NULL == g_user_type) { + LOGE("[ERROR] Fail to allocate memory"); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + return -1; + } + + if (0 == strcmp(g_user_type, "none")) { + /* GUM_USERTYPE_NONE */ + LOGE("[ERROR] Fail to get target uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (globalapp_uid == g_uid) { + /* global directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + if (0 >= g_list_length(list)) { + LOGE("[ERROR] No Engine Metadata"); + G_FREE(g_user_type) + return 0; + } + + if (0 != __write_metadata_inxml(pkgid, appid, list)) { + LOGE("[ERROR] Fail to write metadata in the xml"); + xmlFreeDoc(g_doc); + G_FREE(g_user_type) + return -1; + } + + /* Save in /etc/skel/share/ */ + g_dir_config_base = strdup(VC_GLOBAL_CONFIG_BASE); + g_dir_home = strdup(VC_GLOBAL_HOME); + g_dir_engine_base = strdup(VC_GLOBAL_ENGINE_BASE); + g_dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + + if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + xmlFreeDoc(g_doc); + G_FREE(g_user_type) + return -1; + } + + if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) { + LOGE("[ERROR] Fail to make engine info file"); + xmlFreeDoc(g_doc); + G_FREE(g_user_type) + return -1; + } + + /* Get user data by using libgum */ + + GumUserService *gus = NULL; + GumUserList *users = NULL; + GumUserList *iter = NULL; + GumUser *user = NULL; + gchar **query; + GumUserType gumut = GUM_USERTYPE_NONE; + gchar *user_type = NULL; + + uid_t uid; + gid_t gid; + gchar *home_dir = NULL; + + gus = gum_user_service_create_sync(TRUE); + if (!gus) { + LOGE("Failed to create gum user service"); + G_FREE(g_user_type) + return -1; + } + + query = g_strsplit("admin,normal", ",", -1); + + users = gum_user_service_get_user_list_sync(gus, (const gchar *const *)query); + g_strfreev(query); + + if (!users) { + LOGD("NO users"); + g_object_unref(gus); + gus = NULL; + G_FREE(g_user_type) + return 0; + } + + /* Make new user list */ + + iter = users; + while (iter != NULL) { + user = (GumUser*) iter->data; + g_object_get(G_OBJECT(user), "uid", &uid, NULL); + G_FREE(home_dir) + + g_object_get(G_OBJECT(user), "gid", &gid, NULL); + g_object_get(G_OBJECT(user), "homedir", &home_dir, NULL); + g_object_get(G_OBJECT(user), "usertype", &gumut, NULL); + user_type = g_strdup(gum_user_type_to_string(gumut)); + if (NULL == user_type) { + gum_user_service_list_free(users); + G_FREE(home_dir) + g_object_unref(gus); + gus = NULL; + return -1; + } + + LOGD("[DEBUG] user info"); + if (NULL != home_dir) { + LOGD("[DEBUG] uid(%d), gid(%d), user_type(%s), home_dir(%s)", uid, gid, user_type, home_dir); + + g_dir_config_base = (char*)calloc(strlen(home_dir) + 14, sizeof(char)); + g_dir_home = (char*)calloc(strlen(home_dir) + 17, sizeof(char)); + g_dir_engine_base = (char*)calloc(strlen(home_dir) + 21, sizeof(char)); + g_dir_engine_info = (char*)calloc(strlen(home_dir) + 33, sizeof(char)); + + if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + gum_user_service_list_free(users); + g_object_unref(gus); + gus = NULL; + G_FREE(user_type) + G_FREE(home_dir) + return -1; + } + snprintf(g_dir_config_base, strlen(home_dir) + 14, "%s/share/.voice", home_dir); + snprintf(g_dir_home, strlen(home_dir) + 17, "%s/share/.voice/vc", home_dir); + snprintf(g_dir_engine_base, strlen(home_dir) + 21, "%s/share/.voice/vc/1.0", home_dir); + snprintf(g_dir_engine_info, strlen(home_dir) + 33, "%s/share/.voice/vc/1.0/engine-info", home_dir); + + LOGD("[DEBUG] g_dir_engine_info(%s)", g_dir_engine_info); + + if (0 != __save_engine_info_xml(pkgid, user_type, uid, gid)) { + LOGE("[ERROR] Fail to make engine info file"); + } + + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + + G_FREE(home_dir) + } + + G_FREE(user_type) + iter = g_list_next(iter); + } + + gum_user_service_list_free(users); + g_object_unref(gus); + gus = NULL; + } else { + /* user directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + + ret = tzplatform_set_user(g_uid); + if (ret < 0) { + LOGE("[ERROR] Invalid uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return 0; + } else { + LOGD("TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + printf("[Parser Debug][DEBUG] TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + } + + if (0 >= g_list_length(list)) { + LOGE("[ERROR] No Engine Metadata"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return 0; + } + + if (0 != __write_metadata_inxml(pkgid, appid, list)) { + LOGE("[ERROR] Fail to write metadata in the xml"); + xmlFreeDoc(g_doc); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + g_dir_config_base = strdup(VC_CONFIG_BASE); + g_dir_home = strdup(VC_HOME); + g_dir_engine_base = strdup(VC_ENGINE_BASE); + g_dir_engine_info = strdup(VC_ENGINE_INFO); + + if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + xmlFreeDoc(g_doc); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) { + LOGE("[ERROR] Fail to make engine info file"); + xmlFreeDoc(g_doc); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + G_FREE(g_user_type) + return -1; + } + } + + xmlFreeDoc(g_doc); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + G_FREE(g_user_type) + + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + + return 0; +} + +EXPORT_API +int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgid, const char *appid, GList *list) +{ + LOGD("METADATA UNINSTALL"); + LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list)); + + int ret = -1; + ret = pkgmgr_installer_info_get_target_uid(&g_uid); + if (ret < 0) { + LOGE("[ERROR] Fail to get target uid"); + return 0; + } else { + LOGD("uid(%d)", g_uid); + printf("[Parser Debug][DEBUG] uid(%d)", g_uid); + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + if (globalapp_uid == g_uid) { + g_user_type = g_strdup("admin"); + } else { + g_guser = gum_user_get_sync(g_uid, FALSE); + if (NULL == g_guser) { + LOGE("[ERROR] g_guser is NULL"); + return -1; + } + + g_object_get(G_OBJECT(g_guser), "usertype", &g_ut, NULL); + g_user_type = g_strdup(gum_user_type_to_string(g_ut)); + } + + if (NULL == g_user_type) { + LOGE("[ERROR] Fail to allocate memory"); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + return -1; + } + + if (0 == strcmp(g_user_type, "none")) { + /* GUM_USERTYPE_NONE */ + LOGE("[ERROR] Fail to get target uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (globalapp_uid == g_uid) { + /* global directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + + /* Remove files in /etc/skel/share/ */ + g_dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + if (NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + G_FREE(g_user_type) + return -1; + } + + if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) { + LOGE("[ERROR] Fail to remove engine info file"); + } + + /* Get user data by using libgum */ + + GumUserService *gus = NULL; + GumUserList *users = NULL; + GumUserList *iter = NULL; + GumUser *user = NULL; + gchar **query; + GumUserType gumut = GUM_USERTYPE_NONE; + gchar *user_type = NULL; + + uid_t uid; + gchar *home_dir = NULL; + + GList *md_iter = NULL; + metadata *md = NULL; + + gus = gum_user_service_create_sync(TRUE); + if (!gus) { + LOGE("Failed to create gum user service"); + G_FREE(g_user_type) + return -1; + } + + query = g_strsplit("admin,normal", ",", -1); + + users = gum_user_service_get_user_list_sync(gus, (const gchar *const *)query); + g_strfreev(query); + + if (!users) { + LOGD("NO users"); + g_object_unref(gus); + gus = NULL; + G_FREE(g_user_type) + return 0; + } + + /* Make new user list */ + + iter = users; + while (iter != NULL) { + user = (GumUser*) iter->data; + g_object_get(G_OBJECT(user), "uid", &uid, NULL); + G_FREE(home_dir) + g_object_get(G_OBJECT(user), "homedir", &home_dir, NULL); + g_object_get(G_OBJECT(user), "usertype", &gumut, NULL); + user_type = g_strdup(gum_user_type_to_string(gumut)); + if (NULL == user_type) { + gum_user_service_list_free(users); + G_FREE(home_dir) + g_object_unref(gus); + gus = NULL; + return -1; + } + + if (NULL != home_dir) { + g_dir_engine_info = (char*)calloc(strlen(home_dir) + 33, sizeof(char)); + if (NULL == g_dir_engine_info) { + gum_user_service_list_free(users); + G_FREE(home_dir) + g_object_unref(gus); + gus = NULL; + G_FREE(user_type) + return -1; + } + + snprintf(g_dir_engine_info, strlen(home_dir) + 33, "%s/share/.voice/vc/1.0/engine-info", home_dir); + + md_iter = g_list_first(list); + while (NULL != md_iter) { + md = (metadata *)md_iter->data; + LOGD(" - key(%s) value(%s)", md->key, md->value); + md_iter = g_list_next(md_iter); + } + + if (0 != __remove_engine_info_xml(pkgid, user_type, uid)) { + LOGE("[ERROR] Fail to remove engine info file"); + } + + G_FREE(home_dir) + G_FREE(g_dir_engine_info) + } + G_FREE(user_type) + + LOGD("Finish release memory"); + iter = g_list_next(iter); + LOGD("Finish next iter"); + } + + gum_user_service_list_free(users); + g_object_unref(gus); + gus = NULL; + } else { + /* user directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + + ret = tzplatform_set_user(g_uid); + if (ret < 0) { + LOGE("[ERROR] Invalid uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } else { + LOGD("TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + printf("[Parser Debug][DEBUG] TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + } + + g_dir_engine_info = strdup(VC_ENGINE_INFO); + if (NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) { + LOGE("[ERROR] Fail to remove engine info file"); + } + + } + + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + G_FREE(g_user_type) + + FREE(g_dir_engine_info) + + LOGD(""); + return 0; +} + +EXPORT_API +int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgid, const char *appid, GList *list) +{ + LOGD("METADATA UPGRADE"); + LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list)); + + PKGMGR_MDPARSER_PLUGIN_UNINSTALL(pkgid, appid, list); + PKGMGR_MDPARSER_PLUGIN_INSTALL(pkgid, appid, list); + + LOGD(""); + return 0; +} diff --git a/packaging/voice-control.spec b/packaging/voice-control.spec index 278936c..6d0cc6d 100644 --- a/packaging/voice-control.spec +++ b/packaging/voice-control.spec @@ -26,9 +26,12 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(libgum) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(pkgmgr-info) +BuildRequires: pkgconfig(pkgmgr-installer) %if "%{tizen_profile_name}" == "tv" BuildRequires: pkgconfig(capi-network-bluetooth) BuildRequires: pkgconfig(capi-network-bluetooth-tv) @@ -128,6 +131,7 @@ mkdir -p %{_libdir}/voice/vc %{_libdir}/libvc_engine.so %{TZ_SYS_RO_SHARE}/voice/vc/1.0/vc-config.xml %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice* +%{TZ_SYS_RO_ETC}/package-manager/parserlib/metadata/libvc-engine-parser.so* /etc/dbus-1/session.d/vc-server.conf %files devel -- 2.7.4 From 37715281667b7b9ffa44defae1e904715272724c Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Thu, 5 Jul 2018 16:52:42 +0900 Subject: [PATCH 14/16] Call service_state_changed_cb on client side Change-Id: If72acefe89371e7880f2aa3353296489b5629571 Signed-off-by: Wonnam Jang --- client/vc.c | 17 +++++++++++++++++ client/vc_mgr.c | 19 +++++++++++++++++-- client/vc_mgr_client.c | 2 +- client/vc_widget.c | 20 +++++++++++++++++++- server/vcd_server.c | 2 +- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/client/vc.c b/client/vc.c index 14bdf8b..1152606 100644 --- a/client/vc.c +++ b/client/vc.c @@ -511,8 +511,25 @@ static Eina_Bool __vc_connect_daemon(void *data) } /* Set service state */ + vc_service_state_e previous_service_state; + vc_client_get_service_state(g_vc, &previous_service_state); + vc_client_set_service_state(g_vc, (vc_service_state_e)service_state); + vc_service_state_changed_cb service_changed_callback = NULL; + void* user_data = NULL; + vc_client_get_service_state_changed_cb(g_vc, &service_changed_callback, &user_data); + + if (NULL != service_changed_callback) { + vc_client_use_callback(g_vc); + service_changed_callback(previous_service_state, service_state, user_data); + vc_client_not_use_callback(g_vc); + SLOG(LOG_DEBUG, TAG_VCC, "Service state changed callback is called"); + } else { + SLOG(LOG_WARN, TAG_VCC, "[WARNING] Service state changed callback is null"); + } + + /* Register focus handler */ g_focus_in_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, __focus_changed_cb, NULL); g_focus_out_handler = ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, __focus_changed_cb, NULL); diff --git a/client/vc_mgr.c b/client/vc_mgr.c index ab8d584..ff628fc 100644 --- a/client/vc_mgr.c +++ b/client/vc_mgr.c @@ -396,18 +396,33 @@ static Eina_Bool __vc_mgr_connect_daemon(void *data) } /* Set service state */ + vc_service_state_e previous_service_state; + vc_mgr_client_get_service_state(g_vc_m, &previous_service_state); + vc_mgr_client_set_service_state(g_vc_m, (vc_service_state_e)service_state); + vc_service_state_changed_cb service_changed_callback = NULL; + void* user_data = NULL; + vc_mgr_client_get_service_state_changed_cb(g_vc_m, &service_changed_callback, &user_data); + + if (NULL != service_changed_callback) { + vc_mgr_client_use_callback(g_vc_m); + service_changed_callback(previous_service_state, service_state, user_data); + vc_mgr_client_not_use_callback(g_vc_m); + SLOG(LOG_DEBUG, TAG_VCM, "Service state changed callback is called"); + } else { + SLOG(LOG_WARN, TAG_VCM, "[WARNING] Service state changed callback is null"); + } + /* Set foreground */ vc_mgr_client_set_foreground(g_vc_m, foreground, true); SLOG(LOG_ERROR, TAG_VCM, "[SUCCESS] Connected daemon"); + /* Set client state */ vc_mgr_client_set_client_state(g_vc_m, VC_STATE_READY); vc_state_changed_cb changed_callback = NULL; - void* user_data = NULL; - vc_mgr_client_get_state_changed_cb(g_vc_m, &changed_callback, &user_data); vc_state_e current_state; diff --git a/client/vc_mgr_client.c b/client/vc_mgr_client.c index 18120ed..f6b9603 100644 --- a/client/vc_mgr_client.c +++ b/client/vc_mgr_client.c @@ -198,7 +198,7 @@ int vc_mgr_client_create(vc_h* vc) client->result_event = -1; client->result_text = NULL; - client->service_state = 0; + client->service_state = VC_SERVICE_STATE_NONE; client->internal_state = VC_INTERNAL_STATE_NONE; diff --git a/client/vc_widget.c b/client/vc_widget.c index 0dcca65..eb54aa7 100644 --- a/client/vc_widget.c +++ b/client/vc_widget.c @@ -395,10 +395,28 @@ static Eina_Bool __vc_widget_connect_daemon(void *data) return EINA_TRUE; } + /* Set service state */ + vc_service_state_e previous_service_state; + vc_widget_client_get_service_state(vc_w, &previous_service_state); + vc_widget_client_set_service_state(vc_w, (vc_service_state_e)service_state); + vc_service_state_changed_cb service_changed_callback = NULL; + void* user_data = NULL; + vc_widget_client_get_service_state_changed_cb(vc_w, &service_changed_callback, &user_data); + + if (NULL != service_changed_callback) { + vc_widget_client_use_callback(vc_w); + service_changed_callback(previous_service_state, service_state, user_data); + vc_widget_client_not_use_callback(vc_w); + SLOG(LOG_DEBUG, TAG_VCW, "Service state changed callback is called"); + } else { + SLOG(LOG_WARN, TAG_VCW, "[WARNING] Service state changed callback is null"); + } + SLOG(LOG_INFO, TAG_VCW, "@@@ [Widget] Connect daemon"); + /* Get app focus and set foreground */ char appid[1024] = {'\0',}; aul_app_get_appid_bypid(getpid(), appid, sizeof(appid) - 1); @@ -411,10 +429,10 @@ static Eina_Bool __vc_widget_connect_daemon(void *data) } } + /* Set client state */ vc_widget_client_set_state(vc_w, VC_STATE_READY); vc_state_changed_cb changed_callback = NULL; - void* user_data; vc_widget_client_get_state_changed_cb(vc_w, &changed_callback, &user_data); diff --git a/server/vcd_server.c b/server/vcd_server.c index d5bf69b..8bdf090 100644 --- a/server/vcd_server.c +++ b/server/vcd_server.c @@ -1217,7 +1217,7 @@ int vcd_initialize(vce_request_callback_s *callback) vcd_client_manager_unset(); vcd_config_set_service_state(VCD_STATE_READY); - vcdc_send_service_state(VCD_STATE_READY); +// vcdc_send_service_state(VCD_STATE_READY); /* Set timer cleanup client all */ g_check_client_timer = ecore_timer_add(CLIENT_CLEAN_UP_TIME, vcd_cleanup_client_all, NULL); -- 2.7.4 From 86f610f7fc5872a5f7804537475ff6707e81ba60 Mon Sep 17 00:00:00 2001 From: sungrae jo Date: Tue, 24 Jul 2018 16:20:04 +0900 Subject: [PATCH 15/16] Add not supported logic for VCE Change-Id: Icda734be455ffb1edd2a98fab7604c20215c0714 Signed-off-by: sungrae jo --- server/vce.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/server/vce.c b/server/vce.c index 36e842d..56ef2b2 100644 --- a/server/vce.c +++ b/server/vce.c @@ -176,6 +176,10 @@ int vce_main(int argc, char** argv, vce_request_callback_s *callback) int vce_send_result(vce_result_event_e event, int* result_id, int count, const char* all_result, const char* non_fixed_result, const char* nlu_result, const char* msg, int* user_info, void *user_data) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (event < VCE_RESULT_EVENT_SUCCESS || event > VCE_RESULT_EVENT_ERROR) { @@ -200,6 +204,10 @@ int vce_send_result(vce_result_event_e event, int* result_id, int count, const c int vce_send_asr_result(vce_asr_result_event_e event, const char* asr_result, void *user_data) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (event < VCE_ASR_RESULT_EVENT_FINAL_RESULT || event > VCE_ASR_RESULT_EVENT_ERROR) { @@ -223,6 +231,10 @@ int vce_send_asr_result(vce_asr_result_event_e event, const char* asr_result, vo int vce_send_specific_engine_result(const char* engine_app_id, const char* event, const char* result, void *user_info) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (NULL == engine_app_id || NULL == event) { @@ -246,6 +258,10 @@ int vce_send_specific_engine_result(const char* engine_app_id, const char* event int vce_send_nlg_result(const char* nlg_result, void *user_data) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (NULL == nlg_result) { @@ -264,6 +280,10 @@ int vce_send_nlg_result(const char* nlg_result, void *user_data) int vce_send_error(vce_error_e error, const char* msg, void *user_data) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (NULL == msg) { @@ -283,6 +303,10 @@ int vce_send_error(vce_error_e error, const char* msg, void *user_data) /* Daemon API */ int vce_get_foreach_command(vce_cmd_h vce_command, vce_command_cb callback, void* user_data) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; ret = vcd_get_foreach_command(vce_command, callback, user_data); @@ -295,6 +319,10 @@ int vce_get_foreach_command(vce_cmd_h vce_command, vce_command_cb callback, void int vce_get_command_count(vce_cmd_h vce_command, int* count) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (NULL == count) { @@ -460,6 +488,10 @@ int vce_set_private_data_requested_cb(vce_private_data_requested_cb callback_fun int vce_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_func) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + if (NULL == callback_func) { SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Invalid parameter"); return VCE_ERROR_INVALID_PARAMETER; @@ -475,6 +507,10 @@ int vce_set_nlu_base_info_requested_cb(vce_nlu_base_info_requested_cb callback_f int vce_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_func) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + if (NULL == callback_func) { SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Invalid parameter"); return VCE_ERROR_INVALID_PARAMETER; @@ -490,6 +526,10 @@ int vce_set_specific_engine_request_cb(vce_specific_engine_request_cb callback_f int vce_unset_specific_engine_request_cb(void) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = vcd_set_specific_engine_request_cb(NULL); if (0 != ret) { SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to set specific engine request cb"); @@ -501,6 +541,10 @@ int vce_unset_specific_engine_request_cb(void) /* for TTS feedback */ int vce_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_audio_type_e audio_type) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (channel < VCE_AUDIO_CHANNEL_MONO || channel > VCE_AUDIO_CHANNEL_STEREO) { @@ -523,6 +567,10 @@ int vce_send_feedback_audio_format(int rate, vce_audio_channel_e channel, vce_au int vce_send_feedback_streaming(vce_feedback_event_e event, char* buffer, int len) { + if (0 != __vce_get_feature_enabled()) { + return VCE_ERROR_NOT_SUPPORTED; + } + int ret = VCE_ERROR_NONE; if (NULL == buffer) { -- 2.7.4 From b1d7b60b7dff945bd755b0294f12c8645a75c30f Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Mon, 30 Jul 2018 14:47:53 +0900 Subject: [PATCH 16/16] Fix dbus delay when requesting hello Change-Id: I376556d68ed3d1a3b6ad2ab59830d91aaeb5e46d Signed-off-by: sooyeon.kim --- client/vc_dbus.c | 2 +- client/vc_mgr_dbus.c | 2 +- client/vc_widget_dbus.c | 2 +- server/vcd_dbus.c | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/client/vc_dbus.c b/client/vc_dbus.c index dfe0228..c72dff6 100644 --- a/client/vc_dbus.c +++ b/client/vc_dbus.c @@ -402,7 +402,7 @@ int vc_dbus_request_hello() DBusMessage* result_msg = NULL; int result = 0; - result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, 500, &err); + result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, -1, &err); if (dbus_error_is_set(&err)) { SLOG(LOG_DEBUG, TAG_VCC, "[ERROR] Dbus Error (%s)", err.message); diff --git a/client/vc_mgr_dbus.c b/client/vc_mgr_dbus.c index 040ebcb..bc69307 100644 --- a/client/vc_mgr_dbus.c +++ b/client/vc_mgr_dbus.c @@ -842,7 +842,7 @@ int vc_mgr_dbus_request_hello() DBusMessage* result_msg = NULL; int result = 0; - result_msg = dbus_connection_send_with_reply_and_block(g_m_conn_sender, msg, 500, &err); + result_msg = dbus_connection_send_with_reply_and_block(g_m_conn_sender, msg, -1, &err); if (dbus_error_is_set(&err)) { SLOG(LOG_DEBUG, TAG_VCM, "[ERROR] Dbus Error (%s)", err.message); diff --git a/client/vc_widget_dbus.c b/client/vc_widget_dbus.c index 6883ad0..8dbca3c 100644 --- a/client/vc_widget_dbus.c +++ b/client/vc_widget_dbus.c @@ -485,7 +485,7 @@ int vc_widget_dbus_request_hello() DBusMessage* result_msg = NULL; int result = 0; - result_msg = dbus_connection_send_with_reply_and_block(g_w_conn_sender, msg, 500, &err); + result_msg = dbus_connection_send_with_reply_and_block(g_w_conn_sender, msg, -1, &err); if (dbus_error_is_set(&err)) { if (!strncmp(err.name, DBUS_ERROR_SERVICE_UNKNOWN, strlen(err.name))) diff --git a/server/vcd_dbus.c b/server/vcd_dbus.c index 5b3d4ee..e53814c 100644 --- a/server/vcd_dbus.c +++ b/server/vcd_dbus.c @@ -1250,6 +1250,11 @@ int vcd_dbus_open_connection() return VCD_ERROR_OPERATION_FAILED; } + /* Flush messages which are received before fd event handler registration */ + while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status(g_conn_listener)) { + listener_event_callback(NULL, NULL); + } + /* add a rule for getting signal */ char rule[128]; snprintf(rule, 128, "type='signal',interface='%s'", VC_SERVER_SERVICE_INTERFACE); -- 2.7.4