From 6136ff63f55ec03f67272624a37e8a21e623441f Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Wed, 26 Jul 2017 08:59:17 +0900 Subject: [PATCH] Add internal api for file recognition Change-Id: Ic51ab61631b9f0023a8005e2c7496309b76d1bb9 Signed-off-by: Wonnam Jang --- client/stt.c | 121 ++++++++++++++++++++++++++++++- client/stt_dbus.c | 115 ++++++++++++++++++++++++++++++ client/stt_dbus.h | 4 ++ client/stt_file_client.c | 4 ++ common/stt_defs.h | 3 + include/stt_internal.h | 64 +++++++++++++++++ server/sttd_dbus.c | 23 ++++-- server/sttd_dbus_server.c | 90 +++++++++++++++++++++++ server/sttd_dbus_server.h | 3 + server/sttd_engine_agent.c | 61 ++++++++++++++++ server/sttd_engine_agent.h | 4 ++ server/sttd_recorder.c | 67 ++++++++++++++++++ server/sttd_recorder.h | 4 ++ server/sttd_server.c | 173 ++++++++++++++++++++++++++++++++++++++++++++- server/sttd_server.h | 3 + 15 files changed, 729 insertions(+), 10 deletions(-) mode change 100755 => 100644 server/sttd_server.c diff --git a/client/stt.c b/client/stt.c index fe24360..f4fe7a6 100644 --- a/client/stt.c +++ b/client/stt.c @@ -1998,9 +1998,9 @@ static void __stt_notify_state_changed(void *data) client->state_changed_cb(client->stt, client->before_state, client->current_state, client->state_changed_user_data); stt_client_not_use_callback(client); - SLOG(LOG_DEBUG, TAG_STTC, "State changed callback is called"); + SLOG(LOG_DEBUG, TAG_STTC, "State changed callback is called, State(%d)", client->current_state); } else { - SLOG(LOG_WARN, TAG_STTC, "[WARNING] State changed callback is null"); + SLOG(LOG_WARN, TAG_STTC, "[WARNING] State changed callback is null, State(%d)", client->current_state); } return; @@ -2490,3 +2490,120 @@ int stt_unset_speech_status_cb(stt_h stt) return 0; } + +int stt_start_file(stt_h stt, const char* language, const char* type, const char* filepath, stt_audio_type_e audio_type, int sample_rate) +{ + 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 == filepath) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Input parameter is NULL"); + return STT_ERROR_INVALID_PARAMETER; + } + + SLOG(LOG_DEBUG, TAG_STTC, "===== STT START FILE"); + + /* check state */ + if (client->current_state != STT_STATE_READY) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid State: Current state(%d) is not READY", client->current_state); + 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); + return STT_ERROR_IN_PROGRESS_TO_RECORDING; + } + + int ret = -1; + char appid[128] = {0, }; + ret = aul_app_get_appid_bypid(getpid(), appid, sizeof(appid)); + + if ((AUL_R_OK != ret) || (0 == strlen(appid))) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to get application ID"); + } else { + SLOG(LOG_DEBUG, TAG_STTC, "[DEBUG] Current app id is %s", appid); + } + + char* temp = NULL; + if (NULL == language) { + temp = strdup("default"); + } else { + temp = strdup(language); + } + + if (true == client->credential_needed && NULL == client->credential) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Do not have app credential for this engine(%s)", client->current_engine_id); + return STT_ERROR_PERMISSION_DENIED; + } + + client->internal_state = STT_INTERNAL_STATE_STARTING; + ret = stt_dbus_request_start_file(client->uid, temp, type, client->silence, appid, client->credential, filepath, audio_type, sample_rate); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to start file : %s", __stt_get_error_code(ret)); + client->internal_state = STT_INTERNAL_STATE_NONE; + } else { + SLOG(LOG_DEBUG, TAG_STTC, "[SUCCESS] Start is successful but not done"); + } + + if (NULL != temp) free(temp); + + SLOG(LOG_DEBUG, TAG_STTC, "====="); + SLOG(LOG_DEBUG, TAG_STTC, " "); + + return ret; +} + +int stt_cancel_file(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; + } + + SLOG(LOG_DEBUG, TAG_STTC, "===== STT CANCEL FILE"); + + /* check state */ + if (STT_STATE_RECORDING != client->current_state && STT_STATE_PROCESSING != client->current_state) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Invalid state : Current state(%d) is 'Ready'", client->current_state); + return STT_ERROR_INVALID_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; + } + + client->internal_state = STT_INTERNAL_STATE_CANCELING; + int ret = stt_dbus_request_cancel_file(client->uid); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Fail to cancel file : %s", __stt_get_error_code(ret)); + client->internal_state = STT_INTERNAL_STATE_NONE; + } else { + SLOG(LOG_DEBUG, TAG_STTC, "[SUCCESS] Cancel file is successful but not done"); + } + + SLOG(LOG_DEBUG, TAG_STTC, "====="); + SLOG(LOG_DEBUG, TAG_STTC, " "); + + return ret; +} + diff --git a/client/stt_dbus.c b/client/stt_dbus.c index e5da100..f62b0a4 100644 --- a/client/stt_dbus.c +++ b/client/stt_dbus.c @@ -2139,3 +2139,118 @@ int stt_dbus_request_cancel(int uid) return result; #endif } + +int stt_dbus_request_start_file(int uid, const char* lang, const char* type, int silence, const char* appid, const char* credential, const char* filepath, stt_audio_type_e audio_type, int sample_rate) +{ + if (NULL == lang || NULL == type || NULL == appid) { + SLOG(LOG_ERROR, TAG_STTC, "Input parameter is NULL"); + return STT_ERROR_INVALID_PARAMETER; + } + + DBusMessage* msg; + + /* create a signal & check for errors */ + msg = dbus_message_new_method_call( + g_server_service_name, + g_server_service_object, + g_server_service_interface, + STT_METHOD_START_FILE); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_STTC, ">>>> stt start file : Fail to make message"); + return STT_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_STTC, ">>>> stt start file : uid(%d), language(%s), type(%s), appid(%s), filepath(%s), audio_type(%d), sample_rate(%d)", uid, lang, type, appid, filepath, audio_type, sample_rate); + } + + char *temp = NULL; + if (NULL == credential) { + temp = strdup("NULL"); + } else { + temp = strdup(credential); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &uid, + DBUS_TYPE_STRING, &lang, + DBUS_TYPE_STRING, &type, + DBUS_TYPE_INT32, &silence, + DBUS_TYPE_STRING, &appid, + DBUS_TYPE_STRING, &temp, + DBUS_TYPE_STRING, &filepath, + DBUS_TYPE_INT32, &audio_type, + DBUS_TYPE_INT32, &sample_rate, + DBUS_TYPE_INVALID); + if (g_conn_sender) { + dbus_message_set_no_reply(msg, TRUE); + + if (!dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_STTC, "[Dbus ERROR] <<<< stt start message : Out Of Memory !"); + if (NULL != temp) { + free(temp); + temp = NULL; + } + return STT_ERROR_OUT_OF_MEMORY; + } else { + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + + } else { + SLOG(LOG_WARN, TAG_STTC, "[WARN] dbus connection handle is null (%p)", g_conn_sender); + if (NULL != temp) { + free(temp); + temp = NULL; + } + return STT_ERROR_OPERATION_FAILED; + } + + if (NULL != temp) { + free(temp); + temp = NULL; + } + return 0; +} + +int stt_dbus_request_cancel_file(int uid) +{ + DBusMessage* msg; + + /* create a signal & check for errors */ + msg = dbus_message_new_method_call( + g_server_service_name, + g_server_service_object, + g_server_service_interface, + STT_METHOD_CANCEL_FILE); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_STTC, ">>>> stt cancel file : Fail to make message"); + return STT_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_STTC, ">>>> stt cancel file : uid(%d)", uid); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &uid, + DBUS_TYPE_INVALID); + + if (g_conn_sender) { + dbus_message_set_no_reply(msg, TRUE); + + if (!dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_STTC, "[Dbus ERROR] <<<< stt stop message : Out Of Memory !"); + return STT_ERROR_OUT_OF_MEMORY; + } else { + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + } else { + SLOG(LOG_WARN, TAG_STTC, "[WARN] dbus connection handle is null (%p)", g_conn_sender); + return STT_ERROR_OPERATION_FAILED; + } + + return 0; +} + diff --git a/client/stt_dbus.h b/client/stt_dbus.h index 4564d41..6c7e059 100644 --- a/client/stt_dbus.h +++ b/client/stt_dbus.h @@ -17,6 +17,7 @@ #include "stt.h" #include "stt_main.h" +#include "stt_internal.h" #ifdef __cplusplus extern "C" { @@ -62,6 +63,9 @@ int stt_dbus_request_stop(int uid); int stt_dbus_request_cancel(int uid); +int stt_dbus_request_start_file(int uid, const char* lang, const char* type, int silence, const char* appid, const char* credential, const char* filepath, stt_audio_type_e audio_type, int sample_rate); + +int stt_dbus_request_cancel_file(int uid); #ifdef __cplusplus } diff --git a/client/stt_file_client.c b/client/stt_file_client.c index 40f722e..a5303e4 100644 --- a/client/stt_file_client.c +++ b/client/stt_file_client.c @@ -28,6 +28,10 @@ int stt_file_client_new() } g_client_info = (stt_file_client_s*)calloc(1, sizeof(stt_file_client_s)); + if (!g_client_info) { + SLOG(LOG_ERROR, TAG_STTFC, "[ERROR] Fail to allocate memory"); + return STT_FILE_ERROR_OUT_OF_MEMORY; + } /* initialize client data */ g_client_info->recognition_result_cb = NULL; diff --git a/common/stt_defs.h b/common/stt_defs.h index 465e22c..2fd8fd6 100644 --- a/common/stt_defs.h +++ b/common/stt_defs.h @@ -76,6 +76,9 @@ extern "C" { #define STTD_METHOD_SET_VOLUME "sttd_method_set_volume" #define STTD_METHOD_SPEECH_STATUS "sttd_method_speech_status" +#define STT_METHOD_START_FILE "stt_method_start_file" +#define STT_METHOD_CANCEL_FILE "stt_method_cancel_file" + /****************************************************************************************** * Defines for configuration diff --git a/include/stt_internal.h b/include/stt_internal.h index 5b0cc70..bebf85b 100644 --- a/include/stt_internal.h +++ b/include/stt_internal.h @@ -32,6 +32,14 @@ extern "C" #define STT_SPEECH_STATUS_BEGINNING_POINT_DETECTED 0 /** +* @brief Enumerations of audio type. +*/ +typedef enum { + STT_AUDIO_TYPE_RAW_S16 = 0, /**< Signed 16-bit audio sample */ + STT_AUDIO_TYPE_RAW_U8, /**< Unsigned 8-bit audio sample */ +} stt_audio_type_e; + +/** * @brief Called when user speaking is detected. * * @param[in] stt The STT handle @@ -124,6 +132,62 @@ int stt_unset_speech_status_cb(stt_h stt); */ int stt_set_server_stt(stt_h stt, const char* key, char* user_data); +/** + * @brief Starts file recognition asynchronously. + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * @remarks This function starts sending recorded data from file to engine. + * @param[in] stt The STT handle + * @param[in] language The language selected from stt_foreach_supported_languages() + * @param[in] type The type for recognition (e.g. #STT_RECOGNITION_TYPE_FREE, #STT_RECOGNITION_TYPE_FREE_PARTIAL) + * @param[in] filepath PCM filepath for recognition + * @param[in] audio_type audio type of file + * @param[in] sample_rate sample rate of file + * @return @c 0 on success, + * otherwise a negative error value + * @retval #STT_ERROR_NONE Successful + * @retval #STT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STT_ERROR_INVALID_STATE Invalid state + * @retval #STT_ERROR_OPERATION_FAILED Operation failure + * @retval #STT_ERROR_NOT_SUPPORTED STT NOT supported + * @retval #STT_ERROR_PERMISSION_DENIED Permission denied + * @retval #STT_ERROR_IN_PROGRESS_TO_RECORDING Progress to recording is not finished + * @pre The state should be #STT_STATE_READY. + * @post It will invoke stt_state_changed_cb(), if you register a callback with stt_state_changed_cb(). + * If this function succeeds, the STT state will be #STT_STATE_RECORDING. + * If you call this function again before state changes, you will receive STT_ERROR_IN_PROGRESS_TO_RECORDING. + * @see stt_cancel_file() + * @see stt_state_changed_cb() +*/ +int stt_start_file(stt_h stt, const char* language, const char* type, const char* filepath, stt_audio_type_e audio_type, int sample_rate); + +/** + * @brief Cancels processing file recognition asynchronously. + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * @remarks This function cancels recording and engine cancels recognition processing. + * After successful cancel, stt_state_changed_cb() is called otherwise if error is occurred, stt_error_cb() is called. + * @param[in] stt The STT handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #STT_ERROR_NONE Successful + * @retval #STT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STT_ERROR_INVALID_STATE Invalid state + * @retval #STT_ERROR_OPERATION_FAILED Operation failure + * @retval #STT_ERROR_NOT_SUPPORTED STT NOT supported + * @retval #STT_ERROR_PERMISSION_DENIED Permission denied + * @retval #STT_ERROR_IN_PROGRESS_TO_READY Progress to ready is not finished + * @retval #STT_ERROR_IN_PROGRESS_TO_RECORDING Progress to recording is not finished + * @retval #STT_ERROR_IN_PROGRESS_TO_PROCESSING Progress to processing is not finished + * @pre The state should be #STT_STATE_RECORDING or #STT_STATE_PROCESSING. + * @post It will invoke stt_state_changed_cb(), if you register a callback with stt_state_changed_cb(). + * If this function succeeds, the STT state will be #STT_STATE_READY. + * If you call this function again before state changes, you will receive STT_ERROR_IN_PROGRESS_TO_READY. + * @see stt_start_file() + * @see stt_state_changed_cb() +*/ +int stt_cancel_file(stt_h stt); + #ifdef __cplusplus } #endif diff --git a/server/sttd_dbus.c b/server/sttd_dbus.c index 0f68473..99a29a2 100644 --- a/server/sttd_dbus.c +++ b/server/sttd_dbus.c @@ -475,6 +475,11 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle else if (dbus_message_is_method_call(msg, g_server_service_interface, STT_METHOD_CANCEL)) sttd_dbus_server_cancel(g_conn_listener, msg); + else if (dbus_message_is_method_call(msg, g_server_service_interface, STT_METHOD_START_FILE)) + sttd_dbus_server_start_file(g_conn_listener, msg); + + else if (dbus_message_is_method_call(msg, g_server_service_interface, STT_METHOD_CANCEL_FILE)) + sttd_dbus_server_cancel_file(g_conn_listener, msg); /* free the message */ dbus_message_unref(msg); @@ -585,18 +590,24 @@ int __sttd_get_buxtonkey() if (NULL == engine_appid || NULL == engine_default || 0 == strncmp(engine_appid, engine_default, strlen(engine_appid))) { g_server_service_name = (char*)calloc(strlen(STT_SERVER_SERVICE_NAME) + 1, sizeof(char)); - snprintf(g_server_service_name, strlen(STT_SERVER_SERVICE_NAME) + 1, "%s", STT_SERVER_SERVICE_NAME); + if (g_server_service_name) + snprintf(g_server_service_name, strlen(STT_SERVER_SERVICE_NAME) + 1, "%s", STT_SERVER_SERVICE_NAME); g_server_service_object = (char*)calloc(strlen(STT_SERVER_SERVICE_OBJECT_PATH) + 1, sizeof(char)); - snprintf(g_server_service_object, strlen(STT_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", STT_SERVER_SERVICE_OBJECT_PATH); + if (g_server_service_object) + snprintf(g_server_service_object, strlen(STT_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", STT_SERVER_SERVICE_OBJECT_PATH); g_server_service_interface = (char*)calloc(strlen(STT_SERVER_SERVICE_INTERFACE) + 1, sizeof(char)); - snprintf(g_server_service_interface, strlen(STT_SERVER_SERVICE_INTERFACE) + 1, "%s", STT_SERVER_SERVICE_INTERFACE); + if (g_server_service_interface) + snprintf(g_server_service_interface, strlen(STT_SERVER_SERVICE_INTERFACE) + 1, "%s", STT_SERVER_SERVICE_INTERFACE); } else { g_server_service_name = (char*)calloc(strlen(STT_SERVER_SERVICE_NAME) + strlen(engine_appid) - 8, sizeof(char)); - snprintf(g_server_service_name, strlen(STT_SERVER_SERVICE_NAME) + strlen(engine_appid) - 8, "%s%s%s", STT_SERVER_SERVICE_NAME, ".", (engine_appid + 10)); + if (g_server_service_name) + snprintf(g_server_service_name, strlen(STT_SERVER_SERVICE_NAME) + strlen(engine_appid) - 8, "%s%s%s", STT_SERVER_SERVICE_NAME, ".", (engine_appid + 10)); g_server_service_object = (char*)calloc(strlen(STT_SERVER_SERVICE_OBJECT_PATH) + strlen(engine_appid) - 8, sizeof(char)); - snprintf(g_server_service_object, strlen(STT_SERVER_SERVICE_OBJECT_PATH) + strlen(engine_appid) - 8, "%s%s%s", STT_SERVER_SERVICE_OBJECT_PATH, "/", (engine_appid + 10)); + if (g_server_service_object) + snprintf(g_server_service_object, strlen(STT_SERVER_SERVICE_OBJECT_PATH) + strlen(engine_appid) - 8, "%s%s%s", STT_SERVER_SERVICE_OBJECT_PATH, "/", (engine_appid + 10)); g_server_service_interface = (char*)calloc(strlen(STT_SERVER_SERVICE_INTERFACE) + strlen(engine_appid) - 8, sizeof(char)); - snprintf(g_server_service_interface, strlen(STT_SERVER_SERVICE_INTERFACE) + strlen(engine_appid) - 8, "%s%s%s", STT_SERVER_SERVICE_INTERFACE, ".", (engine_appid + 10)); + if (g_server_service_interface) + snprintf(g_server_service_interface, strlen(STT_SERVER_SERVICE_INTERFACE) + strlen(engine_appid) - 8, "%s%s%s", STT_SERVER_SERVICE_INTERFACE, ".", (engine_appid + 10)); } if (NULL == g_server_service_name || NULL == g_server_service_object || NULL == g_server_service_interface) { diff --git a/server/sttd_dbus_server.c b/server/sttd_dbus_server.c index 2428cb0..b3ab460 100644 --- a/server/sttd_dbus_server.c +++ b/server/sttd_dbus_server.c @@ -1147,3 +1147,93 @@ int sttd_dbus_server_cancel(DBusConnection* conn, DBusMessage* msg) return 0; } + +int sttd_dbus_server_start_file(DBusConnection* conn, DBusMessage* msg) +{ + DBusError err; + dbus_error_init(&err); + + int uid; + char* lang; + char* type; + char* appid; + int silence; + char* credential; + char* filepath; + stte_audio_type_e audio_type; + int sample_rate; + + int ret = STTD_ERROR_OPERATION_FAILED; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &uid, + DBUS_TYPE_STRING, &lang, + DBUS_TYPE_STRING, &type, + DBUS_TYPE_INT32, &silence, + DBUS_TYPE_STRING, &appid, + DBUS_TYPE_STRING, &credential, + DBUS_TYPE_STRING, &filepath, + DBUS_TYPE_INT32, &audio_type, + DBUS_TYPE_INT32, &sample_rate, + DBUS_TYPE_INVALID); + + SLOG(LOG_DEBUG, TAG_STTD, ">>>>> STT Start File"); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_STTD, "[IN ERROR] stt start file: get arguments error (%s)", err.message); + dbus_error_free(&err); + ret = STTD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_STTD, "[IN] stt start file : uid(%d), lang(%s), type(%s), silence(%d) appid(%s) filepath(%s), audio_type(%d), sample_rate(%d)" + , uid, lang, type, silence, appid, filepath, audio_type, sample_rate); + ret = sttd_server_start_file(uid, lang, type, silence, appid, credential, filepath, audio_type, sample_rate); + } + + if (0 <= ret) { + SLOG(LOG_DEBUG, TAG_STTD, "[OUT SUCCESS] Result(%d)", ret); + } else { + SLOG(LOG_ERROR, TAG_STTD, "[OUT ERROR] Result(%d)", ret); + if (0 != sttdc_send_error_signal(uid, ret, "[ERROR] Fail to start file")) { + SLOG(LOG_ERROR, TAG_STTD, "[ERROR] Fail to send error signal"); + } + } + + SLOG(LOG_DEBUG, TAG_STTD, "<<<<<"); + SLOG(LOG_DEBUG, TAG_STTD, " "); + + return 0; +} + +int sttd_dbus_server_cancel_file(DBusConnection* conn, DBusMessage* msg) +{ + DBusError err; + dbus_error_init(&err); + + int uid; + int ret = STTD_ERROR_OPERATION_FAILED; + dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &uid, DBUS_TYPE_INVALID); + + SLOG(LOG_DEBUG, TAG_STTD, ">>>>> STT Cancel File"); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_STTD, "[IN ERROR] stt cancel file : get arguments error (%s)", err.message); + dbus_error_free(&err); + ret = STTD_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_STTD, "[IN] stt cancel file : uid(%d)", uid); + ret = sttd_server_cancel_file(uid); + } + + if (0 <= ret) { + SLOG(LOG_DEBUG, TAG_STTD, "[OUT SUCCESS] Result(%d)", ret); + } else { + SLOG(LOG_ERROR, TAG_STTD, "[OUT ERROR] Result(%d)", ret); + if (0 != sttdc_send_error_signal(uid, ret, "[ERROR] Fail to cancel")) { + SLOG(LOG_ERROR, TAG_STTD, "[ERROR] Fail to send error signal"); + } + } + SLOG(LOG_DEBUG, TAG_STTD, "<<<<<"); + SLOG(LOG_DEBUG, TAG_STTD, " "); + + return 0; +} diff --git a/server/sttd_dbus_server.h b/server/sttd_dbus_server.h index 6e7c16d..da21771 100644 --- a/server/sttd_dbus_server.h +++ b/server/sttd_dbus_server.h @@ -68,6 +68,9 @@ int sttd_dbus_server_stop(DBusConnection* conn, DBusMessage* msg); int sttd_dbus_server_cancel(DBusConnection* conn, DBusMessage* msg); +int sttd_dbus_server_start_file(DBusConnection* conn, DBusMessage* msg); + +int sttd_dbus_server_cancel_file(DBusConnection* conn, DBusMessage* msg); #ifdef __cplusplus diff --git a/server/sttd_engine_agent.c b/server/sttd_engine_agent.c index 5e39973..b0e7071 100644 --- a/server/sttd_engine_agent.c +++ b/server/sttd_engine_agent.c @@ -837,6 +837,32 @@ int sttd_engine_agent_recognize_start_recorder(int uid) return 0; } +int sttd_engine_agent_recognize_start_file(int uid, const char* filepath) +{ + if (NULL == g_engine_info) { + SECURE_SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] The engine is not valid"); + return STTD_ERROR_INVALID_PARAMETER; + } + + if (false == g_engine_info->is_loaded) { + SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] Not loaded engine"); + return STTD_ERROR_OPERATION_FAILED; + } + + SLOG(LOG_DEBUG, TAG_STTD, "[Engine Agent] Start recorder"); + + int ret; + ret = sttd_recorder_start_file(uid, filepath); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] Fail to start recorder : result(%d)", ret); + stt_engine_recognize_cancel(); + sttd_recorder_stop_file(); + return ret; + } + + return 0; +} + int sttd_engine_agent_set_recording_data(const void* data, unsigned int length) { if (false == g_agent_init) { @@ -867,6 +893,41 @@ int sttd_engine_agent_set_recording_data(const void* data, unsigned int length) return ret; } +int sttd_engine_agent_recognize_stop_file() +{ + if (false == g_agent_init) { + SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] Not Initialized"); + return STTD_ERROR_OPERATION_FAILED; + } + + if (NULL == g_engine_info) { + SECURE_SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] The engine is not valid"); + return STTD_ERROR_INVALID_PARAMETER; + } + + if (false == g_engine_info->is_loaded) { + SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] Not loaded engine"); + return STTD_ERROR_OPERATION_FAILED; + } + + SLOG(LOG_DEBUG, TAG_STTD, "[Engine Agent] Stop recorder"); + int ret; + ret = sttd_recorder_stop_file(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Engine Agent ERROR] Fail to stop recorder : result(%d)", ret); + return ret; + } + +#ifdef AUDIO_CREATE_ON_START + SECURE_SLOG(LOG_DEBUG, TAG_STTD, "[Engine Agent] Destroy recorder"); + if (0 != sttd_recorder_destroy()) + SECURE_SLOG(LOG_WARN, TAG_STTD, "[Engine Agent] Fail to destroy recorder"); +#endif + + SLOG(LOG_DEBUG, TAG_STTD, "[Engine Agent Success] Stop recorder"); + return 0; +} + int sttd_engine_agent_recognize_stop_recorder() { if (false == g_agent_init) { diff --git a/server/sttd_engine_agent.h b/server/sttd_engine_agent.h index f44723d..58058be 100644 --- a/server/sttd_engine_agent.h +++ b/server/sttd_engine_agent.h @@ -98,10 +98,14 @@ int sttd_engine_agent_recognize_start_engine(int uid, const char* lang, const ch int sttd_engine_agent_recognize_start_recorder(int uid); +int sttd_engine_agent_recognize_start_file(int uid, const char* filepath); + int sttd_engine_agent_set_recording_data(const void* data, unsigned int length); int sttd_engine_agent_recognize_stop(); +int sttd_engine_agent_recognize_stop_file(); + int sttd_engine_agent_recognize_stop_recorder(); int sttd_engine_agent_recognize_stop_engine(); diff --git a/server/sttd_recorder.c b/server/sttd_recorder.c index 52b66ef..2d9a037 100644 --- a/server/sttd_recorder.c +++ b/server/sttd_recorder.c @@ -623,3 +623,70 @@ int sttd_recorder_stop() return 0; } + +int sttd_recorder_start_file(int uid, const char *filepath) +{ + if (STTD_RECORDER_STATE_RECORDING == g_recorder_state) + return 0; + + /* Check engine id is valid */ + if (NULL == g_recorder) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid"); + return STTD_ERROR_INVALID_PARAMETER; + } + g_recorder_state = STTD_RECORDER_STATE_RECORDING; + g_recorder->uid = uid; + + int cnt = 0; + int totalReadBytes = 0; + + FILE *infile = fopen(filepath, "rb"); + + //process the file + if (infile != NULL) { + while (!feof(infile)) { + static char pcm_buff[BUFFER_LENGTH]; + int read_byte = fread(pcm_buff, 1, BUFFER_LENGTH, infile); + totalReadBytes += read_byte; + if (0 != read_byte) { + if (0 != g_audio_cb(pcm_buff, read_byte)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to call audio callback"); + fclose(infile); + return -1; + } + if (0 == cnt % 30) { + float vol_db = get_volume_decibel(pcm_buff, BUFFER_LENGTH, g_recorder->audio_type); + if (0 != sttdc_send_set_volume(g_recorder->uid, vol_db)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder] Fail to send recording volume(%f)", vol_db); + } + } + + /* Audio read log */ + if (0 == cnt % 50) + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder][%d] Recording... : read_size(%d)", cnt, read_byte); + cnt++; + } + } + fclose(infile); + } + + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder][%d] total bytes(%d)", cnt, totalReadBytes); + return 0; +} + +int sttd_recorder_stop_file() +{ + if (STTD_RECORDER_STATE_READY == g_recorder_state) + return 0; + + /* Check engine id is valid */ + if (NULL == g_recorder) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid"); + return STTD_ERROR_INVALID_PARAMETER; + } + + g_recorder->uid = -1; + g_recorder_state = STTD_RECORDER_STATE_READY; + + return 0; +} diff --git a/server/sttd_recorder.h b/server/sttd_recorder.h index 946a283..3c27c87 100644 --- a/server/sttd_recorder.h +++ b/server/sttd_recorder.h @@ -42,6 +42,10 @@ int sttd_recorder_start(int uid); int sttd_recorder_stop(); +int sttd_recorder_start_file(int uid, const char *filepath); + +int sttd_recorder_stop_file(); + #ifdef __cplusplus } diff --git a/server/sttd_server.c b/server/sttd_server.c old mode 100755 new mode 100644 index f364cf3..8fcee24 --- a/server/sttd_server.c +++ b/server/sttd_server.c @@ -341,8 +341,8 @@ int __server_speech_status_callback(stte_speech_status_e status, void *user_para return STTD_ERROR_OPERATION_FAILED; } - if (APP_STATE_RECORDING != state) { - SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Current state is not recording"); + if (APP_STATE_RECORDING != state && APP_STATE_PROCESSING != state) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Current state is not recording, state(%d), status(%d)", state, status); return STTD_ERROR_INVALID_STATE; } @@ -1448,3 +1448,172 @@ int sttd_server_cancel(int uid) return STTD_ERROR_NONE; } + +int sttd_server_start_file(int uid, const char* lang, const char* recognition_type, int silence, const char* appid, const char* credential, + const char* filepath, stte_audio_type_e audio_type, int sample_rate) +{ + if (NULL == lang || NULL == recognition_type || NULL == filepath) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Input parameter is NULL"); + return STTD_ERROR_INVALID_PARAMETER; + } + + /* check if uid is valid */ + app_state_e state; + if (0 != sttd_client_get_state(uid, &state)) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] uid is NOT valid "); + return STTD_ERROR_INVALID_PARAMETER; + } + + /* check uid state */ + if (APP_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] sttd_server_start : current state is not ready"); + return STTD_ERROR_INVALID_STATE; + } + + int ret = 0; + if (false == stt_client_get_app_agreed(uid)) { + bool temp = false; + ret = sttd_engine_agent_check_app_agreed(appid, &temp); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to get engine available : %d", ret); + return ret; + } + + if (false == temp) { + SLOG(LOG_ERROR, TAG_STTD, "[Server] App(%s) NOT confirmed that engine is available", appid); + return STTD_ERROR_PERMISSION_DENIED; + } + + stt_client_set_app_agreed(uid); + } + + /* check if engine use network */ + if (true == sttd_engine_agent_need_network()) { + if (false == stt_network_is_connected()) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Disconnect network. Current engine needs to network connection."); + return STTD_ERROR_OUT_OF_NETWORK; + } + } + + if (0 != stt_client_set_current_recognition(uid)) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Current STT is busy because of recording or processing"); + return STTD_ERROR_RECORDER_BUSY; + } + + /* engine start recognition */ + SLOG(LOG_DEBUG, TAG_STTD, "[Server] start : uid(%d), lang(%s), recog_type(%s), appid(%s), file(%s), audio_type(%d), sample_rate(%d)", uid, lang, recognition_type, appid, filepath, audio_type, sample_rate); + + /* 1. Set audio session */ + ret = sttd_recorder_set_audio_session(); + if (0 != ret) { + stt_client_unset_current_recognition(); + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to set session : %d", ret); + return ret; + } + + /* 2. Start engine to recognize */ + ret = sttd_engine_agent_recognize_start_engine(uid, lang, recognition_type, silence, appid, credential, NULL); + if (0 != ret) { + stt_client_unset_current_recognition(); + sttd_recorder_unset_audio_session(); + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to start engine : result(%d)", ret); + return ret; + } + + sttd_client_set_state(uid, APP_STATE_RECORDING); + sttdc_send_set_state(uid, APP_STATE_RECORDING); + + /* 3. Start to send pcm from file to engine */ + ret = sttd_engine_agent_recognize_start_file(uid, filepath); + if (0 != ret) { + stt_client_unset_current_recognition(); + sttd_recorder_unset_audio_session(); + sttd_engine_agent_recognize_cancel(); + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to start file : result(%d)", ret); + return ret; + } + + /* 4. Stop to send pcm from file */ + ret = sttd_engine_agent_recognize_stop_file(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to stop recorder : result(%d)", ret); + stt_client_unset_current_recognition(); + sttd_recorder_unset_audio_session(); + sttd_engine_agent_recognize_cancel(); + return ret; + } + + /* 5. change & notify uid state */ + sttd_client_set_state(uid, APP_STATE_PROCESSING); + sttdc_send_set_state(uid, APP_STATE_PROCESSING); + + /* 6. Unset audio session */ + ret = sttd_recorder_unset_audio_session(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to unset session : %d", ret); + stt_client_unset_current_recognition(); + return ret; + } + + /* 7. Stop engine */ + ret = sttd_engine_agent_recognize_stop_engine(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to stop engine : result(%d)", ret); + stt_client_unset_current_recognition(); + return ret; + } + + return STTD_ERROR_NONE; +} + +int sttd_server_cancel_file(int uid) +{ + /* check if uid is valid */ + app_state_e state; + if (0 != sttd_client_get_state(uid, &state)) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] uid is NOT valid "); + return STTD_ERROR_INVALID_PARAMETER; + } + + /* check uid state */ + if (APP_STATE_READY == state) { + SLOG(LOG_WARN, TAG_STTD, "[Server WARNING] Current state is ready"); + return STTD_ERROR_NONE; + } + + stt_client_unset_current_recognition(); + + if (NULL != g_recording_timer) { + ecore_timer_del(g_recording_timer); + g_recording_timer = NULL; + } + + if (NULL != g_processing_timer) { + ecore_timer_del(g_processing_timer); + g_processing_timer = NULL; + } + + if (APP_STATE_RECORDING == state) { + /* Unset audio session */ + int ret = sttd_recorder_unset_audio_session(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to unset session : %d", ret); + return ret; + } + } + + /* change uid state */ + sttd_client_set_state(uid, APP_STATE_READY); + + /* cancel engine recognition */ + int ret = sttd_engine_agent_recognize_cancel(); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to cancel : result(%d)", ret); + return ret; + } + + /* Notify uid state change */ + sttdc_send_set_state(uid, APP_STATE_READY); + + return STTD_ERROR_NONE; +} diff --git a/server/sttd_server.h b/server/sttd_server.h index 0fd6dd9..72c231b 100644 --- a/server/sttd_server.h +++ b/server/sttd_server.h @@ -76,6 +76,9 @@ int sttd_server_stop(int uid); int sttd_server_cancel(int uid); +int sttd_server_start_file(int uid, const char* lang, const char* recognition_type, int silence, const char* appid, const char* credential, const char* filepath, stte_audio_type_e audio_type, int sample_rate); + +int sttd_server_cancel_file(int uid); #ifdef __cplusplus -- 2.7.4