Merge "Support download engine language" into tizen
[platform/core/uifw/tts.git] / client / tts.c
index 0702e2b..19684fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-*  Copyright (c) 2011-2014 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
@@ -15,7 +15,7 @@
 #include <Ecore.h>
 #include <iconv.h>
 #include <sys/stat.h>
-#include <sys/types.h> 
+#include <sys/types.h>
 #include <sys/wait.h>
 #include <system_info.h>
 #include <vconf.h>
 #include "tts_main.h"
 
 
-static bool g_is_daemon_started = false;
-
-static bool g_is_noti_daemon_started = false;
-
-static bool g_is_sr_daemon_started = false;
+static bool g_screen_reader;
 
-static Ecore_Timer* g_connect_timer = NULL;
+static int g_feature_enabled = -1;
 
-static bool g_screen_reader;
+static bool g_err_callback_status = false;
 
 /* Function definition */
 static Eina_Bool __tts_notify_state_changed(void *data);
@@ -46,9 +42,33 @@ 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) {
+       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";
@@ -62,6 +82,8 @@ static const char* __tts_get_error_code(tts_error_e err)
        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";
        }
@@ -78,14 +100,14 @@ static int __tts_convert_config_error_code(tts_config_error_e code)
        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_OPERATION_FAILED;
+       if (code == TTS_CONFIG_ERROR_NOT_SUPPORTED_FEATURE)     return TTS_ERROR_NOT_SUPPORTED_FEATURE;
 
        return code;
 }
 
 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)
 {
-       SECURE_SLOG(LOG_DEBUG, TAG_TTSC, "Voice changed : Before lang(%s) type(%d) , Current lang(%s), type(%d)", 
+       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;
@@ -101,7 +123,7 @@ void __tts_config_voice_changed_cb(const char* before_lang, int before_voice_typ
                while (NULL != iter) {
                        data = iter->data;
                        if (NULL != data->default_voice_changed_cb) {
-                               SECURE_SLOG(LOG_DEBUG, TAG_TTSC, "Call default voice changed callback : uid(%d)", data->uid);
+                               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);
                        }
@@ -111,21 +133,17 @@ void __tts_config_voice_changed_cb(const char* before_lang, int before_voice_typ
                }
        }
 
-       return; 
+       return;
 }
 
 int tts_create(tts_h* tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Create TTS");
-       
+
        /* check param */
        if (NULL == tts) {
                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null");
@@ -137,16 +155,12 @@ int tts_create(tts_h* tts)
        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;
        }
 
@@ -170,10 +184,6 @@ int tts_create(tts_h* tts)
                return __tts_convert_config_error_code(ret);
        }
 
-       g_is_daemon_started = false;
-       g_is_noti_daemon_started = false;
-       g_is_sr_daemon_started = false;
-
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
 
@@ -182,20 +192,14 @@ int tts_create(tts_h* tts)
 
 int tts_destroy(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, 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;
        }
 
@@ -204,8 +208,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;
        }
 
@@ -234,9 +236,9 @@ int tts_destroy(tts_h tts)
                                                break;
                                        } else {
                                                SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry finalize");
-                                               usleep(10);
+                                               usleep(10000);
                                                count++;
-                                               if (10 == count) {
+                                               if (TTS_RETRY_COUNT == count) {
                                                        SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request");
                                                        break;
                                                }
@@ -247,27 +249,14 @@ int tts_destroy(tts_h tts)
                        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;
-
-               if (0 == tts_client_get_mode_client_count(client->mode)) {
-                       SLOG(LOG_DEBUG, TAG_TTSC, "Close file msg connection : mode(%d)", client->mode);
-                       ret = tts_file_msg_close_connection(client->mode);
-                       if (0 != ret)
-                               SLOG(LOG_WARN, TAG_TTSC, "[ERROR] Fail to close file message connection");
-               }
-
                client->before_state = client->current_state;
                client->current_state = TTS_STATE_CREATED;
 
        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;
                }
                /* Free resources */
                tts_client_destroy(tts);
@@ -276,13 +265,15 @@ int tts_destroy(tts_h tts)
        default:
                break;
        }
