X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=client%2Ftts.c;h=1c78f22da672637ce201125444864eb7537f9f33;hb=afb4d96918d202f02cafe860d7517875bf96e851;hp=64c073e4e60687da93143418eea3ab36b8291a21;hpb=a65c39e6b953b0bf10676f0ca4fa4d28c7a1f0cb;p=platform%2Fcore%2Fuifw%2Ftts.git diff --git a/client/tts.c b/client/tts.c index 64c073e..1c78f22 100644 --- a/client/tts.c +++ b/client/tts.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "tts.h" #include "tts_client.h" @@ -37,9 +39,30 @@ static bool g_err_callback_status = false; static int g_max_text_size = -1; +static Ecore_Timer* g_check_state_timer = NULL; + +static Ecore_Timer* g_hello_timer; + +/* for repetition */ +static char* g_language = NULL; + +static int g_voice_type = -1; + +static int g_speed = -1; +static int g_retry_cnt = 0; + +/* for checking engine update */ +static pkgmgr_client* g_pkgmgr = NULL; +static char* g_engine_name = NULL; +static int g_engine_update_status = 0; +static pthread_mutex_t g_pkgmgr_mutex = PTHREAD_MUTEX_INITIALIZER; + + /* Function definition */ static Eina_Bool __tts_notify_state_changed(void *data); static Eina_Bool __tts_notify_error(void *data); +int __tts_cb_error(int uid, tts_error_e reason, int utt_id, char* err_msg); + const char* tts_tag() { @@ -109,6 +132,7 @@ static int __tts_convert_config_error_code(tts_config_error_e code) return code; } +//LCOV_EXCL_START void __tts_config_voice_changed_cb(const char* before_lang, int before_voice_type, const char* language, int voice_type, bool auto_voice, void* user_data) { SLOG(LOG_DEBUG, TAG_TTSC, "Voice changed : Before lang(%s) type(%d) , Current lang(%s), type(%d)", @@ -132,6 +156,14 @@ void __tts_config_voice_changed_cb(const char* before_lang, int before_voice_typ language, voice_type, data->default_voice_changed_user_data); } + /* Check whether language is changed or not. If it is changed, make 'text_repeat' NULL */ + if (0 != strncmp(before_lang, language, strlen(before_lang))) { + if (NULL != data->text_repeat) { + free(data->text_repeat); + data->text_repeat = NULL; + } + } + /* Next item */ iter = g_list_next(iter); } @@ -211,6 +243,85 @@ void _tts_config_engine_changed_cb(const char* engine_id, const char* setting, c } return; } +//LCOV_EXCL_STOP + +void __tts_unset_all_callbacks(tts_h tts) +{ + SLOG(LOG_INFO, TAG_TTSC, "@@@ unset all callbacks"); + + tts_unset_state_changed_cb(tts); + tts_unset_utterance_started_cb(tts); + tts_unset_utterance_completed_cb(tts); + tts_unset_error_cb(tts); + tts_unset_default_voice_changed_cb(tts); + tts_unset_engine_changed_cb(tts); + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); +} + +static int __pkgmgr_status_cb(uid_t target_uid, int req_id, const char *type, const char *pkgname, const char *key, const char *val, const void *pmsg, void *data) +{ + SLOG(LOG_INFO, TAG_TTSC, "[INFO] pkgmgr status cb is invoked. pkgname(%s), type(%s), key(%s), val(%s)", pkgname, type, key, val); + + if (0 != strncmp(g_engine_name, pkgname, strlen(g_engine_name))) { + SLOG(LOG_DEBUG, TAG_TTSC, "[WARN] this is not tts engine"); + return 0; + } else { + if (key && 0 == strncmp(key, "start", strlen(key))) { + if (val && (0 == strncmp(val, "update", strlen(val) || 0 == strncmp(val, "uninstall", strlen(val))))) { + SLOG(LOG_INFO, TAG_TTSC, "[INFO] start to install."); + g_engine_update_status = 1; + } + } else if (key && 0 == strncmp(key, "end", strlen(key))) { + SLOG(LOG_INFO, TAG_TTSC, "[INFO] finish to install"); + g_engine_update_status = 0; + } + } + + return 0; +} + +static void __create_pkgmgr_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] create pkgmgr thread"); + + pthread_mutex_lock(&g_pkgmgr_mutex); + + while (!g_pkgmgr) { + g_pkgmgr = pkgmgr_client_new(PC_LISTENING); + if (NULL == g_pkgmgr) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to create pkgmgr handle"); + } else { + if (pkgmgr_client_listen_status(g_pkgmgr, __pkgmgr_status_cb, NULL) < 0) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to listen pkgmgr status. remove and recreate client"); + pkgmgr_client_free(g_pkgmgr); + g_pkgmgr = NULL; + continue; + } else { + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] Succeed to register pkgmgr cb"); + } + } + usleep(10000); + } + + pthread_mutex_unlock(&g_pkgmgr_mutex); + + return ; +} + +static void __finish_pkgmgr_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] Finish pkgmgr thread"); +} + +static void __pkgmgr_thread(void* data) +{ + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] call pkgmgr_thread"); + + ecore_thread_run(__create_pkgmgr_thread, __finish_pkgmgr_thread, NULL, NULL); + + return ; +} int tts_create(tts_h* tts) { @@ -252,13 +363,24 @@ int tts_create(tts_h* tts) return __tts_convert_config_error_code(ret); } - ret = tts_config_mgr_set_callback(client->uid, _tts_config_engine_changed_cb, __tts_config_voice_changed_cb, NULL, NULL, client->tts); + ret = tts_config_mgr_set_callback(client->uid, _tts_config_engine_changed_cb, __tts_config_voice_changed_cb, NULL, NULL, NULL, client->tts); if (0 != ret) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to set config changed : %d", ret); tts_client_destroy(*tts); return __tts_convert_config_error_code(ret); } + ecore_main_loop_thread_safe_call_async(__pkgmgr_thread, NULL); + + SLOG(LOG_INFO, TAG_TTSC, "[INFO] call ecore thread for creating pkgmgr thread"); + + g_engine_name = vconf_get_str(TTS_ENGINE_DB_DEFAULT); + if (NULL == g_engine_name) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get engine name"); + } else { + SLOG(LOG_ERROR, TAG_TTSC, "[INFO] Engine name(%s)", g_engine_name); + } + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); @@ -292,6 +414,14 @@ int tts_destroy(tts_h tts) return TTS_ERROR_OPERATION_FAILED; } + pthread_mutex_lock(&g_pkgmgr_mutex); + if (g_pkgmgr) { + pkgmgr_client_remove_listen_status(g_pkgmgr); + pkgmgr_client_free(g_pkgmgr); + g_pkgmgr = NULL; + } + pthread_mutex_unlock(&g_pkgmgr_mutex); + tts_config_mgr_finalize(client->uid); int ret = -1; @@ -314,6 +444,7 @@ int tts_destroy(tts_h tts) do { ret = tts_dbus_request_finalize(client->uid); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_TIMED_OUT != ret) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); break; @@ -326,6 +457,7 @@ int tts_destroy(tts_h tts) break; } } + //LCOV_EXCL_STOP } } while (0 != ret); } else { @@ -341,6 +473,9 @@ int tts_destroy(tts_h tts) ecore_timer_del(client->conn_timer); client->conn_timer = NULL; } + /* Unset registered callbacks */ + __tts_unset_all_callbacks(tts); + /* Free resources */ tts_client_destroy(tts); break; @@ -355,6 +490,17 @@ int tts_destroy(tts_h tts) } } + if (NULL != g_language) { + free(g_language); + g_language = NULL; + } + + /* Delete state timer before destroying handle */ + if (NULL != g_check_state_timer) { + ecore_timer_del(g_check_state_timer); + g_check_state_timer = NULL; + } + tts = NULL; SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); @@ -362,10 +508,12 @@ int tts_destroy(tts_h tts) return TTS_ERROR_NONE; } +//LCOV_EXCL_START void __tts_screen_reader_changed_cb(bool value) { g_screen_reader = value; } +//LCOV_EXCL_STOP int tts_set_mode(tts_h tts, tts_mode_e mode) { @@ -493,6 +641,7 @@ int tts_set_credential(tts_h tts, const char* credential) return TTS_ERROR_NONE; } +//LCOV_EXCL_START int tts_set_server_tts(tts_h tts, const char* credential) { if (0 != __tts_get_feature_enabled()) { @@ -577,6 +726,7 @@ int tts_set_server_tts(tts_h tts, const char* credential) return TTS_ERROR_NONE; } +// LCOV_EXCL_STOP static Eina_Bool __tts_connect_daemon(void *data) { @@ -589,8 +739,16 @@ static Eina_Bool __tts_connect_daemon(void *data) return EINA_FALSE; } + /* check whether engine is updating or not */ + if (g_engine_update_status) { + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] cannot prepare due to engine update"); + __tts_cb_error(-1, TTS_ERROR_SERVICE_RESET, -1, "Daemon Reset"); + + return EINA_FALSE; + } + /* Send hello */ - if (0 != tts_dbus_request_hello(client->uid)) { + if (0 != tts_dbus_request_hello_sync(client->uid)) { return EINA_TRUE; } @@ -609,7 +767,10 @@ static Eina_Bool __tts_connect_daemon(void *data) client->utt_id = -1; ecore_timer_add(0, __tts_notify_error, (void*)client->tts); - client->conn_timer = NULL; + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } return EINA_FALSE; } else if (TTS_ERROR_PERMISSION_DENIED == ret) { @@ -619,7 +780,10 @@ static Eina_Bool __tts_connect_daemon(void *data) client->utt_id = -1; ecore_timer_add(0, __tts_notify_error, (void*)client->tts); - client->conn_timer = NULL; + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } return EINA_FALSE; } else if (TTS_ERROR_NONE != ret) { @@ -632,7 +796,10 @@ static Eina_Bool __tts_connect_daemon(void *data) SLOG(LOG_ERROR, TAG_TTSC, "Supported options : credential(%s)", credential_needed ? "need" : "no need"); } - client->conn_timer = NULL; + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } client = tts_client_get(tts); /* check handle */ @@ -657,6 +824,104 @@ static Eina_Bool __tts_connect_daemon(void *data) return EINA_FALSE; } +int __tts_cb_hello(int uid, int ret, int credential_needed) +{ + tts_client_s* client = tts_client_get_by_uid(uid); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "Fail to get TTS client or ignore this uid(%d)", uid); + return TTS_ERROR_OPERATION_FAILED; + } + + if (g_hello_timer) { + ecore_timer_del(g_hello_timer); + g_hello_timer = NULL; + } + + if (TTS_STATE_READY == client->current_state) { + SLOG(LOG_INFO, TAG_TTSC, "[INFO] tts client is already READY"); + return TTS_ERROR_NONE; + } + + if (TTS_ERROR_ENGINE_NOT_FOUND == ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to initialize : %s", __tts_get_error_code(ret)); + + client->reason = TTS_ERROR_ENGINE_NOT_FOUND; + client->utt_id = -1; + + ecore_timer_add(0, __tts_notify_error, (void*)client->tts); + return TTS_ERROR_OPERATION_FAILED; + + } else if (TTS_ERROR_PERMISSION_DENIED == ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to initialize : %s", __tts_get_error_code(ret)); + + client->reason = TTS_ERROR_PERMISSION_DENIED; + client->utt_id = -1; + + ecore_timer_add(0, __tts_notify_error, (void*)client->tts); + return TTS_ERROR_PERMISSION_DENIED; + + } else if (TTS_ERROR_NONE != ret) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to connection. Retry to connect : %s", __tts_get_error_code(ret)); + return TTS_ERROR_OPERATION_FAILED; + + } else { + /* success to connect tts-daemon */ + client->credential_needed = credential_needed; + SLOG(LOG_ERROR, TAG_TTSC, "Supported options : credential(%s)", credential_needed ? "need" : "no need"); + } + + client->before_state = client->current_state; + client->current_state = TTS_STATE_READY; + + ecore_timer_add(0.0, __tts_notify_state_changed, client->tts); + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_NONE; +} + +static Eina_Bool __send_hello(void *data) +{ + tts_h tts = (tts_h)data; + tts_client_s* client = tts_client_get(tts); + + /* check handle */ + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); + g_hello_timer = NULL; + return EINA_FALSE; + } + + /* check state */ + if (client->current_state == TTS_STATE_READY) { + SLOG(LOG_ERROR, TAG_TTSC, "[INFO] TTS client has been already connected to tts service"); //LCOV_EXCL_LINE + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + g_hello_timer = NULL; + return EINA_FALSE; + } + + /* Send hello */ + int ret = tts_dbus_request_hello(client->uid); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request hello !!"); //LCOV_EXCL_LINE + } else { + SLOG(LOG_ERROR, TAG_TTSC, "@@@ Send Hello"); + } + + g_retry_cnt++; + if (TTS_HELLO_RETRY_COUNT == g_retry_cnt) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Stop to send hello, retry count reaches the limit"); + g_retry_cnt = 0; + return EINA_FALSE; + } + + if (!g_hello_timer) { + SLOG(LOG_ERROR, TAG_TTSC, "@@@ Call checking Hello timer callback"); + g_hello_timer = ecore_timer_add(0.5, __send_hello, tts); + return EINA_FALSE; + } + return EINA_TRUE; +} + int tts_prepare(tts_h tts) { if (0 != __tts_get_feature_enabled()) { @@ -681,13 +946,20 @@ int tts_prepare(tts_h tts) return TTS_ERROR_INVALID_STATE; } - client->conn_timer = ecore_timer_add(0.02, __tts_connect_daemon, (void*)tts); + if (NULL == g_hello_timer) { + SLOG(LOG_ERROR, TAG_TTSC, "@@@ Call checking Hello timer callback"); + g_retry_cnt = 0; + ecore_thread_main_loop_begin(); + ecore_timer_add(0.0, __send_hello, (void*)tts); + ecore_thread_main_loop_end(); + } SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_NONE; } +//LCOV_EXCL_START int tts_prepare_sync(tts_h tts) { if (0 != __tts_get_feature_enabled()) { @@ -726,6 +998,7 @@ int tts_prepare_sync(tts_h tts) return TTS_ERROR_NONE; } +//LCOV_EXCL_STOP int tts_unprepare(tts_h tts) { @@ -766,6 +1039,7 @@ int tts_unprepare(tts_h tts) do { ret = tts_dbus_request_finalize(client->uid); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -784,6 +1058,7 @@ int tts_unprepare(tts_h tts) break; } } + //LCOV_EXCL_STOP } } while (0 != ret); } else { @@ -1135,6 +1410,28 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty } SLOG(LOG_DEBUG, TAG_TTSC, "Text is valid - text is '%s'", text); + /* save texts for repetition */ + if (NULL != client->text_repeat) { + free(client->text_repeat); + client->text_repeat = NULL; + } + + client->text_repeat = strdup(text); + + if (NULL != g_language) { + free(g_language); + g_language = NULL; + } + if (NULL == language) + g_language = NULL; + else + g_language = strdup(language); + + g_voice_type = voice_type; + g_speed = speed; + + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] repeat: text(%s), language(%s), voice type(%d), speed(%d)", client->text_repeat, (g_language) ? g_language : "NULL", g_voice_type, g_speed); + /* change default language value */ char* temp = NULL; @@ -1155,6 +1452,7 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty while (0 != ret) { ret = tts_dbus_request_add_text(client->uid, text, temp, voice_type, speed, client->current_utt_id, client->credential); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -1173,6 +1471,7 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty break; } } + //LCOV_EXCL_STOP } else { *utt_id = client->current_utt_id; } @@ -1188,6 +1487,7 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty return ret; } +//LCOV_EXCL_START static void __tts_play_async(void *data) { tts_h tts = (tts_h)data; @@ -1294,7 +1594,7 @@ int tts_play_async(tts_h tts) return TTS_ERROR_NONE; } - +//LCOV_EXCL_STOP int tts_play(tts_h tts) { if (0 != __tts_get_feature_enabled()) { @@ -1339,6 +1639,7 @@ int tts_play(tts_h tts) while (0 != ret) { ret = tts_dbus_request_play(client->uid, client->credential); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -1357,6 +1658,7 @@ int tts_play(tts_h tts) return ret; } } + //LCOV_EXCL_STOP } } @@ -1374,7 +1676,7 @@ int tts_play(tts_h tts) return TTS_ERROR_NONE; } - +//LCOV_EXCL_START static void __tts_stop_async(void *data) { tts_h tts = (tts_h)data; @@ -1476,7 +1778,7 @@ int tts_stop_aync(tts_h tts) return TTS_ERROR_NONE; } - +//LCOV_EXCL_STOP int tts_stop(tts_h tts) { if (0 != __tts_get_feature_enabled()) { @@ -1515,6 +1817,7 @@ int tts_stop(tts_h tts) while (0 != ret) { ret = tts_dbus_request_stop(client->uid); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -1533,6 +1836,7 @@ int tts_stop(tts_h tts) return ret; } } + //LCOV_EXCL_STOP } } @@ -1550,7 +1854,7 @@ int tts_stop(tts_h tts) return TTS_ERROR_NONE; } - +//LCOV_EXCL_START static void __tts_pause_async(void *data) { tts_h tts = (tts_h)data; @@ -1653,7 +1957,7 @@ int tts_pause_async(tts_h tts) return TTS_ERROR_NONE; } - +//LCOV_EXCL_STOP int tts_pause(tts_h tts) { if (0 != __tts_get_feature_enabled()) { @@ -1693,6 +1997,7 @@ int tts_pause(tts_h tts) while (0 != ret) { ret = tts_dbus_request_pause(client->uid); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -1711,6 +2016,7 @@ int tts_pause(tts_h tts) return ret; } } + //LCOV_EXCL_STOP } } @@ -1738,7 +2044,7 @@ int tts_set_private_data(tts_h tts, const char* key, const char* data) SLOG(LOG_INFO, TAG_TTSC, "@@@ Set private data, key(%s), data(%s)", key, data); if (NULL == tts) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle isnull"); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); return TTS_ERROR_INVALID_PARAMETER; } @@ -1770,6 +2076,7 @@ int tts_set_private_data(tts_h tts, const char* key, const char* data) while (0 != ret) { ret = tts_dbus_request_set_private_data(client->uid, key, data); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -1788,6 +2095,7 @@ int tts_set_private_data(tts_h tts, const char* key, const char* data) return ret; } } + //LCOV_EXCL_STOP } } @@ -1832,6 +2140,7 @@ int tts_get_private_data(tts_h tts, const char* key, char** data) while (0 != ret) { ret = tts_dbus_request_get_private_data(client->uid, key, data); if (0 != ret) { + //LCOV_EXCL_START if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { client->current_state = TTS_STATE_CREATED; if (0 == tts_prepare_sync(tts)) { @@ -1850,6 +2159,7 @@ int tts_get_private_data(tts_h tts, const char* key, char** data) return ret; } } + //LCOV_EXCL_STOP } } @@ -1863,6 +2173,7 @@ int tts_get_private_data(tts_h tts, const char* key, char** data) return 0; } +//LCOV_EXCL_START static Eina_Bool __tts_notify_error(void *data) { tts_h tts = (tts_h)data; @@ -1891,6 +2202,44 @@ static Eina_Bool __tts_notify_error(void *data) return EINA_FALSE; } +static void __start_reprepare_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] start reprepare thread. engine update status(%d)", g_engine_update_status); + + tts_client_s* temp = (tts_client_s*)data; + if (NULL == temp) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] data is null"); + return ; + } + + int cnt = 0; + while (!g_engine_update_status && (cnt < 10)) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] wait for starting update"); + usleep(50000); + cnt++; + } + + SLOG(LOG_ERROR, TAG_TTSC, "[DEBUG] update status(%d)", g_engine_update_status); + + while (g_engine_update_status && (NULL != g_pkgmgr)) { +// SLOG(LOG_WARN, TAG_TTSC, "[WARNING] wait for finishing update"); + usleep(200000); + } + + SLOG(LOG_INFO, TAG_TTSC, "[INFO] finish updating. request to prepare"); + + if (0 != tts_prepare(temp->tts)) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to prepare"); + } + + return ; +} + +static void __end_reprepare_thread(void* data, Ecore_Thread* thread) +{ + SLOG(LOG_INFO, TAG_TTSC, "[INFO] end reprepare thread"); +} + int __tts_cb_error(int uid, tts_error_e reason, int utt_id, char* err_msg) { if (-1 == uid) { @@ -1927,9 +2276,8 @@ int __tts_cb_error(int uid, tts_error_e reason, int utt_id, char* err_msg) SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Service Reset"); data->current_state = TTS_STATE_CREATED; - if (0 != tts_prepare(data->tts)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to prepare"); - } + data->reason = 0; + ecore_thread_run(__start_reprepare_thread, __end_reprepare_thread, NULL, data); } /* Next item */ @@ -1964,9 +2312,8 @@ int __tts_cb_error(int uid, tts_error_e reason, int utt_id, char* err_msg) SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Service Reset"); client->current_state = TTS_STATE_CREATED; - if (0 != tts_prepare(client->tts)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to prepare"); - } + client->reason = 0; + ecore_thread_run(__start_reprepare_thread, __end_reprepare_thread, NULL, client); } } @@ -2013,7 +2360,11 @@ int __tts_cb_set_state(int uid, int state) } if (NULL != client->state_changed_cb) { - ecore_timer_add(0, __tts_notify_state_changed, client->tts); + if (NULL != g_check_state_timer) { + ecore_timer_del(g_check_state_timer); + g_check_state_timer = NULL; + } + g_check_state_timer = ecore_timer_add(0, __tts_notify_state_changed, client->tts); } else { SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null"); } @@ -2023,6 +2374,7 @@ int __tts_cb_set_state(int uid, int state) return 0; } +//LCOV_EXCL_STOP int __tts_cb_utt_started(int uid, int utt_id) { @@ -2133,6 +2485,11 @@ int tts_unset_state_changed_cb(tts_h tts) client->state_changed_cb = NULL; client->state_changed_user_data = NULL; + if (NULL != g_check_state_timer) { + ecore_timer_del(g_check_state_timer); + g_check_state_timer = NULL; + } + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Unset state changed cb"); return 0; @@ -2447,6 +2804,7 @@ int tts_unset_engine_changed_cb(tts_h tts) return 0; } +//LCOV_EXCL_START int tts_add_pcm(tts_h tts, int event, const void* data, unsigned int data_size, int audio_type, int rate) { if (0 != __tts_get_feature_enabled()) { @@ -2658,3 +3016,97 @@ int tts_stop_pcm(tts_h tts) return TTS_ERROR_NONE; } +//LCOV_EXCL_STOP + +int tts_repeat(tts_h tts, char** text_repeat, int* utt_id) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Repeat TTS"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (NULL == text_repeat || NULL == utt_id) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + *text_repeat = NULL; + *utt_id = -1; + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_READY != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid. (%d)", client->current_state); + return TTS_ERROR_INVALID_STATE; + } + + /* Clear the legacy and Add texts to be played repeatedly */ + int ret = -1; + ret = tts_stop(tts); + if (TTS_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to clear the legacy"); + return ret; + } + + if (NULL != client->text_repeat) { + char* tmp_text = strdup(client->text_repeat); + char* tmp_lang = NULL; + if (NULL != g_language) { + tmp_lang = strdup(g_language); + } + ret = tts_add_text(tts, tmp_text, tmp_lang, g_voice_type, g_speed, utt_id); + if (TTS_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to add texts for repetition."); + if (NULL != tmp_text) { + free(tmp_text); + tmp_text = NULL; + } + if (NULL != tmp_lang) { + free(tmp_lang); + tmp_lang = NULL; + } + return ret; + } + *text_repeat = strdup(client->text_repeat); + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] text to repeat(%s), utt_id(%d)", (*text_repeat) ? *text_repeat : "NULL", *utt_id); + if (NULL != tmp_text) { + free(tmp_text); + tmp_text = NULL; + } + if (NULL != tmp_lang) { + free(tmp_lang); + tmp_lang = NULL; + } + } else { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] There is no previous added texts. Please add texts"); + return TTS_ERROR_OPERATION_FAILED; + } + + /* Play added texts */ + ret = tts_play(tts); + if (TTS_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to play texts for repetition."); + if (NULL != *text_repeat) { + free(*text_repeat); + *text_repeat = NULL; + } + *utt_id = -1; + return ret; + } + + return TTS_ERROR_NONE; +}