From 0a2ac30711b29d638c6a5fd5e89506370b48a374 Mon Sep 17 00:00:00 2001 From: Kwangyoun Kim Date: Thu, 24 Nov 2016 19:18:54 +0900 Subject: [PATCH 1/1] Add internal method to get speech status info Change-Id: Ie07311ba2af1c29ab1cfe8f2be36d69869d8fa97 Signed-off-by: Kwangyoun Kim --- client/stt.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ client/stt_client.c | 4 ++ client/stt_client.h | 7 ++++ client/stt_dbus.c | 28 ++++++++++++++ common/stt_defs.h | 1 + include/CMakeLists.txt | 1 + include/stt_internal.h | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ packaging/stt.spec | 1 + server/sttd_dbus.c | 44 ++++++++++++++++++++++ server/sttd_dbus.h | 2 + server/sttd_server.c | 1 + 11 files changed, 281 insertions(+) create mode 100644 include/stt_internal.h diff --git a/client/stt.c b/client/stt.c index faf821f..4595139 100644 --- a/client/stt.c +++ b/client/stt.c @@ -30,6 +30,7 @@ #include "stt_client.h" #include "stt_dbus.h" #include "stt_config_mgr.h" +#include "stt_internal.h" #include "stt_main.h" @@ -1936,6 +1937,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; @@ -2190,3 +2231,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; +} \ No newline at end of file diff --git a/client/stt_client.c b/client/stt_client.c index e36e87e..793bfd7 100644 --- a/client/stt_client.c +++ b/client/stt_client.c @@ -68,6 +68,8 @@ int stt_client_new(stt_h* stt) client->error_user_data = NULL; client->default_lang_changed_cb = NULL; client->default_lang_changed_user_data = NULL; + client->speech_status_cb = NULL; + client->speech_status_user_data = NULL; client->current_engine_id = NULL; client->credential = NULL; @@ -88,6 +90,8 @@ int stt_client_new(stt_h* stt) client->internal_state = STT_INTERNAL_STATE_NONE; + client->speech_status = -1; + client->cb_ref_count = 0; g_client_list = g_list_append(g_client_list, client); diff --git a/client/stt_client.h b/client/stt_client.h index 2a89e2f..20c35d8 100644 --- a/client/stt_client.h +++ b/client/stt_client.h @@ -17,6 +17,7 @@ #include #include "stt.h" +#include "stt_internal.h" #include "stt_main.h" #ifdef __cplusplus @@ -55,6 +56,9 @@ typedef struct { stt_supported_language_cb supported_lang_cb; void* supported_lang_user_data; + stt_speech_status_cb speech_status_cb; + void* speech_status_user_data; + char* current_engine_id; char* credential; @@ -69,6 +73,9 @@ typedef struct { stt_internal_state_e internal_state; + /* speech status */ + int speech_status; + /* mutex */ int cb_ref_count; diff --git a/client/stt_dbus.c b/client/stt_dbus.c index 7337224..a143b71 100644 --- a/client/stt_dbus.c +++ b/client/stt_dbus.c @@ -43,6 +43,8 @@ extern int __stt_cb_set_state(int uid, int state); extern int __stt_cb_set_volume(int uid, float volume); +extern int __stt_cb_speech_status(int uid, int status); + char* __stt_get_service_name(char* engine_id) { char* service_name = NULL; @@ -587,6 +589,32 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle SLOG(LOG_DEBUG, TAG_STTC, " "); } /* STTD_METHOD_ERROR */ + else if (dbus_message_is_signal(msg, if_name, STTD_METHOD_SPEECH_STATUS)) { + SLOG(LOG_DEBUG, TAG_STTC, "===== Speech status"); + int uid = 0; + int status = -1; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &uid, + DBUS_TYPE_INT32, &status, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_STTC, "[ERROR] Get arguments error (%s)", err.message); + dbus_error_free(&err); + } + + if (uid > 0 && status >= 0) { + SLOG(LOG_DEBUG, TAG_STTC, "<<<< stt speech status : uid(%d), status(%d)", uid, status); + __stt_cb_speech_status(uid, status); + } else { + SLOG(LOG_ERROR, TAG_STTC, "<<<< stt set status : invalid uid or status"); + } + + SLOG(LOG_DEBUG, TAG_STTC, "====="); + SLOG(LOG_DEBUG, TAG_STTC, " "); + } /* STTD_METHOD_SPEECH_STATUS */ + else { SLOG(LOG_DEBUG, TAG_STTC, "Message is NOT valid"); dbus_message_unref(msg); diff --git a/common/stt_defs.h b/common/stt_defs.h index 08126c4..00f8522 100644 --- a/common/stt_defs.h +++ b/common/stt_defs.h @@ -74,6 +74,7 @@ extern "C" { #define STTD_METHOD_HELLO "sttd_method_hello" #define STTD_METHOD_SET_STATE "sttd_method_set_state" #define STTD_METHOD_SET_VOLUME "sttd_method_set_volume" +#define STTD_METHOD_SPEECH_STATUS "sttd_method_speech_status" /****************************************************************************************** diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index dfabff1..5bd87f7 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -10,6 +10,7 @@ INSTALL(FILES "${CMAKE_BINARY_DIR}/include/${PROJECT_NAME}-file.pc" DESTINATION INSTALL(FILES "${CMAKE_BINARY_DIR}/include/${PROJECT_NAME}-setting.pc" DESTINATION ${LIBDIR}/pkgconfig) INSTALL(FILES "${CMAKE_BINARY_DIR}/include/${PROJECT_NAME}-engine.pc" DESTINATION ${LIBDIR}/pkgconfig) INSTALL(FILES "${CMAKE_BINARY_DIR}/include/stt.h" DESTINATION ${INCLUDEDIR}) +INSTALL(FILES "${CMAKE_BINARY_DIR}/include/stt_internal.h" DESTINATION ${INCLUDEDIR}) INSTALL(FILES "${CMAKE_BINARY_DIR}/include/stt_file.h" DESTINATION ${INCLUDEDIR}) INSTALL(FILES "${CMAKE_BINARY_DIR}/include/stt_setting.h" DESTINATION ${INCLUDEDIR}) INSTALL(FILES "${CMAKE_BINARY_DIR}/include/stte.h" DESTINATION ${INCLUDEDIR}) diff --git a/include/stt_internal.h b/include/stt_internal.h new file mode 100644 index 0000000..d0b0e70 --- /dev/null +++ b/include/stt_internal.h @@ -0,0 +1,100 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STT_INTERNAL_H__ +#define __STT_INTERNAL_H__ + +#include + +/** + * @file stt_internal.h + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define STT_SPEECH_STATUS_BEGINNING_POINT_DETECTED 0 + +/** + * @brief Called when user speaking is detected. + * + * @param[in] stt The STT handle + * @param[in] status The speech status + * @param[in] user_data The user data passed from the callback registration function + * + * @pre An application registers callback function using stt_set_speech_status_cb(). + * + * @see stt_set_speech_status_cb() + * @see stt_unset_speech_status_cb() + */ +typedef void (*stt_speech_status_cb)(stt_h stt, int status, void *user_data); + + +/** + * @brief Registers a callback function to detect the speech status is changed. + * @since_tizen 3.0 + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] stt The STT handle + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * + * @return 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_NOT_SUPPORTED STT NOT supported + * @retval #STT_ERROR_PERMISSION_DENIED Permission denied + * + * @pre The state should be #STT_STATE_CREATED. + * + * @see stt_speech_status_cb() + * @see stt_unset_speech_status_cb() +*/ +int stt_set_speech_status_cb(stt_h stt, stt_speech_status_cb callback, void* user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] stt The STT handle + * + * @return 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_NOT_SUPPORTED STT NOT supported + * @retval #STT_ERROR_PERMISSION_DENIED Permission denied + * + * @pre The state should be #STT_STATE_CREATED. + * + * @see stt_set_speech_status_cb() +*/ +int stt_unset_speech_status_cb(stt_h stt); + +#ifdef __cplusplus +} +#endif + +/** + * @}@} + */ + +#endif /* __STT_INTERNAL_H__ */ + diff --git a/packaging/stt.spec b/packaging/stt.spec index 5746a07..358d33b 100644 --- a/packaging/stt.spec +++ b/packaging/stt.spec @@ -136,6 +136,7 @@ mkdir -p %{TZ_SYS_RO_SHARE}/voice/test %defattr(-,root,root,-) %{_libdir}/pkgconfig/stt.pc %{_includedir}/stt.h +%{_includedir}/stt_internal.h %files file-devel %defattr(-,root,root,-) diff --git a/server/sttd_dbus.c b/server/sttd_dbus.c index ac1ef00..c86aa5d 100644 --- a/server/sttd_dbus.c +++ b/server/sttd_dbus.c @@ -197,6 +197,50 @@ int sttdc_send_set_state(int uid, int state) return 0; } +int sttdc_send_speech_status(int uid, int status) +{ + int pid = sttd_client_get_pid(uid); + + if (0 > pid) { + SLOG(LOG_ERROR, TAG_STTD, "[Dbus ERROR] pid is NOT valid"); + return -1; + } + + char service_name[64]; + memset(service_name, 0, 64); + snprintf(service_name, 64, "%s%d", STT_CLIENT_SERVICE_NAME, pid); + + char target_if_name[128]; + snprintf(target_if_name, sizeof(target_if_name), "%s%d", STT_CLIENT_SERVICE_INTERFACE, pid); + + DBusMessage* msg = NULL; + msg = dbus_message_new_signal( + STT_CLIENT_SERVICE_OBJECT_PATH, /* object name of the signal */ + target_if_name, /* interface name of the signal */ + STTD_METHOD_SPEECH_STATUS); /* name of the signal */ + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_STTD, "[Dbus ERROR] Fail to create message"); + return -1; + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &uid, + DBUS_TYPE_INT32, &status, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_STTD, "[Dbus ERROR] Fail to send speech status message : Out Of Memory !"); + } else { + SLOG(LOG_DEBUG, TAG_STTD, "<<<< Send speech status message : uid(%d), status(%d)", uid, status); + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + + return 0; +} + int sttdc_send_result(int uid, int event, const char** data, int data_count, const char* result_msg) { int pid = sttd_client_get_pid(uid); diff --git a/server/sttd_dbus.h b/server/sttd_dbus.h index 91d81af..1f0d656 100644 --- a/server/sttd_dbus.h +++ b/server/sttd_dbus.h @@ -34,6 +34,8 @@ int sttdc_send_result(int uid, int event, const char** data, int data_count, con int sttdc_send_error_signal(int uid, int reason, const char *err_msg); +int sttdc_send_speech_status(int uid, int status); + #ifdef __cplusplus } diff --git a/server/sttd_server.c b/server/sttd_server.c index ea462df..d2f0bf2 100644 --- a/server/sttd_server.c +++ b/server/sttd_server.c @@ -335,6 +335,7 @@ int __server_speech_status_callback(stte_speech_status_e status, void *user_para if (STTE_SPEECH_STATUS_BEGINNING_POINT_DETECTED == status) { SLOG(LOG_DEBUG, TAG_STTD, "Begin Speech detected"); + sttdc_send_speech_status(uid, status); } else if (STTE_SPEECH_STATUS_END_POINT_DETECTED == status) { SLOG(LOG_DEBUG, TAG_STTD, "End Speech detected"); ecore_main_loop_thread_safe_call_async(__stop_by_silence, NULL); -- 2.7.4