+
        if (0 == tts_client_get_size()) {
                if (0 != tts_dbus_close_connection()) {
                        SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to close connection");
                }
        }
 
+       tts = NULL;
+
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
 
@@ -296,12 +287,8 @@ void __tts_screen_reader_changed_cb(bool value)
 
 int tts_set_mode(tts_h tts, tts_mode_e mode)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Set TTS mode");
@@ -318,7 +305,7 @@ int tts_set_mode(tts_h tts, tts_mode_e mode)
 
        /* check state */
        if (client->current_state != TTS_STATE_CREATED) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); 
+               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;
@@ -355,12 +342,8 @@ int tts_set_mode(tts_h tts, tts_mode_e mode)
 
 int tts_get_mode(tts_h tts, tts_mode_e* mode)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Get TTS mode");
@@ -377,7 +360,7 @@ int tts_get_mode(tts_h tts, tts_mode_e* mode)
 
        /* check state */
        if (client->current_state != TTS_STATE_CREATED) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); 
+               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;
@@ -385,59 +368,46 @@ int tts_get_mode(tts_h tts, tts_mode_e* mode)
 
        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, " ");
 
        return TTS_ERROR_NONE;
 }
 
-static void* __fork_tts_daemon(void* data)
+int tts_set_credential(tts_h tts, const char* credential)
 {
-       char daemon_path[64] = {'\0',};
-       int pid, i;
-       tts_mode_e mode;
-
-       mode = (tts_mode_e)data;
-
-       if (TTS_MODE_DEFAULT == mode) {
-               snprintf(daemon_path, 64, "%s", "/usr/bin/tts-daemon");
-       } else if (TTS_MODE_NOTIFICATION == mode) {
-               snprintf(daemon_path, 64, "%s", "/usr/bin/tts-daemon-noti");
-       } else if (TTS_MODE_SCREEN_READER == mode) {
-               snprintf(daemon_path, 64, "%s", "/usr/bin/tts-daemon-sr");
-       } else {
-               SLOG(LOG_ERROR, TAG_TTSC, "mode is not valid");
-               return (void*)-1;
+       if(0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
-       
-       /* fork-exec daemom */
-       pid = fork();
 
-       switch(pid) {
-       case -1:
-               SLOG(LOG_ERROR, TAG_TTSC, "Fail to create daemon");
-               break;
+       if (NULL == tts || NULL == credential) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input parameter is null");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
 
-       case 0:
-               setsid();
-               for (i = 0;i < _NSIG;i++)
-                       signal(i, SIG_DFL);
+       tts_client_s* client = tts_client_get(tts);
 
-               execl(daemon_path, daemon_path, NULL);
-               break;
+       if (NULL == client) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get state : A handle is not valid");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
 
-       default:
-               break;
+       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;
        }
 
-       return (void*) 1;
+       client->credential = strdup(credential);
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+       SLOG(LOG_DEBUG, TAG_TTSC, " ");
+
+       return TTS_ERROR_NONE;
 }
 
 static Eina_Bool __tts_connect_daemon(void *data)
@@ -448,50 +418,11 @@ static Eina_Bool __tts_connect_daemon(void *data)
        /* check handle */
        if (NULL == client) {
                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid");
-               g_connect_timer = NULL;
                return EINA_FALSE;
        }
 
        /* Send hello */
        if (0 != tts_dbus_request_hello(client->uid)) {
-               pthread_t thread;
-               int thread_id;
-
-               if (TTS_MODE_SCREEN_READER == client->mode) {
-                       if (false == g_is_sr_daemon_started) {
-                               g_is_sr_daemon_started = true;
-                               thread_id = pthread_create(&thread, NULL, __fork_tts_daemon, (void*)TTS_MODE_SCREEN_READER);
-                               if (thread_id < 0) {
-                                       SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to make thread");
-                                       g_connect_timer = NULL;
-                                       return EINA_FALSE;
-                               }
-                               pthread_detach(thread);
-                       }
-               } else if (TTS_MODE_NOTIFICATION == client->mode) {
-                       if (false == g_is_noti_daemon_started) {
-                               g_is_noti_daemon_started = true;
-                               thread_id = pthread_create(&thread, NULL, __fork_tts_daemon, (void*)TTS_MODE_NOTIFICATION);
-                               if (thread_id < 0) {
-                                       SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to make thread");
-                                       g_connect_timer = NULL;
-                                       return EINA_FALSE;
-                               }
-                               pthread_detach(thread);
-                       }
-               } else {
-                       if (false == g_is_daemon_started) {
-                               g_is_daemon_started = true;
-                               thread_id = pthread_create(&thread, NULL, __fork_tts_daemon, (void*)TTS_MODE_DEFAULT);
-                               if (thread_id < 0) {
-                                       SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to make thread");
-                                       g_connect_timer = NULL;
-                                       return EINA_FALSE;
-                               }
-                               pthread_detach(thread);
-                       }
-               }
-               
                return EINA_TRUE;
        }
 
@@ -499,16 +430,18 @@ static Eina_Bool __tts_connect_daemon(void *data)
 
        /* do request initialize */
        int ret = -1;
-       ret = tts_dbus_request_initialize(client->uid);
+       bool credential_needed = false;
+
+       ret = tts_dbus_request_initialize(client->uid, &credential_needed);
 
        if (TTS_ERROR_ENGINE_NOT_FOUND == ret) {
                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to initialize : %s", __tts_get_error_code(ret));
-               
+
                client->reason = TTS_ERROR_ENGINE_NOT_FOUND;
                client->utt_id = -1;
 
                ecore_timer_add(0, __tts_notify_error, (void*)client->tts);
-               g_connect_timer = NULL;
+               client->conn_timer = NULL;
                return EINA_FALSE;
 
        } else if (TTS_ERROR_NONE != ret) {
@@ -517,19 +450,11 @@ static Eina_Bool __tts_connect_daemon(void *data)
 
        } 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");
        }
 
-       g_connect_timer = NULL;
-
-       if (0 == tts_client_get_mode_client_count(client->mode)) {
-               SLOG(LOG_DEBUG, TAG_TTSC, "Open file msg connection : mode(%d)", client->mode);
-               ret = tts_file_msg_open_connection(client->mode);
-               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;
-               }
-       }
+       client->conn_timer = NULL;
 
        client = tts_client_get(tts);
        /* check handle */
