X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=client%2Fstt.c;h=149ac44a692772f55d7e008d2bbd2dd08ab5db2d;hb=a0f10f8a82016e437f4f8adf8aef288ed2cf9404;hp=d69e7f0d65361d72353c237a847b9a7174416a43;hpb=40599ac6a76c42cdcab03a44caec593edf562501;p=platform%2Fcore%2Fuifw%2Fstt.git diff --git a/client/stt.c b/client/stt.c index d69e7f0..149ac44 100644 --- a/client/stt.c +++ b/client/stt.c @@ -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 @@ -24,11 +24,13 @@ #include #include #include +#include #include "stt.h" #include "stt_client.h" #include "stt_dbus.h" #include "stt_config_mgr.h" +#include "stt_internal.h" #include "stt_main.h" @@ -85,20 +87,21 @@ static int __check_privilege_initialize() int ret = cynara_initialize(&p_cynara, NULL); if (CYNARA_API_SUCCESS != ret) SLOG(LOG_ERROR, TAG_STTC, "[ERROR] fail to initialize"); - + return ret == CYNARA_API_SUCCESS; } static int __check_privilege(const char* uid, const char * privilege) { FILE *fp = NULL; - char smack_label[1024] = "/proc/self/attr/current"; + char label_path[1024] = "/proc/self/attr/current"; + char smack_label[1024] = {'\0',}; if (!p_cynara) { return false; } - fp = fopen(smack_label, "r"); + fp = fopen(label_path, "r"); if (fp != NULL) { if (fread(smack_label, 1, sizeof(smack_label), fp) <= 0) SLOG(LOG_ERROR, TAG_STTC, "[ERROR] fail to fread"); @@ -110,8 +113,10 @@ static int __check_privilege(const char* uid, const char * privilege) char *session = cynara_session_from_pid(pid); int ret = cynara_check(p_cynara, smack_label, session, uid, privilege); SLOG(LOG_DEBUG, TAG_STTC, "[Client]cynara_check returned %d(%s)", ret, (CYNARA_API_ACCESS_ALLOWED == ret) ? "Allowed" : "Denied"); - if (session) - free(session); + if (session) { + free(session); + session = NULL; + } if (ret != CYNARA_API_ACCESS_ALLOWED) return false; @@ -133,7 +138,7 @@ static int __stt_check_privilege() SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Permission is denied"); return STT_ERROR_PERMISSION_DENIED; } else if (-1 == g_privilege_allowed) { - if (false == __check_privilege_initialize()){ + if (false == __check_privilege_initialize()) { SLOG(LOG_ERROR, TAG_STTC, "[ERROR] privilege initialize is failed"); return STT_ERROR_PERMISSION_DENIED; } @@ -148,7 +153,7 @@ static int __stt_check_privilege() } g_privilege_allowed = 1; - return STT_ERROR_NONE; + return STT_ERROR_NONE; } static const char* __stt_get_error_code(stt_error_e err) @@ -168,6 +173,7 @@ static const char* __stt_get_error_code(stt_error_e err) case STT_ERROR_ENGINE_NOT_FOUND: return "STT_ERROR_ENGINE_NOT_FOUND"; case STT_ERROR_OPERATION_FAILED: return "STT_ERROR_OPERATION_FAILED"; case STT_ERROR_NOT_SUPPORTED_FEATURE: return "STT_ERROR_NOT_SUPPORTED_FEATURE"; + case STT_ERROR_SERVICE_RESET: return "STT_ERROR_SERVICE_RESET"; default: return "Invalid error code"; } @@ -224,6 +230,33 @@ void __stt_config_lang_changed_cb(const char* before_language, const char* curre return; } +static Eina_Bool __reconnect_by_engine_changed(void *data) +{ + stt_h stt = (stt_h)data; + + stt_client_s* client = stt_client_get(stt); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_STTC, "[WARNING] A handle is not valid"); + return EINA_FALSE; + } + + if (STT_STATE_READY != client->current_state) { + usleep(10000); + return EINA_TRUE; + } + + int ret = stt_unprepare(stt); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + ret = stt_prepare(stt); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + + return EINA_FALSE; +} + void __stt_config_engine_changed_cb(const char* engine_id, const char* setting, const char* language, bool support_silence, bool need_credential, void* user_data) { stt_h stt = (stt_h)user_data; @@ -239,11 +272,34 @@ void __stt_config_engine_changed_cb(const char* engine_id, const char* setting, if (NULL != language) SLOG(LOG_DEBUG, TAG_STTC, "Language(%s)", language); SLOG(LOG_DEBUG, TAG_STTC, "Silence(%s), Credential(%s)", support_silence ? "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 (NULL == client->current_engine_id) { + if (STT_STATE_RECORDING == client->current_state || STT_STATE_PROCESSING == client->current_state) { + ret = stt_cancel(stt); + if (0 != ret) { + SLOG(LOG_DEBUG, TAG_STTC, "[DEBUG] STT client canceling..."); + } + + ecore_idler_add(__reconnect_by_engine_changed, (void*)stt); + } else if (STT_STATE_READY == client->current_state) { + ret = stt_unprepare(stt); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + ret = stt_prepare(stt); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to prepare for setting a new engine... (%d)", ret); + } + } + } + /* call callback function */ if (NULL != client->engine_changed_cb) { client->engine_changed_cb(stt, engine_id, language, support_silence, need_credential, client->engine_changed_user_data); } else { - SLOG(LOG_WARN, TAG_STTC, "No registered callback function of supported languages"); + SLOG(LOG_WARN, TAG_STTC, "No registered callback function for engine change"); } return; } @@ -501,6 +557,61 @@ int stt_get_engine(stt_h stt, char** engine_id) return ret; } +int __stt_set_buxtonkey(const char* engine_id) +{ + /* Set vconfkey */ + struct buxton_client * bux_cli; + struct buxton_layer * bux_layer; + struct buxton_value * bux_val; + + int ret = buxton_open(&bux_cli, NULL, NULL); + if (0 != ret) { + SLOG(LOG_ERROR, stt_tag(), "[DBUS-BUXTON2] Fail to open buxton client"); + return STT_ERROR_OPERATION_FAILED; + } + SLOG(LOG_DEBUG, stt_tag(), "[DBUS-BUXTON2] buxton_open: %d", ret); + bux_layer = buxton_create_layer("system"); + if (NULL == bux_layer) { + SLOG(LOG_ERROR, stt_tag(), "[DBUS-BUXTON2] buxton_create_layer FAIL"); + buxton_close(bux_cli); + bux_cli = NULL; + return STT_ERROR_OPERATION_FAILED; + } + bux_val = buxton_value_create_string(engine_id); + if (NULL == bux_val) { + SLOG(LOG_ERROR, stt_tag(), "[DBUS-BUXTON2] buxton_value_create_string FAIL"); + buxton_free_layer(bux_layer); + buxton_close(bux_cli); + bux_layer = NULL; + bux_cli = NULL; + return STT_ERROR_OPERATION_FAILED; + } + + ret = buxton_set_value_sync(bux_cli, bux_layer, STT_ENGINE_DB_CUSTOM, bux_val); + if (0 != ret) { + SLOG(LOG_ERROR, stt_tag(), "[DBUS-BUXTON2] Fail to set value sync"); + buxton_value_free(bux_val); + buxton_free_layer(bux_layer); + buxton_close(bux_cli); + + bux_cli = NULL; + bux_layer = NULL; + bux_val = NULL; + return STT_ERROR_OPERATION_FAILED; + } + SLOG(LOG_DEBUG, stt_tag(), "[DBUS-BUXTON2] buxton_set_value_sync: %d, %s", ret, STT_ENGINE_DB_CUSTOM); + + buxton_value_free(bux_val); + buxton_free_layer(bux_layer); + buxton_close(bux_cli); + + bux_cli = NULL; + bux_layer = NULL; + bux_val = NULL; + + return STT_ERROR_NONE; +} + int stt_set_engine(stt_h stt, const char* engine_id) { stt_client_s* client = NULL; @@ -529,10 +640,20 @@ int stt_set_engine(stt_h stt, const char* engine_id) if (NULL != client->current_engine_id) { free(client->current_engine_id); + client->current_engine_id = NULL; } + SLOG(LOG_DEBUG, TAG_STTC, "===== engined_id(%s)", engine_id); + client->current_engine_id = strdup(engine_id); + /* Set vconfkey */ + int ret = __stt_set_buxtonkey(engine_id); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] set buxtonkey Failed!!!"); + return ret; + } + SLOG(LOG_DEBUG, TAG_STTC, "====="); SLOG(LOG_DEBUG, TAG_STTC, " "); @@ -555,7 +676,7 @@ int stt_set_credential(stt_h stt, const char* credential) SLOG(LOG_DEBUG, TAG_STTC, "===== Set credential"); if (NULL == credential) { - SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Input parameter is NULL, stt(%s), credential(%a)", stt, credential); + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Input parameter is NULL"); return STT_ERROR_INVALID_PARAMETER; } @@ -565,6 +686,10 @@ int stt_set_credential(stt_h stt, const char* credential) return STT_ERROR_INVALID_STATE; } + if (NULL != client->credential) { + free(client->credential); + client->credential = NULL; + } client->credential = strdup(credential); SLOG(LOG_DEBUG, TAG_STTC, "====="); @@ -599,6 +724,11 @@ int stt_set_private_data(stt_h stt, const char* key, const char* data) return STT_ERROR_INVALID_STATE; } + if (true != client->internal && (0 == strcmp(key, "server") || 0 == strcmp(key, "rampcode") || 0 == strcmp(key, "epd"))) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] This is not an internal app"); + return STT_ERROR_INVALID_PARAMETER; + } + int ret = -1; int count = 0; while (0 != ret) { @@ -671,11 +801,79 @@ int stt_get_private_data(stt_h stt, const char* key, char** data) } } + if (0 == strncmp(*data, "NULL", strlen(*data))) { + free(*data); + *data = NULL; + } + SLOG(LOG_DEBUG, TAG_STTC, "====="); SLOG(LOG_DEBUG, TAG_STTC, ""); return STT_ERROR_NONE; } + +int stt_set_server_stt(stt_h stt, const char* key, char* user_data) +{ + int ret = -1; + stt_client_s* client = NULL; + + if (0 != __stt_get_feature_enabled()) { + return STT_ERROR_NOT_SUPPORTED; + } + if (0 != __stt_check_privilege()) { + return STT_ERROR_PERMISSION_DENIED; + } + if (0 != __stt_check_handle(stt, &client)) { + return STT_ERROR_INVALID_PARAMETER; + } + + SLOG(LOG_DEBUG, TAG_STTC, "===== Set STT server"); + + if (NULL == key || NULL == user_data) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid parameter"); + return STT_ERROR_INVALID_PARAMETER; + } + + if (STT_STATE_CREATED != client->current_state && STT_STATE_READY != client->current_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] The current state is invalid (%d).", client->current_state); + return STT_ERROR_INVALID_STATE; + } + + + client->internal = true; + + char* private_key = NULL; + private_key = strdup(key); + if (NULL == private_key) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to allocate memory(private_key)"); + return STT_ERROR_OUT_OF_MEMORY; + } + + char* data = NULL; + data = strdup(user_data); + if (NULL == data) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to allocate memory(data)"); + free(private_key); + private_key = NULL; + return STT_ERROR_OUT_OF_MEMORY; + } + + ret = stt_set_private_data(stt, private_key, data); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to set private data, ret(%d), key(%s)", ret, private_key); + } + + free(data); + data = NULL; + free(private_key); + private_key = NULL; + + SLOG(LOG_DEBUG, TAG_STTC, "======"); + SLOG(LOG_DEBUG, TAG_STTC, " "); + + return ret; +} + static Eina_Bool __stt_connect_daemon(void *data) { stt_client_s* client = (stt_client_s*)data; @@ -688,7 +886,7 @@ static Eina_Bool __stt_connect_daemon(void *data) /* Send hello */ int ret = -1; - ret = stt_dbus_request_hello(); + ret = stt_dbus_request_hello(client->uid); if (0 != ret) { if (STT_ERROR_INVALID_STATE == ret) { @@ -699,7 +897,7 @@ static Eina_Bool __stt_connect_daemon(void *data) } g_connect_timer = NULL; - SLOG(LOG_DEBUG, TAG_STTC, "===== Connect daemon"); + SLOG(LOG_DEBUG, TAG_STTC, "===== Connect stt-service"); /* request initialization */ bool silence_supported = false; @@ -719,17 +917,20 @@ static Eina_Bool __stt_connect_daemon(void *data) SLOG(LOG_ERROR, TAG_STTC, "[WARNING] Fail to connection. Retry to connect"); return EINA_TRUE; } else { - /* success to connect stt-daemon */ + /* success to connect stt-service */ client->silence_supported = silence_supported; client->credential_needed = credential_needed; SLOG(LOG_DEBUG, TAG_STTC, "Supported options : silence(%s), credential(%s)", silence_supported ? "support" : "no support", credential_needed ? "need" : "no need"); } +#ifdef __UNUSED_CODES__ if (NULL != client->current_engine_id) { ret = -1; int count = 0; silence_supported = false; credential_needed = false; + SLOG(LOG_DEBUG, TAG_STTC, "[WARNING] current_engine_id(%s)", client->current_engine_id); + while (0 != ret) { ret = stt_dbus_request_set_current_engine(client->uid, client->current_engine_id, &silence_supported, &credential_needed); if (0 != ret) { @@ -754,7 +955,7 @@ static Eina_Bool __stt_connect_daemon(void *data) } } } - +#endif SLOG(LOG_DEBUG, TAG_STTC, "[SUCCESS] uid(%d)", client->uid); client->before_state = client->current_state; @@ -938,6 +1139,7 @@ int stt_foreach_supported_languages(stt_h stt, stt_supported_language_cb callbac if (NULL != current_engine_id) { free(current_engine_id); + current_engine_id = NULL; } client->supported_lang_cb = NULL; @@ -1427,8 +1629,14 @@ int stt_stop(stt_h stt) return STT_ERROR_INVALID_STATE; } - if (STT_INTERNAL_STATE_NONE != client->internal_state) { - SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is NOT none : %d", client->internal_state); + if (STT_INTERNAL_STATE_STARTING == client->internal_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is STARTING : %d", client->internal_state); + return STT_ERROR_IN_PROGRESS_TO_RECORDING; + } else if (STT_INTERNAL_STATE_CANCELING == client->internal_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is CANCELING : %d", client->internal_state); + return STT_ERROR_IN_PROGRESS_TO_READY; + } else if (STT_INTERNAL_STATE_STOPPING == client->internal_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is STOPPING : %d", client->internal_state); return STT_ERROR_IN_PROGRESS_TO_PROCESSING; } @@ -1438,7 +1646,7 @@ int stt_stop(stt_h stt) SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to stop : %s", __stt_get_error_code(ret)); } else { SLOG(LOG_DEBUG, TAG_STTC, "[SUCCESS] Stop is successful but not done"); - client->internal_state = STT_INTERNAL_STATE_STOPING; + client->internal_state = STT_INTERNAL_STATE_STOPPING; } SLOG(LOG_DEBUG, TAG_STTC, "====="); @@ -1469,8 +1677,14 @@ int stt_cancel(stt_h stt) return STT_ERROR_INVALID_STATE; } - if (STT_INTERNAL_STATE_NONE != client->internal_state) { - SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is NOT none : %d", client->internal_state); + if (STT_INTERNAL_STATE_STARTING == client->internal_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is STARTING : %d", client->internal_state); + return STT_ERROR_IN_PROGRESS_TO_RECORDING; + } else if (STT_INTERNAL_STATE_STOPPING == client->internal_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is STOPPING : %d", client->internal_state); + return STT_ERROR_IN_PROGRESS_TO_PROCESSING; + } else if (STT_INTERNAL_STATE_CANCELING == client->internal_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State : Internal state is CANCELING : %d", client->internal_state); return STT_ERROR_IN_PROGRESS_TO_READY; } @@ -1630,26 +1844,82 @@ static Eina_Bool __stt_notify_error(void *data) int __stt_cb_error(int uid, int reason, char* err_msg) { - stt_client_s* client = stt_client_get_by_uid(uid); - if (NULL == client) { - SLOG(LOG_ERROR, TAG_STTC, "Handle not found"); - return -1; - } + if (-1 == uid) { + GList* client_list = NULL; + client_list = stt_client_get_client_list(); - client->reason = reason; - client->internal_state = STT_INTERNAL_STATE_NONE; - if (NULL != client->err_msg) { - free(client->err_msg); - client->err_msg = NULL; - } - client->err_msg = strdup(err_msg); + GList *iter = NULL; + stt_client_s *data = NULL; - SLOG(LOG_INFO, TAG_STTC, "internal state is initialized to 0"); + if (g_list_length(client_list) > 0) { + /* Get a first item */ + iter = g_list_first(client_list); - if (NULL != client->error_cb) { - ecore_timer_add(0, __stt_notify_error, client); + while (NULL != iter) { + data = iter->data; + + data->reason = reason; + data->internal_state = STT_INTERNAL_STATE_NONE; + if (NULL != data->err_msg) { + free(data->err_msg); + data->err_msg = NULL; + } + if (NULL != err_msg) + data->err_msg = strdup(err_msg); + + SLOG(LOG_INFO, TAG_STTC, "internal state is initialized to 0"); + + if (NULL != data->error_cb) { + ecore_timer_add(0, __stt_notify_error, data); + } else { + SLOG(LOG_WARN, TAG_STTC, "[WARNING] Error callback is null"); + } + + if (STT_ERROR_SERVICE_RESET == reason) { + SLOG(LOG_WARN, TAG_STTC, "[WARNING] Service reset"); + + data->current_state = STT_STATE_CREATED; + if (0 != stt_prepare(data->stt)) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to prepare"); + } + } + + /* Next item */ + iter = g_list_next(iter); + } + } } else { - SLOG(LOG_WARN, TAG_STTC, "[WARNING] Error callback is null"); + stt_client_s* client = stt_client_get_by_uid(uid); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_STTC, "Handle not found"); + return -1; + } + + client->reason = reason; + client->internal_state = STT_INTERNAL_STATE_NONE; + if (NULL != client->err_msg) { + free(client->err_msg); + client->err_msg = NULL; + } + if (NULL != err_msg) + client->err_msg = strdup(err_msg); + + SLOG(LOG_INFO, TAG_STTC, "internal state is initialized to 0"); + + if (NULL != client->error_cb) { + ecore_timer_add(0, __stt_notify_error, client); + } else { + SLOG(LOG_WARN, TAG_STTC, "[WARNING] Error callback is null"); + } + + if (STT_ERROR_SERVICE_RESET == reason) { + SLOG(LOG_WARN, TAG_STTC, "[WARNING] Service reset"); + + client->current_state = STT_STATE_CREATED; + if (0 != stt_prepare(client->stt)) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to prepare"); + } + } } return 0; @@ -1672,7 +1942,7 @@ static void __stt_notify_state_changed(void *data) if (STT_INTERNAL_STATE_STARTING == client->internal_state && STT_STATE_RECORDING == client->current_state) { client->internal_state = STT_INTERNAL_STATE_NONE; SLOG(LOG_DEBUG, TAG_STTC, "Internal state change to NONE"); - } else if (STT_INTERNAL_STATE_STOPING == client->internal_state && STT_STATE_PROCESSING == client->current_state) { + } else if (STT_INTERNAL_STATE_STOPPING == client->internal_state && STT_STATE_PROCESSING == client->current_state) { client->internal_state = STT_INTERNAL_STATE_NONE; SLOG(LOG_DEBUG, TAG_STTC, "Internal state change to NONE"); } else if (STT_INTERNAL_STATE_CANCELING == client->internal_state && STT_STATE_READY == client->current_state) { @@ -1832,6 +2102,46 @@ int __stt_cb_set_state(int uid, int state) return 0; } +static void __stt_notify_speech_status(void *data) +{ + stt_client_s* client = (stt_client_s*)data; + + /* check handle */ + if (NULL == client) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to notify speech status : A handle is not valid"); + return; + } + + if (NULL == stt_client_get_by_uid(client->uid)) { + return; + } + + if (NULL != client->speech_status_cb) { + stt_client_use_callback(client); + client->speech_status_cb(client->stt, client->speech_status, client->speech_status_user_data); + stt_client_not_use_callback(client); + SLOG(LOG_DEBUG, TAG_STTC, "Speech status callback is called"); + } else { + SLOG(LOG_WARN, TAG_STTC, "[WARNING] Speech status callback is null"); + } + + return; +} + +int __stt_cb_speech_status(int uid, int status) +{ + stt_client_s* client = stt_client_get_by_uid(uid); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_STTC, "Handle not found"); + return -1; + } + + client->speech_status = status; + + ecore_main_loop_thread_safe_call_async(__stt_notify_speech_status, client); + return 0; +} + int stt_set_recognition_result_cb(stt_h stt, stt_recognition_result_cb callback, void* user_data) { stt_client_s* client = NULL; @@ -2086,3 +2396,54 @@ int stt_unset_engine_changed_cb(stt_h stt) return 0; } + +int stt_set_speech_status_cb(stt_h stt, stt_speech_status_cb callback, void* user_data) +{ + stt_client_s* client = NULL; + if (0 != __stt_get_feature_enabled()) { + return STT_ERROR_NOT_SUPPORTED; + } + if (0 != __stt_check_privilege()) { + return STT_ERROR_PERMISSION_DENIED; + } + if (0 != __stt_check_handle(stt, &client)) { + return STT_ERROR_INVALID_PARAMETER; + } + + if (NULL == callback) + return STT_ERROR_INVALID_PARAMETER; + + if (STT_STATE_CREATED != client->current_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Current state(%d) is not 'Created'", client->current_state); + return STT_ERROR_INVALID_STATE; + } + + client->speech_status_cb = callback; + client->speech_status_user_data = user_data; + + return 0; +} + +int stt_unset_speech_status_cb(stt_h stt) +{ + stt_client_s* client = NULL; + if (0 != __stt_get_feature_enabled()) { + return STT_ERROR_NOT_SUPPORTED; + } + if (0 != __stt_check_privilege()) { + return STT_ERROR_PERMISSION_DENIED; + } + if (0 != __stt_check_handle(stt, &client)) { + return STT_ERROR_INVALID_PARAMETER; + } + + if (STT_STATE_CREATED != client->current_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Current state(%d) is not 'Created'", client->current_state); + return STT_ERROR_INVALID_STATE; + } + + client->speech_status_cb = NULL; + client->speech_status_user_data = NULL; + + return 0; +}