X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=client%2Ftts.c;h=67db4b9f3c920f1429a5880a21da601db35e6511;hb=refs%2Fheads%2Ftizen_5.5_mobile_hotfix;hp=0a0f5e97e5b454f5bc34409da647c8889919ed7f;hpb=45958d186275d172e8eb8b33c84fae0b91cd282c;p=platform%2Fcore%2Fuifw%2Ftts.git diff --git a/client/tts.c b/client/tts.c index 0a0f5e9..67db4b9 100644 --- a/client/tts.c +++ b/client/tts.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2011-2016 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 @@ -11,65 +11,290 @@ * limitations under the License. */ - -#include +#include +#include #include +#include #include -#include -#include +#include +#include +#include +#include -#include "tts_main.h" +#include "tts.h" #include "tts_client.h" +#include "tts_config_mgr.h" #include "tts_dbus.h" +#include "tts_main.h" + +#include "tts_internal.h" -#define MAX_TEXT_COUNT 2000 +static bool g_screen_reader; -static bool g_is_daemon_started = false; +static int g_feature_enabled = -1; -static bool g_is_noti_daemon_started = false; +static bool g_err_callback_status = false; -static bool g_is_sr_daemon_started = false; +static int g_max_text_size = -1; + +static Ecore_Timer* g_check_state_timer = NULL; + + +/* for repetition */ +static char* g_language = NULL; + +static int g_voice_type = -1; + +static int g_speed = -1; -static Ecore_Timer* g_connect_timer = NULL; /* Function definition */ -static int __tts_check_tts_daemon(tts_mode_e mode); static Eina_Bool __tts_notify_state_changed(void *data); static Eina_Bool __tts_notify_error(void *data); +const char* tts_tag() +{ + return "ttsc"; +} + +static int __tts_get_feature_enabled() +{ + if (0 == g_feature_enabled) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] TTS feature NOT supported"); + return TTS_ERROR_NOT_SUPPORTED; + } else if (-1 == g_feature_enabled) { + bool tts_supported = false; + if (0 == system_info_get_platform_bool(TTS_FEATURE_PATH, &tts_supported)) { + if (false == tts_supported) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] TTS feature NOT supported"); + g_feature_enabled = 0; + return TTS_ERROR_NOT_SUPPORTED; + } + + g_feature_enabled = 1; + } else { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get feature value"); + return TTS_ERROR_NOT_SUPPORTED; + } + } + + return 0; +} + +static const char* __tts_get_error_code(tts_error_e err) +{ + switch (err) { + case TTS_ERROR_NONE: return "TTS_ERROR_NONE"; + case TTS_ERROR_OUT_OF_MEMORY: return "TTS_ERROR_OUT_OF_MEMORY"; + case TTS_ERROR_IO_ERROR: return "TTS_ERROR_IO_ERROR"; + case TTS_ERROR_INVALID_PARAMETER: return "TTS_ERROR_INVALID_PARAMETER"; + case TTS_ERROR_OUT_OF_NETWORK: return "TTS_ERROR_OUT_OF_NETWORK"; + case TTS_ERROR_TIMED_OUT: return "TTS_ERROR_TIMED_OUT"; + case TTS_ERROR_PERMISSION_DENIED: return "TTS_ERROR_PERMISSION_DENIED"; + case TTS_ERROR_NOT_SUPPORTED: return "TTS_ERROR_NOT_SUPPORTED"; + case TTS_ERROR_INVALID_STATE: return "TTS_ERROR_INVALID_STATE"; + case TTS_ERROR_INVALID_VOICE: return "TTS_ERROR_INVALID_VOICE"; + case TTS_ERROR_ENGINE_NOT_FOUND: return "TTS_ERROR_ENGINE_NOT_FOUND"; + case TTS_ERROR_OPERATION_FAILED: return "TTS_ERROR_OPERATION_FAILED"; + case TTS_ERROR_AUDIO_POLICY_BLOCKED: return "TTS_ERROR_AUDIO_POLICY_BLOCKED"; + case TTS_ERROR_NOT_SUPPORTED_FEATURE: return "TTS_ERROR_NOT_SUPPORTED_FEATURE"; + case TTS_ERROR_SERVICE_RESET: return "TTS_ERROR_SERVICE_RESET"; + default: + return "Invalid error code"; + } + return NULL; +} + +static int __tts_convert_config_error_code(tts_config_error_e code) +{ + if (code == TTS_CONFIG_ERROR_NONE) return TTS_ERROR_NONE; + if (code == TTS_CONFIG_ERROR_OUT_OF_MEMORY) return TTS_ERROR_OUT_OF_MEMORY; + if (code == TTS_CONFIG_ERROR_IO_ERROR) return TTS_ERROR_IO_ERROR; + if (code == TTS_CONFIG_ERROR_INVALID_PARAMETER) return TTS_ERROR_INVALID_PARAMETER; + if (code == TTS_CONFIG_ERROR_INVALID_STATE) return TTS_ERROR_INVALID_STATE; + if (code == TTS_CONFIG_ERROR_INVALID_VOICE) return TTS_ERROR_INVALID_VOICE; + if (code == TTS_CONFIG_ERROR_ENGINE_NOT_FOUND) return TTS_ERROR_ENGINE_NOT_FOUND; + if (code == TTS_CONFIG_ERROR_OPERATION_FAILED) return TTS_ERROR_OPERATION_FAILED; + if (code == TTS_CONFIG_ERROR_NOT_SUPPORTED_FEATURE) return TTS_ERROR_NOT_SUPPORTED_FEATURE; + + 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)", + before_lang, before_voice_type, language, voice_type); + + GList* client_list = NULL; + client_list = tts_client_get_client_list(); + + GList *iter = NULL; + tts_client_s *data = NULL; + + if (g_list_length(client_list) > 0) { + /* Get a first item */ + iter = g_list_first(client_list); + + while (NULL != iter) { + data = iter->data; + if (NULL != data->default_voice_changed_cb) { + SLOG(LOG_DEBUG, TAG_TTSC, "Call default voice changed callback : uid(%d)", data->uid); + data->default_voice_changed_cb(data->tts, before_lang, before_voice_type, + 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); + } + } + + return; +} + +static Eina_Bool __reconnect_by_engine_changed(void* data) +{ + tts_h tts = (tts_h)data; + + tts_client_s* client = tts_client_get(tts); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[WARNING] A handle is not valid"); + return EINA_FALSE; + } + + if (TTS_STATE_READY != client->current_state) { + usleep(10000); + return EINA_TRUE; + } + + int ret = tts_unprepare(tts); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + ret = tts_prepare(tts); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + + return EINA_FALSE; +} + +void _tts_config_engine_changed_cb(const char* engine_id, const char* setting, const char* language, int voice_type, bool auto_voice, bool need_credential, void* user_data) +{ + tts_h tts = (tts_h)user_data; + + tts_client_s* client = tts_client_get(tts); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[WARNING] A handle is not valid"); + return; + } + + if (NULL != engine_id) SLOG(LOG_DEBUG, TAG_TTSC, "Engine id(%s)", engine_id); + if (NULL != setting) SLOG(LOG_DEBUG, TAG_TTSC, "Engine setting(%s)", setting); + if (NULL != language) SLOG(LOG_DEBUG, TAG_TTSC, "Language(%s)", language); + SLOG(LOG_DEBUG, TAG_TTSC, "Voice type(%d), Auto voice(%s), Credential(%s)", voice_type, auto_voice ? "on" : "off", need_credential ? "need" : "no need"); + + /* When the default engine is changed, please unload the old engine and load the new one. */ + int ret = -1; + + if (TTS_STATE_PLAYING == client->current_state || TTS_STATE_PAUSED == client->current_state) { + ret = tts_stop(tts); + if (0 != ret) { + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] TTS client stopping..."); + } + + ecore_idler_add(__reconnect_by_engine_changed, (void*)tts); + } else if (TTS_STATE_READY == client->current_state) { + ret = tts_unprepare(tts); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to unprepare for setting a new engine... (%d)", ret); + } + ret = tts_prepare(tts); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + } + + /* call callback function */ + if (NULL != client->engine_changed_cb) { + client->engine_changed_cb(tts, engine_id, language, voice_type, need_credential, client->engine_changed_user_data); + } else { + SLOG(LOG_WARN, TAG_TTSC, "No registered callback function for changed engine"); + } + 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, "@@@"); +} + int tts_create(tts_h* tts) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Create TTS"); - + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Create TTS"); + /* check param */ if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; - } + } if (0 == tts_client_get_size()) { if (0 != tts_dbus_open_connection()) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to open dbus connection"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_OPERATION_FAILED; } } if (0 != tts_client_new(tts)) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to create client!!!!!"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_OUT_OF_MEMORY; } - g_is_daemon_started = false; - g_is_noti_daemon_started = false; - g_is_sr_daemon_started = false; + tts_client_s* client = tts_client_get(*tts); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get client"); + return TTS_ERROR_OPERATION_FAILED; + } + + int ret = tts_config_mgr_initialize(client->uid); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to init config manager : %d", ret); + tts_client_destroy(*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, 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); + } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_NONE; @@ -77,12 +302,14 @@ int tts_create(tts_h* tts) int tts_destroy(tts_h tts) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Destroy TTS"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Destroy TTS"); if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; } @@ -91,8 +318,6 @@ int tts_destroy(tts_h tts) /* check handle */ if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; } @@ -102,139 +327,315 @@ int tts_destroy(tts_h tts) return TTS_ERROR_OPERATION_FAILED; } + tts_config_mgr_finalize(client->uid); + int ret = -1; + int count = 0; + int screen_reader = -1; /* check state */ switch (client->current_state) { case TTS_STATE_PAUSED: case TTS_STATE_PLAYING: case TTS_STATE_READY: - /* Request Finalize */ - ret = tts_dbus_request_finalize(client->uid); + ret = vconf_get_bool(TTS_ACCESSIBILITY_KEY, &screen_reader); if (0 != ret) { - SLOG(LOG_WARN, TAG_TTSC, "[ERROR] Fail to request finalize"); + SLOG(LOG_ERROR, tts_tag(), "[ERROR] Fail to get screen reader"); + } else { + SLOG(LOG_INFO, tts_tag(), "[INFO] Success to get screen reader(%d), g_screen_reader(%s), client->mode(%d)", screen_reader, (true == g_screen_reader) ? "True" : "False", client->mode); + g_screen_reader = (bool)screen_reader; + } + if (!(false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode)) { + 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; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry finalize"); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + break; + } + } + //LCOV_EXCL_STOP + } + } while (0 != ret); + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Do not request finalize : g_sr(%d) mode(%d)", g_screen_reader, client->mode); } - - if (TTS_MODE_SCREEN_READER == client->mode) - g_is_sr_daemon_started = false; - else if (TTS_MODE_NOTIFICATION == client->mode) - g_is_noti_daemon_started = false; - else - g_is_daemon_started = false; client->before_state = client->current_state; client->current_state = TTS_STATE_CREATED; - ecore_timer_add(0, __tts_notify_state_changed, (void*)tts); - - /* Close file message connection */ - if (0 == tts_client_get_connected_client_count()) { - SLOG(LOG_DEBUG, TAG_TTSC, "Close file msg connection"); - ret = tts_file_msg_close_connection(); - if (0 != ret) - SLOG(LOG_WARN, TAG_TTSC, "[ERROR] Fail to close file message connection"); - } - case TTS_STATE_CREATED: - if (NULL != g_connect_timer) { + if (NULL != client->conn_timer) { SLOG(LOG_DEBUG, TAG_TTSC, "Connect Timer is deleted"); - ecore_timer_del(g_connect_timer); + 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; + + default: + break; } - + if (0 == tts_client_get_size()) { if (0 != tts_dbus_close_connection()) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to close connection"); } } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + 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, "@@@"); 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) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Set TTS mode"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Set TTS mode(%d)", mode); tts_client_s* client = tts_client_get(tts); /* check handle */ if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not available"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } /* check state */ if (client->current_state != TTS_STATE_CREATED) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_STATE; } - if (TTS_MODE_DEFAULT <= mode && mode <= TTS_MODE_SCREEN_READER) { + if (TTS_MODE_DEFAULT <= mode && mode <= TTS_MODE_INTERRUPT) { client->mode = mode; } else { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] mode is not valid : %d", mode); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + if (TTS_MODE_SCREEN_READER == mode) { + int ret; + int screen_reader; + ret = vconf_get_bool(TTS_ACCESSIBILITY_KEY, &screen_reader); + if (0 != ret) { + SLOG(LOG_ERROR, tts_tag(), "[Config ERROR] Fail to get screen reader"); + return TTS_ERROR_OPERATION_FAILED; + } + g_screen_reader = (bool)screen_reader; + tts_config_set_screen_reader_callback(client->uid, __tts_screen_reader_changed_cb); + } else { + tts_config_unset_screen_reader_callback(client->uid); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_NONE; } int tts_get_mode(tts_h tts, tts_mode_e* mode) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Get TTS mode"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Get TTS mode"); tts_client_s* client = tts_client_get(tts); /* check handle */ if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not available"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; } /* check state */ if (client->current_state != TTS_STATE_CREATED) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_STATE; } if (NULL == mode) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter(mode) is NULL"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; - } + } *mode = client->mode; - - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_NONE; } +int tts_set_credential(tts_h tts, const char* credential) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts || NULL == credential) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_CREATED != client->current_state && 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; + } + + if (NULL != client->credential) { + free(client->credential); + client->credential = NULL; + } + client->credential = strdup(credential); + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} + +//LCOV_EXCL_START +int tts_set_server_tts(tts_h tts, const char* credential) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_CREATED != client->current_state && 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; + } + + if (NULL != client->credential) { + free(client->credential); + client->credential = NULL; + } + + client->internal = true; + + char* key = NULL; + if (NULL != credential) { + key = strdup("EnableServerTTS"); + client->credential = strdup(credential); + if (NULL == client->credential) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to allocate memory"); + if (NULL != key) { + free(key); + key = NULL; + } + return TTS_ERROR_OUT_OF_MEMORY; + } + } else { + key = strdup("DisableServerTTS"); + } + + if (NULL == key) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to allocate memory"); + return TTS_ERROR_OUT_OF_MEMORY; + } + + int pid = getpid(); + char* appid = NULL; + int ret = app_manager_get_app_id(pid, &appid); + if (0 != ret || NULL == appid) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get appid, ret(%d), pid(%d), appid(%s)", ret, pid, appid); + free(key); + key = NULL; + if (NULL != appid) { + free(appid); + appid = NULL; + } + return TTS_ERROR_OPERATION_FAILED; + } + + ret = tts_set_private_data(tts, key, appid); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to set private data, ret(%d), pid(%d), appid(%s)", ret, pid, appid); + free(key); + key = NULL; + free(appid); + appid = NULL; + return ret; + } + + free(appid); + appid = NULL; + free(key); + key = NULL; + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} +// LCOV_EXCL_STOP + static Eina_Bool __tts_connect_daemon(void *data) { tts_h tts = (tts_h)data; - tts_client_s* client = tts_client_get(tts); /* check handle */ @@ -245,112 +646,166 @@ static Eina_Bool __tts_connect_daemon(void *data) /* Send hello */ if (0 != tts_dbus_request_hello(client->uid)) { - if (TTS_MODE_SCREEN_READER == client->mode) { - if (false == g_is_sr_daemon_started) { - g_is_sr_daemon_started = true; - __tts_check_tts_daemon(client->mode); - } - } else if (TTS_MODE_NOTIFICATION == client->mode) { - if (false == g_is_noti_daemon_started) { - g_is_noti_daemon_started = true; - __tts_check_tts_daemon(client->mode); - } - } else { - if (false == g_is_daemon_started) { - g_is_daemon_started = true; - __tts_check_tts_daemon(client->mode); - } - } - return EINA_TRUE; } - SLOG(LOG_DEBUG, TAG_TTSC, "===== Connect daemon"); + SLOG(LOG_INFO, TAG_TTSC, "@@@ Connect daemon"); /* do request initialize */ int ret = -1; + bool credential_needed = false; - ret = tts_dbus_request_initialize(client->uid); + ret = tts_dbus_request_initialize(client->uid, &credential_needed); if (TTS_ERROR_ENGINE_NOT_FOUND == ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Engine not found"); - + 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); + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } return EINA_FALSE; - } else if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to connection"); + } 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_TIMED_OUT; + client->reason = TTS_ERROR_PERMISSION_DENIED; client->utt_id = -1; ecore_timer_add(0, __tts_notify_error, (void*)client->tts); + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } return EINA_FALSE; + + } 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 EINA_TRUE; + } 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"); } - if (0 == tts_client_get_connected_client_count()) { - SLOG(LOG_DEBUG, TAG_TTSC, "Open file msg connection"); - ret = tts_file_msg_open_connection(); - if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to open file message connection"); - ecore_timer_add(0, __tts_notify_error, (void*)client->tts); - return EINA_FALSE; - } + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } + + client = tts_client_get(tts); + /* check handle */ + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); + return EINA_FALSE; } client->before_state = client->current_state; client->current_state = TTS_STATE_READY; - ecore_timer_add(0, __tts_notify_state_changed, (void*)client->tts); - - g_connect_timer = NULL; - - SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] uid(%d)", client->uid); + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + } else { + SLOG(LOG_WARN, TAG_TTSC, "State changed callback is NULL"); + } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return EINA_FALSE; } int tts_prepare(tts_h tts) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Prepare TTS"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Prepare TTS"); tts_client_s* client = tts_client_get(tts); /* check handle */ if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not available"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } /* check state */ if (client->current_state != TTS_STATE_CREATED) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_STATE; } - g_connect_timer = ecore_timer_add(0, __tts_connect_daemon, (void*)tts); + ecore_thread_main_loop_begin(); + if (client->conn_timer) { + ecore_timer_del(client->conn_timer); + client->conn_timer = NULL; + } + client->conn_timer = ecore_timer_add(0.02, __tts_connect_daemon, (void*)tts); + ecore_thread_main_loop_end(); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_NONE; } -int tts_unprepare(tts_h tts) +//LCOV_EXCL_START +int tts_prepare_sync(tts_h tts) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Unprepare TTS"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Prepare TTS"); + + tts_client_s* client = tts_client_get(tts); + + /* check handle */ + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not available"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + /* check state */ + if (client->current_state != TTS_STATE_CREATED) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_STATE; + } + + int cnt = 0; + while (EINA_TRUE == __tts_connect_daemon((void*)tts) && TTS_CONNECTION_RETRY_COUNT > cnt) { + cnt++; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + if (TTS_CONNECTION_RETRY_COUNT == cnt) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to connect daemon"); + return TTS_ERROR_OPERATION_FAILED; + } + + return TTS_ERROR_NONE; +} +//LCOV_EXCL_STOP + +int tts_unprepare(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Unprepare TTS"); tts_client_s* client = tts_client_get(tts); @@ -362,53 +817,99 @@ int tts_unprepare(tts_h tts) /* check state */ if (client->current_state != TTS_STATE_READY) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'READY'"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'READY'"); return TTS_ERROR_INVALID_STATE; } - - int ret; - ret = tts_dbus_request_finalize(client->uid); + int ret = -1; + int count = 0; + int screen_reader = -1; + + ret = vconf_get_bool(TTS_ACCESSIBILITY_KEY, &screen_reader); if (0 != ret) { - SLOG(LOG_WARN, TAG_TTSC, "[ERROR] Fail to request finalize"); + SLOG(LOG_ERROR, tts_tag(), "[ERROR] Fail to get screen reader"); + } else { + SLOG(LOG_INFO, tts_tag(), "[INFO] Success to get screen reader(%d), g_screen_reader(%s), client->mode(%d)", screen_reader, (true == g_screen_reader) ? "True" : "False", client->mode); + g_screen_reader = (bool)screen_reader; + } + + bool is_prepared = false; + if (!(false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode)) { + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry finalize : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + break; + } + } + //LCOV_EXCL_STOP + } + } while (0 != ret); + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Do not request finalize : g_sr(%d) mode(%d)", g_screen_reader, client->mode); } - if (TTS_MODE_SCREEN_READER == client->mode) - g_is_sr_daemon_started = false; - else if (TTS_MODE_NOTIFICATION == client->mode) - g_is_noti_daemon_started = false; - else - g_is_daemon_started = false; - client->before_state = client->current_state; client->current_state = TTS_STATE_CREATED; - ecore_timer_add(0, __tts_notify_state_changed, (void*)tts); - - /* Close file message connection */ - if (0 == tts_client_get_connected_client_count()) { - SLOG(LOG_DEBUG, TAG_TTSC, "Close file msg connection"); - ret = tts_file_msg_close_connection(); - if (0 != ret) - SLOG(LOG_WARN, TAG_TTSC, "[ERROR] Fail to close file message connection"); + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_NONE; } +bool __tts_supported_voice_cb(const char* engine_id, const char* language, int type, void* user_data) +{ + tts_h tts = (tts_h)user_data; + + tts_client_s* client = tts_client_get(tts); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[WARNING] A handle is not valid"); + return false; + } + + /* call callback function */ + if (NULL != client->supported_voice_cb) { + return client->supported_voice_cb(tts, language, type, client->supported_voice_user_data); + } else { + SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of supported voice"); + } + + return false; +} + int tts_foreach_supported_voices(tts_h tts, tts_supported_voice_cb callback, void* user_data) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Foreach supported voices"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Foreach supported voices"); if (NULL == tts || NULL == callback) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } @@ -417,38 +918,52 @@ int tts_foreach_supported_voices(tts_h tts, tts_supported_voice_cb callback, voi /* check handle */ if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } - if (TTS_STATE_READY != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "Current state is NOT 'READY'."); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); - return TTS_ERROR_INVALID_STATE; + int ret = 0; + char* current_engine = NULL; + ret = tts_config_mgr_get_engine(¤t_engine); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get current engine : %d", ret); + return __tts_convert_config_error_code(ret); } - int ret = 0; - ret = tts_dbus_request_get_support_voice(client->uid, client->tts, callback, user_data); + client->supported_voice_cb = callback; + client->supported_voice_user_data = user_data; + + ret = tts_config_mgr_get_voice_list(current_engine, __tts_supported_voice_cb, client->tts); + + if (NULL != current_engine) { + free(current_engine); + current_engine = NULL; + } + + client->supported_voice_cb = NULL; + client->supported_voice_user_data = NULL; + if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %d", ret); - } + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Result : %d", ret); + ret = TTS_ERROR_OPERATION_FAILED; + } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return ret; } -int tts_get_default_voice(tts_h tts, char** lang, tts_voice_type_e* vctype) +int tts_get_default_voice(tts_h tts, char** lang, int* vctype) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Get default voice"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Get default voice"); if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } @@ -456,91 +971,763 @@ int tts_get_default_voice(tts_h tts, char** lang, tts_voice_type_e* vctype) if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + /* Request call remote method */ + int ret = 0; + ret = tts_config_mgr_get_voice(lang, vctype); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %d", ret); + return __tts_convert_config_error_code(ret); + } else { + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] Default language(%s), type(%d)", *lang, *vctype); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return ret; +} + +int tts_get_max_text_size(tts_h tts, unsigned int* size) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts || NULL == size) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get max text count : Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get max text count : A handle is not valid"); return TTS_ERROR_INVALID_PARAMETER; } if (TTS_STATE_READY != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is NOT 'READY'. "); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get max text count : Current state is NOT 'READY'."); + return TTS_ERROR_INVALID_STATE; + } + + if (0 != tts_config_mgr_get_max_text_size(size)) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get max text size"); + return TTS_ERROR_INVALID_PARAMETER; + } + + g_max_text_size = (int)*size; + + SLOG(LOG_DEBUG, TAG_TTSC, "Get max text count : %d", *size); + return TTS_ERROR_NONE; +} + +int tts_get_state(tts_h tts, tts_state_e* state) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts || NULL == state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + *state = client->current_state; + + switch (*state) { + case TTS_STATE_CREATED: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Created'"); break; + case TTS_STATE_READY: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Ready'"); break; + case TTS_STATE_PLAYING: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Playing'"); break; + case TTS_STATE_PAUSED: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Paused'"); break; + default: SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid value"); break; + } + + return TTS_ERROR_NONE; +} + +int tts_get_speed_range(tts_h tts, int* min, int* normal, int* max) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts || NULL == min || NULL == normal || NULL == max) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + *min = TTS_SPEED_MIN; + *normal = TTS_SPEED_NORMAL; + *max = TTS_SPEED_MAX; + + return TTS_ERROR_NONE; +} + +int tts_get_error_message(tts_h tts, char** err_msg) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts || NULL == err_msg) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (NULL != client->err_msg) { + *err_msg = strdup(client->err_msg); + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Error msg (%s)", *err_msg); + } else { + *err_msg = NULL; + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Error msg (NULL)"); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} + +int tts_add_text(tts_h tts, const char* text, const char* language, int voice_type, int speed, int* utt_id) +{ + SLOG(LOG_INFO, TAG_TTSC, "[DEBUG] Add text: text(%s), language(%s), type(%d)", (NULL == text) ? "NULL" : text, (NULL == language) ? "NULL" : language, voice_type); + + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (speed < 0) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Speed should not be negative(%d)", speed); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (voice_type < 0) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Voice type should not be negative(%d)", voice_type); + return TTS_ERROR_INVALID_PARAMETER; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Add text"); + + if (NULL == tts || NULL == utt_id) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'."); + return TTS_ERROR_INVALID_STATE; + } + + if (-1 == g_max_text_size) { + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] g_max_text_size is %d", g_max_text_size); + if (0 != tts_config_mgr_get_max_text_size((unsigned int*)&g_max_text_size)) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to get max text size"); + return TTS_ERROR_INVALID_PARAMETER; + } + } + + if (0 == g_max_text_size) { + if (strlen(text) <= 0) { + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] Max Text Size is %d", g_max_text_size); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input text size is invalid. (max text size is unlimited.)"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + } else { + SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] g_max_text_size is %d", g_max_text_size); + if (g_max_text_size < strlen(text) || strlen(text) <= 0) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input text size is invalid."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + } + + if (TTS_SPEED_AUTO > speed || TTS_SPEED_MAX < speed) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] speed value(%d) is invalid.", speed); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } + + if (true == client->credential_needed && NULL == client->credential) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Do not have app credential for this engine"); + return TTS_ERROR_PERMISSION_DENIED; + } + + /* check valid utf8 */ + bool valid = false; + + DBusError err; + dbus_error_init(&err); + + valid = dbus_validate_utf8(text, &err); + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Dbus Error(%s), text(%s)", err.message, text); + dbus_error_free(&err); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (valid != true) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Text is invalid - '%s'", text); + return TTS_ERROR_INVALID_PARAMETER; + } + 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_voice_type, g_speed); + + /* change default language value */ + char* temp = NULL; + + if (NULL == language) + temp = strdup("default"); + else + temp = strdup(language); + + client->current_utt_id++; + if (client->current_utt_id == 10000) { + client->current_utt_id = 1; + } + + /* do request */ + int ret = -1; + int count = 0; + bool is_prepared = false; + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry add text : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_MIN_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + break; + } + } + //LCOV_EXCL_STOP + } else { + *utt_id = client->current_utt_id; + } + } + + if (NULL != temp) { + free(temp); + temp = NULL; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return ret; +} + +//LCOV_EXCL_START +static void __tts_play_async(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"); + return; + } + + int ret = -1; + int count = 0; + bool is_prepared = false; + while (0 != ret) { + ret = tts_dbus_request_play(client->uid, client->credential); + if (0 != ret) { + if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + client->current_state = TTS_STATE_CREATED; + if (0 == tts_prepare_sync(tts)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry play : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + break; + } + } + } + } + + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to play tts : %s", __tts_get_error_code(ret)); + + client->reason = ret; + client->utt_id = -1; + + ecore_timer_add(0, __tts_notify_error, client->tts); + return; + } + + client->before_state = client->current_state; + client->current_state = TTS_STATE_PLAYING; + + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return; +} + +int tts_play_async(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Play tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_PLAYING == client->current_state || TTS_STATE_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid."); + return TTS_ERROR_INVALID_STATE; + } + + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } + + if (true == client->credential_needed && NULL == client->credential) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Do not have app credential for this engine"); + return TTS_ERROR_PERMISSION_DENIED; + } + + ecore_main_loop_thread_safe_call_async(__tts_play_async, (void*)tts); + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} +//LCOV_EXCL_STOP +int tts_play(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Play tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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, "@@@"); SLOG(LOG_DEBUG, TAG_TTSC, " "); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_PLAYING == client->current_state || TTS_STATE_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid."); return TTS_ERROR_INVALID_STATE; } - /* Request call remote method */ - int ret = 0; - ret = tts_dbus_request_get_default_voice(client->uid, lang, vctype ); - - if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %d", ret); + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } + + if (true == client->credential_needed && NULL == client->credential) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Do not have app credential for this engine"); + return TTS_ERROR_PERMISSION_DENIED; + } + + int ret = -1; + int count = 0; + bool is_prepared = false; + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry play : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } + //LCOV_EXCL_STOP + } + } + + client->before_state = client->current_state; + client->current_state = TTS_STATE_PLAYING; + + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} +//LCOV_EXCL_START +static void __tts_stop_async(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"); + return; + } + + int ret = -1; + int count = 0; + bool is_prepared = false; + while (0 != ret) { + ret = tts_dbus_request_stop(client->uid); + if (0 != ret) { + if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + client->current_state = TTS_STATE_CREATED; + if (0 == tts_prepare_sync(tts)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry stop : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + break; + } + } + } + } + + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to stop tts : %s", __tts_get_error_code(ret)); + + client->reason = ret; + client->utt_id = -1; + + ecore_timer_add(0, __tts_notify_error, client->tts); + return; + } + + client->before_state = client->current_state; + client->current_state = TTS_STATE_READY; + + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return; +} + +int tts_stop_aync(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Stop tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'."); + return TTS_ERROR_INVALID_STATE; + } + + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } + + ecore_main_loop_thread_safe_call_async(__tts_stop_async, (void*)tts); + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} +//LCOV_EXCL_STOP +int tts_stop(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Stop tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'."); + return TTS_ERROR_INVALID_STATE; + } + + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } + + int ret = -1; + int count = 0; + bool is_prepared = false; + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry stop : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } + //LCOV_EXCL_STOP + } + } + + client->before_state = client->current_state; + client->current_state = TTS_STATE_READY; + + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); } - - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); - return ret; -} + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); -int tts_get_max_text_count(tts_h tts, int* count) + return TTS_ERROR_NONE; +} +//LCOV_EXCL_START +static void __tts_pause_async(void *data) { - if (NULL == tts || NULL == count) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get max text count : Input parameter is null"); - return TTS_ERROR_INVALID_PARAMETER; - } - + 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] Get max text count : A handle is not valid"); - return TTS_ERROR_INVALID_PARAMETER; + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); + return; } - - if (TTS_STATE_READY != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get max text count : Current state is NOT 'READY'."); - return TTS_ERROR_INVALID_STATE; + + int ret = -1; + int count = 0; + bool is_prepared = false; + while (0 != ret) { + ret = tts_dbus_request_pause(client->uid); + if (0 != ret) { + if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + client->current_state = TTS_STATE_CREATED; + if (0 == tts_prepare_sync(tts)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + break; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry pause : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + break; + } + } + } } - *count = MAX_TEXT_COUNT; + if (0 != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to pause tts : %s", __tts_get_error_code(ret)); - SLOG(LOG_DEBUG, TAG_TTSC, "[Suceess] Get max text count"); - return TTS_ERROR_NONE; -} + client->reason = ret; + client->utt_id = -1; -int tts_get_state(tts_h tts, tts_state_e* state) -{ - if (NULL == tts || NULL == state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : Input parameter is null"); - return TTS_ERROR_INVALID_PARAMETER; + ecore_timer_add(0, __tts_notify_error, client->tts); + return; } - tts_client_s* client = tts_client_get(tts); + client->before_state = client->current_state; + client->current_state = TTS_STATE_PAUSED; - if (NULL == client) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid"); - return TTS_ERROR_INVALID_PARAMETER; + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); } - *state = client->current_state; - - switch(*state) { - case TTS_STATE_CREATED: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Created'"); break; - case TTS_STATE_READY: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Ready'"); break; - case TTS_STATE_PLAYING: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Playing'"); break; - case TTS_STATE_PAUSED: SLOG(LOG_DEBUG, TAG_TTSC, "Current state is 'Paused'"); break; - } + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); - return TTS_ERROR_NONE; + return; } -int tts_add_text(tts_h tts, const char* text, const char* language, tts_voice_type_e voice_type, tts_speed_e speed, int* utt_id) +int tts_pause_async(tts_h tts) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Add text"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } - if (NULL == tts || NULL == utt_id) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@ Pause tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } @@ -548,112 +1735,120 @@ int tts_add_text(tts_h tts, const char* text, const char* language, tts_voice_ty if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } - if (TTS_STATE_CREATED == client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'."); + if (TTS_STATE_PLAYING != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[Error] The Current state is NOT 'playing'. So this request should be not running."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_STATE; } - if (MAX_TEXT_COUNT < strlen(text)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input text size is too big."); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); - return TTS_ERROR_INVALID_PARAMETER; - } - - /* change default language value */ - char* temp = NULL; - - if (NULL == language) - temp = strdup("default"); - else - temp = strdup(language); - - client->current_utt_id ++; - if (client->current_utt_id == 10000) { - client->current_utt_id = 1; - } - - /* do request */ - int ret = 0; - ret = tts_dbus_request_add_text(client->uid, text, temp, voice_type, speed, client->current_utt_id); - if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %d", ret); - } else { - *utt_id = client->current_utt_id; + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; } - if (NULL != temp) - free(temp); + ecore_main_loop_thread_safe_call_async(__tts_pause_async, (void*)tts); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); - return ret; + return TTS_ERROR_NONE; } - -int tts_play(tts_h tts) +//LCOV_EXCL_STOP +int tts_pause(tts_h tts) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Play tts"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Pause tts"); if (NULL == tts) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } 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, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_PARAMETER; } - if (TTS_STATE_PLAYING == client->current_state || TTS_STATE_CREATED == client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid."); + if (TTS_STATE_PLAYING != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[Error] The Current state is NOT 'playing'. So this request should be not running."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_INVALID_STATE; - } + } - int ret = 0; - ret = tts_dbus_request_play(client->uid); - if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Request play : result(%d)", ret); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); - return ret; + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } + + int ret = -1; + int count = 0; + bool is_prepared = false; + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry pause : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } + //LCOV_EXCL_STOP + } } client->before_state = client->current_state; - client->current_state = TTS_STATE_PLAYING; + client->current_state = TTS_STATE_PAUSED; if (NULL != client->state_changed_cb) { - ecore_timer_add(0, __tts_notify_state_changed, (void*)tts); - } else { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null"); + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); return TTS_ERROR_NONE; } - -int tts_stop(tts_h tts) +int tts_set_private_data(tts_h tts, const char* key, const char* data) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Stop tts"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + 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 is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (NULL == key || NULL == data) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid parameter"); return TTS_ERROR_INVALID_PARAMETER; } @@ -661,49 +1856,68 @@ int tts_stop(tts_h tts) if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; } - if (TTS_STATE_CREATED == client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'."); + if (TTS_STATE_READY != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid state : Current state is NOT 'READY'"); return TTS_ERROR_INVALID_STATE; } - int ret = 0; - ret = tts_dbus_request_stop(client->uid); - if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %d", ret); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); - return ret; - } - - client->before_state = client->current_state; - client->current_state = TTS_STATE_READY; + if (true != client->internal && (0 == strcmp(key, "EnableServerTTS") || 0 == strcmp(key, "DisableServerTTS"))) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] This is not an internal app"); + return TTS_ERROR_INVALID_PARAMETER; + } - if (NULL != client->state_changed_cb) { - ecore_timer_add(0, __tts_notify_state_changed, (void*)tts); - } else { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null"); + int ret = -1; + int count = 0; + bool is_prepared = false; + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } + //LCOV_EXCL_STOP + } } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); - return TTS_ERROR_NONE; + return 0; } - -int tts_pause(tts_h tts) +int tts_get_private_data(tts_h tts, const char* key, char** data) { - SLOG(LOG_DEBUG, TAG_TTSC, "===== Pause tts"); + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Get private data, key(%s)", key); if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (NULL == key || NULL == data) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid parameter"); return TTS_ERROR_INVALID_PARAMETER; } @@ -711,42 +1925,54 @@ int tts_pause(tts_h tts) if (NULL == client) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid"); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); return TTS_ERROR_INVALID_PARAMETER; } - if (TTS_STATE_PLAYING != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[Error] The Current state is NOT 'playing'. So this request should be not running."); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + if (TTS_STATE_READY != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid state : Current state is NOT 'READY'"); return TTS_ERROR_INVALID_STATE; - } - - int ret = 0; - ret = tts_dbus_request_pause(client->uid); - if (0 != ret) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Request pause : result(%d)", ret); - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); - return ret; } - client->before_state = client->current_state; - client->current_state = TTS_STATE_PAUSED; + int ret = -1; + int count = 0; + bool is_prepared = false; + 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)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } + //LCOV_EXCL_STOP + } + } - if (NULL != client->state_changed_cb) { - ecore_timer_add(0, __tts_notify_state_changed, (void*)tts); - } else { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null"); + if (0 == strncmp(*data, "NULL", strlen(*data))) { + free(*data); + *data = NULL; } - SLOG(LOG_DEBUG, TAG_TTSC, "====="); - SLOG(LOG_DEBUG, TAG_TTSC, " "); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); - return TTS_ERROR_NONE; + return 0; } +//LCOV_EXCL_START static Eina_Bool __tts_notify_error(void *data) { tts_h tts = (tts_h)data; @@ -759,10 +1985,14 @@ static Eina_Bool __tts_notify_error(void *data) return EINA_FALSE; } + SLOG(LOG_DEBUG, TAG_TTSC, "Error data : uttid(%d) reason(%s)", client->utt_id, __tts_get_error_code(client->reason)); + if (NULL != client->error_cb) { SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of error"); tts_client_use_callback(client); - client->error_cb(client->tts, client->utt_id, client->reason, client->error_user_data ); + g_err_callback_status = true; + client->error_cb(client->tts, client->utt_id, client->reason, client->error_user_data); + g_err_callback_status = false; tts_client_not_use_callback(client); } else { SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of error "); @@ -771,25 +2001,85 @@ static Eina_Bool __tts_notify_error(void *data) return EINA_FALSE; } -int __tts_cb_error(int uid, tts_error_e reason, int utt_id) +int __tts_cb_error(int uid, tts_error_e reason, int utt_id, char* err_msg) { - tts_client_s* client = tts_client_get_by_uid(uid); + if (-1 == uid) { + GList* client_list = NULL; + client_list = tts_client_get_client_list(); + + GList *iter = NULL; + tts_client_s *data = NULL; + + if (g_list_length(client_list) > 0) { + /* Get a first item */ + iter = g_list_first(client_list); + + while (NULL != iter) { + data = iter->data; + + data->utt_id = utt_id; + data->reason = reason; + if (NULL != data->err_msg) { + free(data->err_msg); + data->err_msg = NULL; + } + if (NULL != err_msg) + data->err_msg = strdup(err_msg); + + /* call callback function */ + if (NULL != data->error_cb) { + ecore_timer_add(0, __tts_notify_error, data->tts); + } else { + SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of error "); + } + + if (TTS_ERROR_SERVICE_RESET == reason) { + 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"); + } + } + + /* Next item */ + iter = g_list_next(iter); + } + } + } else { + tts_client_s* client = tts_client_get_by_uid(uid); - if (NULL == client) { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] A handle is not valid"); - return TTS_ERROR_INVALID_PARAMETER; - } + if (NULL == client) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } - client->utt_id = utt_id; - client->reason = reason; + client->utt_id = utt_id; + client->reason = reason; + if (NULL != client->err_msg) { + free(client->err_msg); + client->err_msg = NULL; + } + if (NULL != err_msg) + client->err_msg = strdup(err_msg); - /* call callback function */ - if (NULL != client->error_cb) { - ecore_timer_add(0, __tts_notify_error, client->tts); - } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of error "); + /* call callback function */ + if (NULL != client->error_cb) { + ecore_timer_add(0, __tts_notify_error, client->tts); + } else { + SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of error "); + } + + if (TTS_ERROR_SERVICE_RESET == reason) { + 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"); + } + } } - + return 0; } @@ -807,9 +2097,9 @@ static Eina_Bool __tts_notify_state_changed(void *data) if (NULL != client->state_changed_cb) { tts_client_use_callback(client); - client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); tts_client_not_use_callback(client); - SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called : pre(%d) cur(%d)", client->before_state, client->current_state); } else { SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null"); } @@ -820,7 +2110,7 @@ static Eina_Bool __tts_notify_state_changed(void *data) int __tts_cb_set_state(int uid, int state) { tts_client_s* client = tts_client_get_by_uid(uid); - if( NULL == client ) { + if (NULL == client) { SLOG(LOG_WARN, TAG_TTSC, "[WARNING] The handle is not valid"); return -1; } @@ -833,7 +2123,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"); } @@ -843,30 +2137,7 @@ int __tts_cb_set_state(int uid, int state) return 0; } - -static Eina_Bool __tts_notify_utt_started(void *data) -{ - tts_h tts = (tts_h)data; - - tts_client_s* client = tts_client_get(tts); - - /* check handle */ - if (NULL == client) { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to notify utt started : A handle is not valid"); - return EINA_FALSE; - } - - if (NULL != client->utt_started_cb) { - SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance started "); - tts_client_use_callback(client); - client->utt_started_cb(client->tts, client->utt_id, client->utt_started_user_data); - tts_client_not_use_callback(client); - } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance started "); - } - - return EINA_FALSE; -} +//LCOV_EXCL_STOP int __tts_cb_utt_started(int uid, int utt_id) { @@ -877,42 +2148,21 @@ int __tts_cb_utt_started(int uid, int utt_id) return TTS_ERROR_INVALID_PARAMETER; } - SLOG(LOG_DEBUG, TAG_TTSC, "utterance started : utt id(%d) ", utt_id); + SLOG(LOG_INFO, TAG_TTSC, "utterance started : utt id(%d) ", utt_id); client->utt_id = utt_id; /* call callback function */ if (NULL != client->utt_started_cb) { - ecore_timer_add(0, __tts_notify_utt_started, client->tts); - } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance started "); - } - - return 0; -} - -static Eina_Bool __tts_notify_utt_completed(void *data) -{ - tts_h tts = (tts_h)data; - - tts_client_s* client = tts_client_get(tts); - - /* check handle */ - if (NULL == client) { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to notify utt completed : A handle is not valid"); - return EINA_FALSE; - } - - if (NULL != client->utt_completeted_cb) { - SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance completed "); + SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance started "); tts_client_use_callback(client); - client->utt_completeted_cb(client->tts, client->utt_id, client->utt_completed_user_data); + client->utt_started_cb(client->tts, client->utt_id, client->utt_started_user_data); tts_client_not_use_callback(client); } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance completed "); + SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance started "); } - return EINA_FALSE; + return 0; } int __tts_cb_utt_completed(int uid, int utt_id) @@ -924,13 +2174,16 @@ int __tts_cb_utt_completed(int uid, int utt_id) return TTS_ERROR_INVALID_PARAMETER; } - SLOG(LOG_DEBUG, TAG_TTSC, "utterance completed : uttid(%d) ", utt_id); + SLOG(LOG_INFO, TAG_TTSC, "utterance completed : uttid(%d) ", utt_id); client->utt_id = utt_id; /* call callback function */ if (NULL != client->utt_completeted_cb) { - ecore_timer_add(0, __tts_notify_utt_completed, client->tts); + SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance completed "); + tts_client_use_callback(client); + client->utt_completeted_cb(client->tts, client->utt_id, client->utt_completed_user_data); + tts_client_not_use_callback(client); } else { SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance completed "); } @@ -940,6 +2193,10 @@ int __tts_cb_utt_completed(int uid, int utt_id) int tts_set_state_changed_cb(tts_h tts, tts_state_changed_cb callback, void* user_data) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts || NULL == callback) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set state changed cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -953,20 +2210,24 @@ int tts_set_state_changed_cb(tts_h tts, tts_state_changed_cb callback, void* use } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set state changed cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set state changed cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } client->state_changed_cb = callback; client->state_changed_user_data = user_data; - SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Set state changed cb"); + SLOG(LOG_INFO, TAG_TTSC, "[SUCCESS] Set state changed cb"); return 0; } int tts_unset_state_changed_cb(tts_h tts) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset state changed cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -980,13 +2241,18 @@ int tts_unset_state_changed_cb(tts_h tts) } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset state changed cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset state changed cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } 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; @@ -994,6 +2260,10 @@ int tts_unset_state_changed_cb(tts_h tts) int tts_set_utterance_started_cb(tts_h tts, tts_utterance_started_cb callback, void* user_data) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts || NULL == callback) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set utt started cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -1007,7 +2277,7 @@ int tts_set_utterance_started_cb(tts_h tts, tts_utterance_started_cb callback, v } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set utt started cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set utt started cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } @@ -1015,12 +2285,16 @@ int tts_set_utterance_started_cb(tts_h tts, tts_utterance_started_cb callback, v client->utt_started_user_data = user_data; SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Set utt started cb"); - + return 0; } int tts_unset_utterance_started_cb(tts_h tts) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset utt started cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -1034,7 +2308,7 @@ int tts_unset_utterance_started_cb(tts_h tts) } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset utt started cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset utt started cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } @@ -1042,12 +2316,16 @@ int tts_unset_utterance_started_cb(tts_h tts) client->utt_started_user_data = NULL; SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Unset utt started cb"); - + return 0; } int tts_set_utterance_completed_cb(tts_h tts, tts_utterance_completed_cb callback, void* user_data) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts || NULL == callback) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set utt completed cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -1061,7 +2339,7 @@ int tts_set_utterance_completed_cb(tts_h tts, tts_utterance_completed_cb callbac } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set utt completed cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set utt completed cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } @@ -1069,12 +2347,16 @@ int tts_set_utterance_completed_cb(tts_h tts, tts_utterance_completed_cb callbac client->utt_completed_user_data = user_data; SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Set utt completed cb"); - + return 0; } int tts_unset_utterance_completed_cb(tts_h tts) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset utt completed cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -1088,7 +2370,7 @@ int tts_unset_utterance_completed_cb(tts_h tts) } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset utt completed cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset utt completed cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } @@ -1101,6 +2383,10 @@ int tts_unset_utterance_completed_cb(tts_h tts) int tts_set_error_cb(tts_h tts, tts_error_cb callback, void* user_data) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts || NULL == callback) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set error cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -1114,7 +2400,7 @@ int tts_set_error_cb(tts_h tts, tts_error_cb callback, void* user_data) } if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set error cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set error cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } @@ -1122,12 +2408,16 @@ int tts_set_error_cb(tts_h tts, tts_error_cb callback, void* user_data) client->error_user_data = user_data; SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Set error cb"); - + return 0; } int tts_unset_error_cb(tts_h tts) { + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + if (NULL == tts) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset error cb : Input parameter is null"); return TTS_ERROR_INVALID_PARAMETER; @@ -1139,9 +2429,9 @@ int tts_unset_error_cb(tts_h tts) SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset error cb : A handle is not valid"); return TTS_ERROR_INVALID_PARAMETER; } - + if (TTS_STATE_CREATED != client->current_state) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset error cb : Current state is not 'Created'."); + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset error cb : Current state is not 'Created'."); return TTS_ERROR_INVALID_STATE; } @@ -1153,112 +2443,433 @@ int tts_unset_error_cb(tts_h tts) return 0; } -static int __get_cmd_line(char *file, char *buf) +int tts_set_default_voice_changed_cb(tts_h tts, tts_default_voice_changed_cb callback, void* user_data) { - FILE *fp = NULL; + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } - fp = fopen(file, "r"); - if (fp == NULL) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get command line"); - return -1; + if (NULL == tts || NULL == callback) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set default voice changed cb : Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; } - memset(buf, 0, 256); - if (NULL == fgets(buf, 256, fp)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to fget command line"); - fclose(fp); - return -1; + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set default voice changed cb : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_CREATED != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set default voice changed cb : Current state is not 'Created'."); + return TTS_ERROR_INVALID_STATE; } - fclose(fp); + + client->default_voice_changed_cb = callback; + client->default_voice_changed_user_data = user_data; + + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Set default voice changed cb"); return 0; } -static bool __tts_is_alive(char* daemon_path) +int tts_unset_default_voice_changed_cb(tts_h tts) { - DIR *dir; - struct dirent *entry; - struct stat filestat; - - int pid; - char cmdLine[256] = {'\0',}; - char tempPath[256] = {'\0',}; - - dir = opendir("/proc"); - if (NULL == dir) { - SLOG(LOG_ERROR, TAG_TTSC, "process checking is FAILED"); - return FALSE; - } - - while ((entry = readdir(dir)) != NULL) { - if (0 != lstat(entry->d_name, &filestat)) { - continue; - } + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset default voice changed cb : Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset default voice changed cb : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_CREATED != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset default voice changed cb : Current state is not 'Created'."); + return TTS_ERROR_INVALID_STATE; + } + + client->default_voice_changed_cb = NULL; + client->default_voice_changed_user_data = NULL; + + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Unset default voice changed cb"); + + return 0; +} + +int tts_set_engine_changed_cb(tts_h tts, tts_engine_changed_cb callback, void* user_data) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts || NULL == callback) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set engine changed cb : Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set engine changed cb : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_CREATED != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set engine changed cb : Current state is not 'Created'."); + return TTS_ERROR_INVALID_STATE; + } + + client->engine_changed_cb = callback; + client->engine_changed_user_data = user_data; + + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Set engine changed cb"); + + return 0; +} + +int tts_unset_engine_changed_cb(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset engine changed cb : Input parameter is null"); + return TTS_ERROR_INVALID_PARAMETER; + } + + tts_client_s* client = tts_client_get(tts); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset engine changed cb : A handle is not valid"); + return TTS_ERROR_INVALID_PARAMETER; + } + + if (TTS_STATE_CREATED != client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset engine changed cb : Current state is not 'Created'."); + return TTS_ERROR_INVALID_STATE; + } + + client->engine_changed_cb = NULL; + client->engine_changed_user_data = NULL; + + SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Unset engine changed cb"); + + 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()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Add pcm tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid."); + return TTS_ERROR_INVALID_STATE; + } + + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } - if (!S_ISDIR(filestat.st_mode)) { - continue; + int ret = -1; + int count = 0; + bool is_prepared = false; + while (0 != ret) { + ret = tts_dbus_request_add_pcm(client->uid, event, data, data_size, audio_type, rate); + if (0 != ret) { + if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + client->current_state = TTS_STATE_CREATED; + if (0 == tts_prepare_sync(tts)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry add pcm : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } } + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} + +int tts_play_pcm(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Play pcm tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_PLAYING == client->current_state || TTS_STATE_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid."); + return TTS_ERROR_INVALID_STATE; + } - pid = atoi(entry->d_name); - if (pid <= 0) continue; + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } - sprintf(tempPath, "/proc/%d/cmdline", pid); - if (0 != __get_cmd_line(tempPath, cmdLine)) { - continue; + int ret = -1; + int count = 0; + bool is_prepared = false; + while (0 != ret) { + ret = tts_dbus_request_play_pcm(client->uid); + if (0 != ret) { + if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + client->current_state = TTS_STATE_CREATED; + if (0 == tts_prepare_sync(tts)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry play pcm : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } } + } + + client->before_state = client->current_state; + client->current_state = TTS_STATE_PLAYING; + + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + + return TTS_ERROR_NONE; +} + +int tts_stop_pcm(tts_h tts) +{ + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_INFO, TAG_TTSC, "@@@ Stop pcm tts"); + + if (NULL == tts) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; + } + + 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_CREATED == client->current_state) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] The current state is invalid."); + return TTS_ERROR_INVALID_STATE; + } + + if (false == g_screen_reader && TTS_MODE_SCREEN_READER == client->mode) { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Screen reader option is NOT available. Ignore this request"); + return TTS_ERROR_INVALID_STATE; + } - if (0 == strncmp(cmdLine, daemon_path, strlen(daemon_path))) { - SLOG(LOG_DEBUG, TAG_TTSC, "%s is ALIVE !!", daemon_path); - closedir(dir); - return TRUE; + int ret = -1; + int count = 0; + bool is_prepared = false; + while (0 != ret) { + ret = tts_dbus_request_stop_pcm(client->uid); + if (0 != ret) { + if (TTS_ERROR_INVALID_PARAMETER == ret && false == is_prepared) { + client->current_state = TTS_STATE_CREATED; + if (0 == tts_prepare_sync(tts)) { + is_prepared = true; + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Success tts_prepare_sync"); + } + } else if (TTS_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret)); + return ret; + } else { + SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry stop pcm : %s", __tts_get_error_code(ret)); + usleep(10000); + count++; + if (TTS_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request"); + return ret; + } + } } } - SLOG(LOG_DEBUG, TAG_TTSC, "THERE IS NO %s !!", daemon_path); + client->before_state = client->current_state; + client->current_state = TTS_STATE_READY; + + if (NULL != client->state_changed_cb) { + tts_client_use_callback(client); + client->state_changed_cb(client->tts, client->before_state, client->current_state, client->state_changed_user_data); + tts_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called"); + } + + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); - closedir(dir); - return FALSE; + return TTS_ERROR_NONE; } +//LCOV_EXCL_STOP -static int __tts_check_tts_daemon(tts_mode_e mode) +int tts_repeat(tts_h tts, char** text_repeat, int* utt_id) { - char daemon_path[64] = {'\0',}; - int pid, i; - - if (TTS_MODE_DEFAULT == mode) { - strcpy(daemon_path, "/usr/bin/tts-daemon"); - } else if (TTS_MODE_NOTIFICATION == mode) { - strcpy(daemon_path, "/usr/bin/tts-daemon-noti"); - } else if (TTS_MODE_SCREEN_READER == mode) { - strcpy(daemon_path, "/usr/bin/tts-daemon-sr"); - } else { - SLOG(LOG_ERROR, TAG_TTSC, "mode is not valid"); - return -1; + if (0 != __tts_get_feature_enabled()) { + return TTS_ERROR_NOT_SUPPORTED; } - if (TRUE == __tts_is_alive(daemon_path)) { - return 0; + 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; } - - /* fork-exec daemom */ - pid = fork(); - switch(pid) { - case -1: - SLOG(LOG_ERROR, TAG_TTSC, "Fail to create daemon"); - break; + 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; + } - case 0: - setsid(); - for (i = 0;i < _NSIG;i++) - signal(i, SIG_DFL); + *text_repeat = NULL; + *utt_id = -1; - execl(daemon_path, daemon_path, NULL); - break; + tts_client_s* client = tts_client_get(tts); - default: - break; + if (NULL == client) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid."); + SLOG(LOG_DEBUG, TAG_TTSC, "@@@"); + return TTS_ERROR_INVALID_PARAMETER; } - return 0; + 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, *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; }