@@ -543,7 +468,7 @@ static Eina_Bool __tts_connect_daemon(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);
        } else {
                SLOG(LOG_WARN, TAG_TTSC, "State changed callback is NULL");
@@ -557,12 +482,8 @@ static Eina_Bool __tts_connect_daemon(void *data)
 
 int tts_prepare(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Prepare TTS");
@@ -579,13 +500,13 @@ int tts_prepare(tts_h tts)
 
        /* check state */
        if (client->current_state != TTS_STATE_CREATED) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid State: Current state is not 'CREATED'"); 
+               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;
        }
 
-       g_connect_timer = ecore_timer_add(0, __tts_connect_daemon, (void*)tts);
+       client->conn_timer = ecore_timer_add(0, __tts_connect_daemon, (void*)tts);
 
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
@@ -595,12 +516,8 @@ int tts_prepare(tts_h tts)
 
 int tts_unprepare(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Unprepare TTS");
@@ -615,9 +532,7 @@ 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;
        }
 
@@ -632,9 +547,9 @@ int tts_unprepare(tts_h tts)
                                        break;
                                } else {
                                        SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry finalize : %s", __tts_get_error_code(ret));
-                                       usleep(10);
+                                       usleep(10000);
                                        count++;
-                                       if (10 == count) {
+                                       if (TTS_RETRY_COUNT == count) {
                                                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request");
                                                break;
                                        }
@@ -645,31 +560,16 @@ int tts_unprepare(tts_h tts)
                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;
 
        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");
        }
 
-       /* Close file message connection */
-       if (0 == tts_client_get_mode_client_count(client->mode)) {
-               SLOG(LOG_DEBUG, TAG_TTSC, "Close file msg connection : mode(%d)", client->mode);
-               ret = tts_file_msg_close_connection(client->mode);
-               if (0 != ret)
-                       SLOG(LOG_WARN, TAG_TTSC, "[ERROR] Fail to close file message connection");
-       }
-
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
 
@@ -698,12 +598,8 @@ bool __tts_supported_voice_cb(const char* engine_id, const char* language, int t
 
 int tts_foreach_supported_voices(tts_h tts, tts_supported_voice_cb callback, void* user_data)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Foreach supported voices");
@@ -747,7 +643,7 @@ int tts_foreach_supported_voices(tts_h tts, tts_supported_voice_cb callback, voi
        if (0 != 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, " ");
@@ -757,12 +653,8 @@ int tts_foreach_supported_voices(tts_h tts, tts_supported_voice_cb callback, voi
 
 int tts_get_default_voice(tts_h tts, char** lang, int* vctype)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        SLOG(LOG_DEBUG, TAG_TTSC, "===== Get default voice");
@@ -786,13 +678,13 @@ int tts_get_default_voice(tts_h tts, char** lang, int* vctype)
        /* Request call remote method */
        int ret = 0;
        ret = tts_config_mgr_get_voice(lang, vctype);
-       if (0 != ret) {
+       if (0 != ret) {
                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %d", ret);
                return __tts_convert_config_error_code(ret);
        } else {
-               SECURE_SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] Default language(%s), type(%d)", *lang, *vctype);
+               SLOG(LOG_DEBUG, TAG_TTSC, "[DEBUG] Default language(%s), type(%d)", *lang, *vctype);
        }
-       
+
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
 
@@ -801,12 +693,8 @@ int tts_get_default_voice(tts_h tts, char** lang, int* vctype)
 
 int tts_get_max_text_size(tts_h tts, unsigned int* size)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == size) {
@@ -820,9 +708,9 @@ int tts_get_max_text_size(tts_h tts, unsigned int* size)
                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] Get max text count : Current state is NOT 'READY'."); 
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Get max text count : Current state is NOT 'READY'.");
                return TTS_ERROR_INVALID_STATE;
        }
 
@@ -834,12 +722,8 @@ int tts_get_max_text_size(tts_h tts, unsigned int* size)
 
 int tts_get_state(tts_h tts, tts_state_e* state)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == state) {
@@ -856,12 +740,12 @@ int tts_get_state(tts_h tts, tts_state_e* state)
 
        *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;
+       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;
@@ -869,12 +753,8 @@ int tts_get_state(tts_h tts, tts_state_e* state)
 
 int tts_get_speed_range(tts_h tts, int* min, int* normal, int* max)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == min || NULL == normal || NULL == max) {
@@ -896,14 +776,51 @@ int tts_get_speed_range(tts_h tts, int* min, int* normal, int* 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 {
+               SLOG(LOG_DEBUG, TAG_TTSC, "[SUCCESS] Error msg (NULL)");
+       }
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+       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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       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");
@@ -925,12 +842,19 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty
        }
 
        if (TTS_STATE_CREATED == client->current_state) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'."); 
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Current state is 'CREATED'.");
                return TTS_ERROR_INVALID_STATE;
        }
 
-       if (TTS_MAX_TEXT_SIZE < strlen(text)) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input text size is too big.");
+       if (TTS_MAX_TEXT_SIZE < strlen(text) || strlen(text) <= 0) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input text size is invalid.");
+               SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+               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, "=====");
                SLOG(LOG_DEBUG, TAG_TTSC, " ");
                return TTS_ERROR_INVALID_PARAMETER;
@@ -941,6 +865,11 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty
                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 */
        iconv_t *ict;
        ict = iconv_open("utf-8", "");
@@ -971,17 +900,17 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty
                return TTS_ERROR_INVALID_PARAMETER;
        }
        iconv_close(ict);
-       SECURE_SLOG(LOG_DEBUG, TAG_TTSC, "Text is valid - Converted text is '%s'", out_buf);
+       SLOG(LOG_DEBUG, TAG_TTSC, "Text is valid - Converted text is '%s'", out_buf);
 
        /* change default language value */
        char* temp = NULL;
 
        if (NULL == language)
                temp = strdup("default");
-       else 
+       else
                temp = strdup(language);
 
-       client->current_utt_id ++;
+       client->current_utt_id++;
        if (client->current_utt_id == 10000) {
                client->current_utt_id = 1;
        }
@@ -990,16 +919,16 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty
        int ret = -1;
        int count = 0;
        while (0 != ret) {
-               ret = tts_dbus_request_add_text(client->uid, out_buf, temp, voice_type, speed, client->current_utt_id);
+               ret = tts_dbus_request_add_text(client->uid, out_buf, temp, voice_type, speed, client->current_utt_id, client->credential);
                if (0 != ret) {
                        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(10);
+                               usleep(10000);
                                count++;
-                               if (10 == count) {
+                               if (TTS_RETRY_COUNT == count) {
                                        SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request");
                                        break;
                                }
@@ -1017,70 +946,53 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty
        return ret;
 }
 
-int tts_play(tts_h tts)
+static void __tts_play_async(void *data)
 {
-       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 NOT supported");
-                       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, "=====");
-               SLOG(LOG_DEBUG, TAG_TTSC, " ");
-               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] 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;
-       }
-
-       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;
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid");
+               return;
        }
 
        int ret = -1;
        int count = 0;
        while (0 != ret) {
-               ret = tts_dbus_request_play(client->uid);
+               ret = tts_dbus_request_play(client->uid, client->credential);
                if (0 != ret) {
                        if (TTS_ERROR_TIMED_OUT != ret) {
                                SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] result : %s", __tts_get_error_code(ret));
-                               return ret;
+                               break;
                        } else {
                                SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry play : %s", __tts_get_error_code(ret));
-                               usleep(10);
+                               usleep(10000);
                                count++;
-                               if (10 == count) {
+                               if (TTS_RETRY_COUNT == count) {
                                        SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request");
-                                       return ret;
+                                       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); 
+               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");
        }
@@ -1088,24 +1000,19 @@ int tts_play(tts_h tts)
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
 
-       return TTS_ERROR_NONE;
+       return;
 }
 
-
-int tts_stop(tts_h tts)
+int tts_play_async(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
-       SLOG(LOG_DEBUG, TAG_TTSC, "===== Stop tts");
+       SLOG(LOG_DEBUG, TAG_TTSC, "===== Play tts");
 
        if (NULL == tts) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null");
+               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;
@@ -1114,14 +1021,14 @@ int tts_stop(tts_h tts)
        tts_client_s* client = tts_client_get(tts);
 
        if (NULL == client) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid");
+               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_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;
        }
 
@@ -1130,35 +1037,12 @@ int tts_stop(tts_h tts)
                return TTS_ERROR_INVALID_STATE;
        }
 
-       int ret = -1;
-       int count = 0;
-       while (0 != ret) {
-               ret = tts_dbus_request_stop(client->uid);
-               if (0 != ret) {
-                       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(10);
-                               count++;
-                               if (10 == count) {
-                                       SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to request");
-                                       return ret;
-                               }
-                       }
-               }
+       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;
        }
 
-       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");
-       }
+       ecore_main_loop_thread_safe_call_async(__tts_play_async, (void*)tts);
 
        SLOG(LOG_DEBUG, TAG_TTSC, "=====");
        SLOG(LOG_DEBUG, TAG_TTSC, " ");
@@ -1166,21 +1050,16 @@ int tts_stop(tts_h tts)
        return TTS_ERROR_NONE;
 }
 
-
-int tts_pause(tts_h tts)
+int tts_play(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
-       SLOG(LOG_DEBUG, TAG_TTSC, "===== Pause tts");
+       SLOG(LOG_DEBUG, TAG_TTSC, "===== Play tts");
 
        if (NULL == tts) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null");
+               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;
@@ -1189,16 +1068,14 @@ int tts_pause(tts_h tts)
        tts_client_s* client = tts_client_get(tts);
 
        if (NULL == client) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid");
+               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_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;
        }
 
@@ -1207,32 +1084,37 @@ int tts_pause(tts_h tts)
                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;
        while (0 != ret) {
-               ret = tts_dbus_request_pause(client->uid);
+               ret = tts_dbus_request_play(client->uid, client->credential);
                if (0 != ret) {
                        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(10);
+                               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] retry play : %s", __tts_get_error_code(ret));
+                               usleep(10000);
                                count++;
-                               if (10 == 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_PAUSED;
+       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); 
+               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");
        }
@@ -1243,106 +1125,461 @@ int tts_pause(tts_h tts)
        return TTS_ERROR_NONE;
 }
 
-static Eina_Bool __tts_notify_error(void *data)
+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_WARN, TAG_TTSC, "Fail to notify error msg : A handle is not valid");
-               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 );
-               tts_client_not_use_callback(client);
-       } else {
-               SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of error ");
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] A handle is not valid");
+               return;
        }
 
-       return EINA_FALSE;
-}
-
-int __tts_cb_error(int uid, tts_error_e reason, int utt_id)
-{
-       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;
+       int ret = -1;
+       int count = 0;
+       while (0 != ret) {
+               ret = tts_dbus_request_stop(client->uid);
+               if (0 != ret) {
+                       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;
+                               }
+                       }
+               }
        }
 
-       client->utt_id = utt_id;
-       client->reason = reason;
+       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;
 
-       /* 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 ");
+               return;
        }
-       
-       return 0;
+
+       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;
 }
 
-static Eina_Bool __tts_notify_state_changed(void *data)
+int tts_stop_aync(tts_h tts)
 {
-       tts_h tts = (tts_h)data;
+       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, "=====");
+               SLOG(LOG_DEBUG, TAG_TTSC, " ");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
 
        tts_client_s* client = tts_client_get(tts);
 
-       /* check handle */
        if (NULL == client) {
-               SLOG(LOG_WARN, TAG_TTSC, "Fail to notify state changed : A handle is not valid");
-               return EINA_FALSE;
+               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'.");
+               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, "=====");
+       SLOG(LOG_DEBUG, TAG_TTSC, " ");
+
+       return TTS_ERROR_NONE;
+}
+
+int tts_stop(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, "=====");
+               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_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;
+       while (0 != ret) {
+               ret = tts_dbus_request_stop(client->uid);
+               if (0 != ret) {
+                       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;
+                               }
+                       }
+               }
        }
 
+       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); 
+               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 : pre(%d) cur(%d)", client->before_state, client->current_state);
-       } else {
-               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null");
+               SLOG(LOG_DEBUG, TAG_TTSC, "State changed callback is called");
        }
 
-       return EINA_FALSE;
+       SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+       SLOG(LOG_DEBUG, TAG_TTSC, " ");
+
+       return TTS_ERROR_NONE;
 }
 
-int __tts_cb_set_state(int uid, int state)
+static void __tts_pause_async(void *data)
 {
-       tts_client_s* client = tts_client_get_by_uid(uid);
-       if( NULL == client ) {
-               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] The handle is not valid");
-               return -1;
+       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;
        }
 
-       tts_state_e state_from_daemon = (tts_state_e)state;
+       int ret = -1;
+       int count = 0;
+       while (0 != ret) {
+               ret = tts_dbus_request_pause(client->uid);
+               if (0 != ret) {
+                       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;
+                               }
+                       }
+               }
+       }
 
-       if (client->current_state == state_from_daemon) {
-               SLOG(LOG_DEBUG, TAG_TTSC, "Current state has already been %d", client->current_state);
-               return 0;
+       if (0 != ret) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to pause 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_PAUSED;
+
        if (NULL != client->state_changed_cb) {
-               ecore_timer_add(0, __tts_notify_state_changed, client->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, " ");
+
+       return;
+}
+
+int tts_pause_async(tts_h tts)
+{
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
+       }
+
+       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, "=====");
+               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) {
+               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, " ");
+               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_pause_async, (void*)tts);
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+       SLOG(LOG_DEBUG, TAG_TTSC, " ");
+
+       return TTS_ERROR_NONE;
+}
+
+int tts_pause(tts_h tts)
+{
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
+       }
+
+       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, "=====");
+               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) {
+               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, " ");
+               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;
+       while (0 != ret) {
+               ret = tts_dbus_request_pause(client->uid);
+               if (0 != ret) {
+                       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;
+                               }
+                       }
+               }
        }
 
        client->before_state = client->current_state;
-       client->current_state = state_from_daemon;
+       client->current_state = TTS_STATE_PAUSED;
+
+       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 TTS_ERROR_NONE;
+}
+
+int tts_set_private_data(tts_h tts, const char* key, const char* data)
+{
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
+       }
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "===== Set private data");
+
+       if (NULL == tts) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
+
+       if (NULL == key || NULL == data) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid parameter");
+               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");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
+
+       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 = -1;
+       int count = 0;
+       while (0 != ret) {
+               ret = tts_dbus_request_set_private_data(client->uid, key, data);
+               if (0 != ret) {
+                       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;
+                               }
+                       }
+               }
+       }
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+       SLOG(LOG_DEBUG, TAG_TTSC, "");
+
+       return 0;
+}
+
+int tts_get_private_data(tts_h tts, const char* key, char** data)
+{
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
+       }
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "===== Get private data");
+
+       if (NULL == tts) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input handle is null");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
+
+       if (NULL == key || NULL == data) {
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Invalid parameter");
+               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");
+               return TTS_ERROR_INVALID_PARAMETER;
+       }
+
+       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 = -1;
+       int count = 0;
+       while (0 != ret) {
+               ret = tts_dbus_request_get_private_data(client->uid, key, data);
+               if (0 != ret) {
+                       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;
+                               }
+                       }
+               }
+       }
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "=====");
+       SLOG(LOG_DEBUG, TAG_TTSC, "");
 
        return 0;
 }
 
-static Eina_Bool __tts_notify_utt_started(void *data)
+static Eina_Bool __tts_notify_error(void *data)
 {
        tts_h tts = (tts_h)data;
 
@@ -1350,23 +1587,27 @@ static Eina_Bool __tts_notify_utt_started(void *data)
 
        /* check handle */
        if (NULL == client) {
-               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to notify utt started : A handle is not valid");
+               SLOG(LOG_WARN, TAG_TTSC, "Fail to notify error msg : 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 ");
+
+       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->utt_started_cb(client->tts, client->utt_id, client->utt_started_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 utterance started ");
+               SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of error ");
        }
 
        return EINA_FALSE;
 }
 
-int __tts_cb_utt_started(int uid, 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);
 
@@ -1375,21 +1616,34 @@ int __tts_cb_utt_started(int uid, int utt_id)
                return TTS_ERROR_INVALID_PARAMETER;
        }
 
-       SECURE_SLOG(LOG_DEBUG, TAG_TTSC, "utterance started : utt id(%d) ", utt_id);
-
        client->utt_id = utt_id;
+       client->reason = reason;
+       if (NULL != client->err_msg) {
+               free(client->err_msg);
+               client->err_msg = NULL;
+       }
+       client->err_msg = strdup(err_msg);
 
        /* call callback function */
-       if (NULL != client->utt_started_cb) {
-               ecore_timer_add(0, __tts_notify_utt_started, client->tts);
+       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 utterance started ");
+               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;
 }
 
-static Eina_Bool __tts_notify_utt_completed(void *data)
+static Eina_Bool __tts_notify_state_changed(void *data)
 {
        tts_h tts = (tts_h)data;
 
@@ -1397,22 +1651,75 @@ static Eina_Bool __tts_notify_utt_completed(void *data)
 
        /* check handle */
        if (NULL == client) {
-               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to notify utt completed : A handle is not valid");
+               SLOG(LOG_WARN, TAG_TTSC, "Fail to notify state changed : 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 ");
+       if (NULL != client->state_changed_cb) {
                tts_client_use_callback(client);
-               client->utt_completeted_cb(client->tts, client->utt_id, client->utt_completed_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 : pre(%d) cur(%d)", client->before_state, client->current_state);
        } else {
-               SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance completed ");
+               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null");
        }
 
        return EINA_FALSE;
 }
 
+int __tts_cb_set_state(int uid, int state)
+{
+       tts_client_s* client = tts_client_get_by_uid(uid);
+       if (NULL == client) {
+               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] The handle is not valid");
+               return -1;
+       }
+
+       tts_state_e state_from_daemon = (tts_state_e)state;
+
+       if (client->current_state == state_from_daemon) {
+               SLOG(LOG_DEBUG, TAG_TTSC, "Current state has already been %d", client->current_state);
+               return 0;
+       }
+
+       if (NULL != client->state_changed_cb) {
+               ecore_timer_add(0, __tts_notify_state_changed, client->tts);
+       } else {
+               SLOG(LOG_WARN, TAG_TTSC, "[WARNING] State changed callback is null");
+       }
+
+       client->before_state = client->current_state;
+       client->current_state = state_from_daemon;
+
+       return 0;
+}
+
+int __tts_cb_utt_started(int uid, int utt_id)
+{
+       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;
+       }
+
+       SLOG(LOG_DEBUG, TAG_TTSC, "utterance started : utt id(%d) ", utt_id);
+
+       client->utt_id = utt_id;
+
+       /* call callback function */
+       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 0;
+}
+
 int __tts_cb_utt_completed(int uid, int utt_id)
 {
        tts_client_s* client = tts_client_get_by_uid(uid);
@@ -1422,13 +1729,16 @@ int __tts_cb_utt_completed(int uid, int utt_id)
                return TTS_ERROR_INVALID_PARAMETER;
        }
 
-       SECURE_SLOG(LOG_DEBUG, TAG_TTSC, "utterance completed : uttid(%d) ", utt_id);
+       SLOG(LOG_DEBUG, 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 ");
        }
@@ -1438,12 +1748,8 @@ 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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == callback) {
@@ -1459,7 +1765,7 @@ 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;
        }
 
@@ -1473,12 +1779,8 @@ int tts_set_state_changed_cb(tts_h tts, tts_state_changed_cb callback, void* use
 
 int tts_unset_state_changed_cb(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts) {
@@ -1494,7 +1796,7 @@ 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;
        }
 
@@ -1508,12 +1810,8 @@ 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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == callback) {
@@ -1529,7 +1827,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;
        }
 
@@ -1537,18 +1835,14 @@ 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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts) {
@@ -1564,7 +1858,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;
        }
 
@@ -1572,18 +1866,14 @@ 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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == callback) {
@@ -1599,7 +1889,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;
        }
 
@@ -1607,18 +1897,14 @@ 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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts) {
@@ -1634,7 +1920,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;
        }
 
@@ -1647,12 +1933,8 @@ int tts_unset_utterance_completed_cb(tts_h tts)
 
 int tts_set_error_cb(tts_h tts, tts_error_cb callback, void* user_data)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == callback) {
@@ -1668,7 +1950,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;
        }
 
@@ -1676,18 +1958,14 @@ 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)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts) {
@@ -1701,9 +1979,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;
        }
 
@@ -1717,12 +1995,8 @@ int tts_unset_error_cb(tts_h tts)
 
 int tts_set_default_voice_changed_cb(tts_h tts, tts_default_voice_changed_cb callback, void* user_data)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts || NULL == callback) {
@@ -1738,7 +2012,7 @@ int tts_set_default_voice_changed_cb(tts_h tts, tts_default_voice_changed_cb cal
        }
 
        if (TTS_STATE_CREATED != client->current_state) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set default voice changed cb : Current state is not 'Created'."); 
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Set default voice changed cb : Current state is not 'Created'.");
                return TTS_ERROR_INVALID_STATE;
        }
 
@@ -1752,12 +2026,8 @@ int tts_set_default_voice_changed_cb(tts_h tts, tts_default_voice_changed_cb cal
 
 int tts_unset_default_voice_changed_cb(tts_h tts)
 {
-       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 NOT supported");
-                       return TTS_ERROR_NOT_SUPPORTED;
-               }
+       if (0 != __tts_get_feature_enabled()) {
+               return TTS_ERROR_NOT_SUPPORTED;
        }
 
        if (NULL == tts) {
@@ -1773,7 +2043,7 @@ int tts_unset_default_voice_changed_cb(tts_h tts)
        }
 
        if (TTS_STATE_CREATED != client->current_state) {
-               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset default voice changed cb : Current state is not 'Created'."); 
+               SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Unset default voice changed cb : Current state is not 'Created'.");
                return TTS_ERROR_INVALID_STATE;
        }