From 3148014a7511856db9228c211cad9f4e80d103a4 Mon Sep 17 00:00:00 2001 From: Wonnam Jang Date: Tue, 15 Mar 2016 15:48:05 +0900 Subject: [PATCH] sync codes to 2.4 spin Change-Id: Icb0193f9686d1dd7368a5f7f53b88107e3e19a0d Signed-off-by: Wonnam Jang --- CMakeLists.txt | 3 +- changelog | 8 +- client/tts.c | 296 ++++++++---------------- client/tts_client.c | 3 + client/tts_dbus.c | 40 +--- common/tts_config_mgr.c | 18 +- doc/images/capi_uix_tts_state_diagram.png | Bin 37015 -> 71504 bytes doc/uix_tts_doc.h | 18 +- packaging/tts.spec | 6 +- server/ttsd_data.cpp | 196 ++++++++++------ server/ttsd_data.h | 10 +- server/ttsd_dbus.c | 48 ++-- server/ttsd_dbus_server.c | 2 +- server/ttsd_engine_agent.c | 106 +++++++-- server/ttsd_player.c | 362 ++++++++++++++++++++++++------ server/ttsd_player.h | 2 + server/ttsd_server.c | 220 ++++++++++++++---- server/ttsp.h | 63 +++++- test/CMakeLists.txt | 5 +- test/test_main.c | 144 +++++++----- 20 files changed, 992 insertions(+), 558 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c32051d..7698a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,8 @@ PROJECT(tts) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(EXEC_PREFIX "${PREFIX}") -SET(VERSION 0.2.41) +SET(INCLUDEDIR "${PREFIX}/include") +SET(VERSION 0.2.43) IF (LIBDIR MATCHES "/usr/lib64") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLIB64") diff --git a/changelog b/changelog index b96985c..1718976 100644 --- a/changelog +++ b/changelog @@ -1,8 +1,14 @@ +tts (0.2.43) -- Wed, 29 Jul 2015 + + * Update utt message to change method call to signal (Dongyeol Lee ) + * Support dbus activation for daemon start (Dongyeol Lee ) + * Move default config file to /usr/share/voice/tts (Dongyeol Lee ) + * Move test program to /usr/share/voice/test (Dongyeol Lee ) + tts (0.2.42) -- Fri, 29 May 2015 * Update utt message to change file message to dbus ipc (Dongyeol Lee ) * Remove unused smack label (Kwangyoun Kim ) - * Upgate utt message IPC based on signal (Dongyeol Lee ) tts (0.2.41) -- Sat, 13 Aug 2014 diff --git a/client/tts.c b/client/tts.c index 7e327cb..59ae6b2 100644 --- a/client/tts.c +++ b/client/tts.c @@ -31,6 +31,8 @@ static Ecore_Timer* g_connect_timer = NULL; static bool g_screen_reader; +static int g_feature_enabled = -1; + /* Function definition */ static Eina_Bool __tts_notify_state_changed(void *data); static Eina_Bool __tts_notify_error(void *data); @@ -40,6 +42,30 @@ 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) { @@ -80,7 +106,7 @@ static int __tts_convert_config_error_code(tts_config_error_e 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) { 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); + before_lang, before_voice_type, language, voice_type); GList* client_list = NULL; client_list = tts_client_get_client_list(); @@ -110,12 +136,8 @@ void __tts_config_voice_changed_cb(const char* before_lang, int before_voice_typ 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"); @@ -168,12 +190,8 @@ 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"); @@ -266,12 +284,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"); @@ -325,12 +339,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"); @@ -435,12 +445,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"); @@ -473,12 +479,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"); @@ -559,12 +561,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"); @@ -618,12 +616,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"); @@ -662,12 +656,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) { @@ -695,12 +685,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) { @@ -730,12 +716,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) { @@ -759,12 +741,18 @@ int tts_get_speed_range(tts_h tts, int* min, int* normal, int* max) 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"); @@ -887,12 +875,8 @@ int tts_add_text(tts_h tts, const char* text, const char* language, int voice_ty 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, "===== Play tts"); @@ -962,12 +946,8 @@ int tts_play(tts_h tts) int tts_stop(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"); @@ -1037,12 +1017,8 @@ int tts_stop(tts_h tts) int tts_pause(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"); @@ -1210,30 +1186,6 @@ int __tts_cb_set_state(int uid, int state) return 0; } -static Eina_Bool __tts_notify_utt_started(void *data) -{ - tts_h tts = (tts_h)data; - - tts_client_s* client = tts_client_get(tts); - - /* check handle */ - if (NULL == client) { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to notify utt started : A handle is not valid"); - return EINA_FALSE; - } - - if (NULL != client->utt_started_cb) { - SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance started "); - tts_client_use_callback(client); - client->utt_started_cb(client->tts, client->utt_id, client->utt_started_user_data); - tts_client_not_use_callback(client); - } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance started "); - } - - return EINA_FALSE; -} - int __tts_cb_utt_started(int uid, int utt_id) { tts_client_s* client = tts_client_get_by_uid(uid); @@ -1249,36 +1201,15 @@ int __tts_cb_utt_started(int uid, int utt_id) /* call callback function */ if (NULL != client->utt_started_cb) { - ecore_timer_add(0, __tts_notify_utt_started, client->tts); - } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance started "); - } - - return 0; -} - -static Eina_Bool __tts_notify_utt_completed(void *data) -{ - tts_h tts = (tts_h)data; - - tts_client_s* client = tts_client_get(tts); - - /* check handle */ - if (NULL == client) { - SLOG(LOG_WARN, TAG_TTSC, "[WARNING] Fail to notify utt completed : A handle is not valid"); - return EINA_FALSE; - } - - if (NULL != client->utt_completeted_cb) { - SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance completed "); + SLOG(LOG_DEBUG, TAG_TTSC, "Call callback function of utterance started "); tts_client_use_callback(client); - client->utt_completeted_cb(client->tts, client->utt_id, client->utt_completed_user_data); + client->utt_started_cb(client->tts, client->utt_id, client->utt_started_user_data); tts_client_not_use_callback(client); } else { - SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance completed "); + SLOG(LOG_WARN, TAG_TTSC, "No registered callback function of utterance started "); } - return EINA_FALSE; + return 0; } int __tts_cb_utt_completed(int uid, int utt_id) @@ -1296,7 +1227,10 @@ int __tts_cb_utt_completed(int uid, int 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 "); } @@ -1306,12 +1240,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) { @@ -1341,12 +1271,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) { @@ -1376,12 +1302,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) { @@ -1411,12 +1333,8 @@ int tts_set_utterance_started_cb(tts_h tts, tts_utterance_started_cb callback, v 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) { @@ -1446,12 +1364,8 @@ int tts_unset_utterance_started_cb(tts_h tts) 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) { @@ -1481,12 +1395,8 @@ int tts_set_utterance_completed_cb(tts_h tts, tts_utterance_completed_cb callbac 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) { @@ -1515,12 +1425,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) { @@ -1550,12 +1456,8 @@ int tts_set_error_cb(tts_h tts, tts_error_cb callback, void* user_data) 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) { @@ -1585,12 +1487,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) { @@ -1620,12 +1518,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) { diff --git a/client/tts_client.c b/client/tts_client.c index bd03627..75718bf 100644 --- a/client/tts_client.c +++ b/client/tts_client.c @@ -112,6 +112,9 @@ int tts_client_destroy(tts_h tts) free(data); free(tts); + SLOG(LOG_DEBUG, TAG_TTSC, "Client destroy"); + g_list_free(iter); + return TTS_ERROR_NONE; } diff --git a/client/tts_dbus.c b/client/tts_dbus.c index 16c5eea..b6fe537 100644 --- a/client/tts_dbus.c +++ b/client/tts_dbus.c @@ -94,7 +94,7 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle if (0 == __tts_cb_utt_completed(uid, uttid)) { SLOG(LOG_DEBUG, TAG_TTSC, "<<<< tts utterance completed : uid(%d) uttid(%d)", uid, uttid); } - } /* TTSD_METHOD_UTTERANCE_COMPLETED */ + } /* TTS_SIGNAL_UTTERANCE_STARTED */ else if (dbus_message_is_signal(msg, if_name, TTSD_METHOD_SET_STATE)) { int uid = 0; @@ -109,7 +109,7 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle if (0 == __tts_cb_set_state(uid, state)) { SLOG(LOG_DEBUG, TAG_TTSC, "<<<< tts state changed : uid(%d) state(%d)", uid, state); } - } /* TTSD_METHOD_SET_STATE */ + } /* TTSD_SIGNAL_SET_STATE */ else if (dbus_message_is_signal(msg, if_name, TTSD_METHOD_ERROR)) { int uid; @@ -130,7 +130,7 @@ static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handle if (0 == __tts_cb_error(uid, reason, uttid)) { SLOG(LOG_ERROR, TAG_TTSC, "<<<< Get Error message : uid(%d), error(%d), uttid(%d)", uid, reason, uttid); } - } /* TTSD_METHOD_ERROR */ + } /* TTSD_SIGNAL_ERROR */ /* free the message */ dbus_message_unref(msg); @@ -175,25 +175,8 @@ int tts_dbus_open_connection() return TTS_ERROR_OPERATION_FAILED; } -#if 0 - int pid = getpid(); - - char service_name[64]; - memset(service_name, 0, 64); - snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid); - - SLOG(LOG_DEBUG, TAG_TTSC, "Service name is %s", service_name); - - /* register our name on the bus, and check for errors */ - dbus_bus_request_name(g_conn_listener, service_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); - if (dbus_error_is_set(&err)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Name Error (%s)", err.message); - dbus_error_free(&err); - } -#endif char rule[128] = {0, }; snprintf(rule, 128, "type='signal',interface='%s'", TTS_CLIENT_SERVICE_INTERFACE); - SLOG(LOG_DEBUG, TAG_TTSC, "rule is %s", rule); /* add a rule for which messages we want to see */ dbus_bus_add_match(g_conn_listener, rule, &err); @@ -225,20 +208,13 @@ int tts_dbus_close_connection() ecore_main_fd_handler_del(g_dbus_fd_handler); g_dbus_fd_handler = NULL; } -#if 0 - int pid = getpid(); - char service_name[64]; - memset(service_name, 0, 64); - snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid); - snprintf(service_name, 64, "%s", TTS_CLIENT_SERVICE_NAME); + dbus_connection_close(g_conn_sender); + dbus_connection_close(g_conn_listener); + + dbus_connection_unref(g_conn_sender); + dbus_connection_unref(g_conn_listener); - dbus_bus_release_name(g_conn_listener, service_name, &err); - if (dbus_error_is_set(&err)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Release name error (%s)", err.message); - dbus_error_free(&err); - } -#endif g_conn_sender = NULL; g_conn_listener = NULL; diff --git a/common/tts_config_mgr.c b/common/tts_config_mgr.c index 371cdbf..842df9a 100644 --- a/common/tts_config_mgr.c +++ b/common/tts_config_mgr.c @@ -124,8 +124,8 @@ int __tts_config_mgr_check_engine_is_valid(const char* engine_id) g_config_info->type = voice->type; SLOG(LOG_DEBUG, tts_tag(), "Default voice is changed : lang(%s) type(%d)", voice->language, voice->type); + break; } - break; } } } @@ -637,7 +637,7 @@ void __tts_config_screen_reader_changed_cb(keynode_t *key, void *data) { int ret; int screen_reader; - ret = vconf_get_int(TTS_ACCESSIBILITY_KEY, &screen_reader); + ret = vconf_get_bool(TTS_ACCESSIBILITY_KEY, &screen_reader); if (0 != ret) { SLOG(LOG_ERROR, tts_tag(), "[Config ERROR] Fail to get screen reader"); return; @@ -1283,8 +1283,10 @@ int tts_config_mgr_set_engine(const char* engine) return TTS_CONFIG_ERROR_INVALID_PARAMETER; /* Check current engine id with new engine id */ - if (0 == strcmp(g_config_info->engine_id, engine)) - return 0; + if (NULL != g_config_info->engine_id) { + if (0 == strcmp(g_config_info->engine_id, engine)) + return 0; + } if (0 >= g_slist_length(g_engine_list)) { SLOG(LOG_ERROR, tts_tag(), "[ERROR] There is no engine!!"); @@ -1347,13 +1349,7 @@ int tts_config_mgr_set_engine(const char* engine) if (voice->type == g_config_info->type) { /* language is valid */ is_valid_voice = true; - - if (NULL != g_config_info->language) { - free(g_config_info->language); - - g_config_info->language = strdup(voice->language); - g_config_info->type = voice->type; - } + g_config_info->type = voice->type; } break; } diff --git a/doc/images/capi_uix_tts_state_diagram.png b/doc/images/capi_uix_tts_state_diagram.png index 83efe114fe2a67c72dac992153ad2ae185958995..81e959a931705b7469718ff543898725bb37820a 100644 GIT binary patch literal 71504 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 z zF?x+3zTZ;-bKeFb2s$npUcxp~XxRuQa^wC6%-)rQv1@#>V!Io>y>+p}%*;%bmzQ@f z^6HOlpPtZf0)WsL0`z?|XhC;~G~J2CXRY*kNjgug3f}XgGZ+Uc&jr zdBxx`<7#nnu?P(CgRP?rW~}#=yXyUDR}3@XM(hc1m-ChL*4TVLpTu^Ntc2oA#!t8S zck4nidxIMsoc19o&|hwr!;DJC4yi<+ZRSt(s{kO_Sdt13(;dRN09`_nkrD9s^^weT z#yU5ACjaLy%y&Cuzqbd% z!a}9Xhl?^8w9*guYRq4QhBJraC7f4`3ox!m7i(%tima%+-^UAE_qbrv8V@l)!|{W4 z0oHpT!;awN*em8Q=P~EAv3Y(jNb-_S&%t)lrgdIN@x4`^;CrE%yv7YXZCwOE^hQKP zIMUKmrN5uC59RMa7rdn31%Lt@t|U0kI7)Cv_F4BMEHo6pqVsmyI%Cd8AqZCcW6IVP zEOoBLCZTEX3_Srm`pVdW;?q{VKpXKw&j#_@yvJS&9zj;&9oQVuj1_K&F>7Zw#;gyK z1I&DvGrT<9q$NWwgzhbxru5O#U#VO^XS>5RXc%nZoKh|!&NsS8XbmJJ#3Lj)7~WnU zLJ&A(+IkO+7E0xe?U`7y*gQkPzt|q1I0i0{NuAzyDnDlCvfN2tELX03|r38vWxeBuAGC)0>nauyt_3 z(ygxe=4VfQyCwv4t#YwkFkqT>TLX_{S7^JGqI{`RqLVsbx^+a~NOq9wBy}x8R^brV zN1N!VW~}l!BFxDWjM)%{;Xird2QznUw|0TIr@JuG0udV)aWV;mf?&6u3+9`<;j5oKF=lCw+SoV>V!p-kCAIa1z+>PA`3U{*-OUnDTNl-OerOj z&!RF0&owVOs{(-F!>G=qH9%L1>b!1(z;{2~++4ABw5zk@AQIPPrTLW9=fLP;s6pI|nrN%I3eFQ#V<}I{+ zPi)xX3?~;C_;`CESPZPV*jO2up^3)027Qv}T2gD!Fxa8ynz9C{fKd_SyzCMLA;H-1 z;|-U6F4(lw3Deej;)|tT_-v1$KnX|_h-(L;qoNQP7$79MC!7TX-e%>5B^EB2wANDy1Rs2}DiD)4$6?yG zbeRFL#IX`9-H%|cR|D313gV~!|2scdiF1}ZR|$z+Bz~JAchMiYCKz8V^O2cJ^EbJQ z!Qu#eCuevHZQtMDPwrNfn3yOB76%yp{ABzpy;IZrHE1|L(B~x-1e}*-revyADw#hY z84-bi0Dn239i3cYvC9z)%=XE&?Jor{8M!tDQ#L0`elSn)g{98bSZ&Bl^glcQPkyt+ zsSk-3Xt`i^jNc7d0$NZ5v`$VeG4WZS6tD(?Z?el~LZ zPX*^p04V5po)QEM6w?RBg&$7(ao$?;A?dKckTmUE-3IZ}%CCSNn`O+v1Qc{v-(3LMVI4B5ye!jv&@PeD08}!ZzLX|u(4fI|V8}}tZ{+;tJf??%!hno8IXOwj@u=u={*w<-`Rm3@I(bGM*;Mp_|#izHmkCR7!e7QXNC$Z}?kYgV)k$_!`sKpkd%apO5GZgr0Z_`Gqk)qLf8_UP5NC zc!}as`h4U<;3Xz001To3LRClVlj_u-NT12;(}mJW8Z>C=AN0mcdgCMd4Bn9RuX&;2 zf)D^FgMJ6}L>e?`(9j!<@eM;7Xc!OzK!XMi8Z?|bGy$MNg9Z(Q6q*3gph1I%K?&gh Y1Beiis09t%=>Px#07*qoM6N<$f`dE9_5c6? literal 37015 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 V)CovdRsjLe3ENYI$JV68e*vR15>WsE diff --git a/doc/uix_tts_doc.h b/doc/uix_tts_doc.h index 6c9b53a..03446f6 100644 --- a/doc/uix_tts_doc.h +++ b/doc/uix_tts_doc.h @@ -27,10 +27,10 @@ * \#include * * @section CAPI_UIX_TTS_MODULE_OVERVIEW Overview - * A main function of Text-To-Speech(below TTS) API reads sound data transformed by the engine using input texts. - * Applications can add input-text to queue for reading continuously and control a player that can play, pause, and stop sound data synthesized from text. + * You can use Text-To-Speech (TTS) API to read sound data transformed by the engine from input texts. + * Applications can add input-text to queue for reading continuously and control the player that can play, pause, and stop sound data synthesized from text. * - * To use of TTS, use the following steps:
+ * To use TTS, follow these steps:
* 1. Create a handle
* 2. Register callback functions for notifications
* 3. Prepare tts-daemon asynchronously
@@ -47,11 +47,21 @@ * tts_utterance_completed_cb(), tts_default_voice_changed_cb(), tts_error_cb(). * * @section CAPI_UIX_TTS_MODULE_STATE_DIAGRAM State Diagram - * The following diagram shows the life cycle and the states of the TTS. + * The following diagram shows the life cycle and the states of the TTS. + * This state diagram shows that the state can be changed from 'None' to 'Created' by calling the tts_create() function. + * Similarly, you can know the relation between the states and API functions. + * You need to know the current state before calling the API, because the TTS API is based on state machine. + * The current state can be known from the state changed callback. * * @image html capi_uix_tts_state_diagram.png "State diagram" * * @section CAPI_UIX_TTS_MODULE_STATE_TRANSITIONS State Transitions + * The following table shows previous state and post state of main function. + * It can be known what precondition is and which synchronous type is. + * Please check both previous state and post state from the table carefully. + * In case of tts_prepare() function, state doesn't be changed at once, but acynchronously. + * From the above state diagram, you can see dotted line as asynchronous api. + * In this case, the state changed callback is only way to know state transition as ready. * * * diff --git a/packaging/tts.spec b/packaging/tts.spec index 433d2b5..9658a69 100644 --- a/packaging/tts.spec +++ b/packaging/tts.spec @@ -1,6 +1,6 @@ Name: tts Summary: Text To Speech client library and daemon -Version: 0.2.42 +Version: 0.2.43 Release: 1 Group: Graphics & UI Framework/Voice Framework License: Apache-2.0 @@ -83,7 +83,7 @@ install LICENSE %{buildroot}/usr/share/license/%{name} mkdir -p %{_libdir}/voice -mkdir -p /usr/share/voice +mkdir -p /usr/share/voice/test mkdir -p /opt/usr/data/voice/tts/1.0/engine-info @@ -102,7 +102,7 @@ chown 5000:5000 /opt/usr/data/voice/tts/1.0/engine-info %{_bindir}/tts-daemon* /usr/share/dbus-1/system-services/org.tizen.voice* /etc/dbus-1/system.d/tts-server.conf -/opt/usr/devel/bin/tts-test +/usr/share/voice/test/tts-test /usr/share/license/%{name} %files devel diff --git a/server/ttsd_data.cpp b/server/ttsd_data.cpp index e295294..7270e65 100644 --- a/server/ttsd_data.cpp +++ b/server/ttsd_data.cpp @@ -11,7 +11,10 @@ * limitations under the License. */ +#include +#include #include + #include "ttsd_main.h" #include "ttsd_data.h" @@ -30,19 +33,19 @@ typedef struct int utt_id_stopped; app_state_e state; - std::vector m_speak_data; - std::vector m_wav_data; + std::list m_speak_data; + std::list m_wav_data; - std::vector m_used_voice; + std::list m_used_voice; }app_data_s; static vector g_app_list; +static pthread_mutex_t g_sound_data_mutex = PTHREAD_MUTEX_INITIALIZER; /* * functions for debug */ - int __data_show_list() { int vsize = g_app_list.size(); @@ -66,10 +69,12 @@ int __data_show_sound_list(int index) { SLOG(LOG_DEBUG, get_tag(), "----- Sound list -----"); - unsigned int i; - for (i=0 ; i < g_app_list[index].m_wav_data.size() ; i++) { - SECURE_SLOG(LOG_DEBUG, get_tag(), "[%dth] data size(%ld), uttid(%d), type(%d)", - i+1, g_app_list[index].m_wav_data[i].data_size, g_app_list[index].m_wav_data[i].utt_id, g_app_list[index].m_wav_data[i].audio_type); + unsigned int i = 0; + std::list::iterator iter; + for (iter = g_app_list[index].m_wav_data.begin(); iter != g_app_list[index].m_wav_data.end(); iter++) { + SLOG(LOG_DEBUG, get_tag(), "[%dth][%p] data(%p) data size(%ld), uttid(%d), type(%d)", + i, *iter, (*iter)->data, (*iter)->data_size, (*iter)->utt_id, (*iter)->audio_type); + i++; } if (i == 0) { @@ -84,11 +89,12 @@ int __data_show_text_list(int index) { SLOG(LOG_DEBUG, get_tag(), "----- Text list -----"); - unsigned int i; - for (i=0 ; i< g_app_list[index].m_speak_data.size() ; i++) { - SECURE_SLOG(LOG_DEBUG, get_tag(), "[%dth] lang(%s), vctype(%d), speed(%d), uttid(%d), text(%s)", - i+1, g_app_list[index].m_speak_data[i].lang, g_app_list[index].m_speak_data[i].vctype, g_app_list[index].m_speak_data[i].speed, - g_app_list[index].m_speak_data[i].utt_id, g_app_list[index].m_speak_data[i].text); + unsigned int i = 0; + std::list::iterator iter; + for (iter = g_app_list[index].m_speak_data.begin(); iter != g_app_list[index].m_speak_data.end(); iter++) { + SLOG(LOG_DEBUG, get_tag(), "[%dth][%p] lang(%s), vctype(%d), speed(%d), uttid(%d), text(%s)", + i + 1, *iter, (*iter)->lang, (*iter)->vctype, (*iter)->speed, (*iter)->utt_id, (*iter)->text); + i++; } if (0 == i) { @@ -101,19 +107,20 @@ int __data_show_text_list(int index) int __data_show_used_voice_list(int index) { - SLOG(LOG_DEBUG, get_tag(), "----- Voice list -----"); + SLOG(LOG_DEBUG, get_tag(), "----- Used voice list -----"); - unsigned int i; - for (i=0 ; i< g_app_list[index].m_speak_data.size() ; i++) { - SECURE_SLOG(LOG_DEBUG, get_tag(), "[%dth] lang(%s), vctype(%d)", - i+1, g_app_list[index].m_used_voice[i].lang, g_app_list[index].m_used_voice[i].vctype); + unsigned int i = 0; + std::list::iterator iter; + for (iter = g_app_list[index].m_used_voice.begin(); iter != g_app_list[index].m_used_voice.end(); iter++) { + SLOG(LOG_DEBUG, get_tag(), "[%dth] lang(%s), vctype(%d)", i + 1, iter->lang, iter->vctype); + i++; } if (0 == i) { SLOG(LOG_DEBUG, get_tag(), "No Voice Data"); } - SLOG(LOG_DEBUG, get_tag(), "---------------------"); + SLOG(LOG_DEBUG, get_tag(), "---------------------------"); return TTSD_ERROR_NONE; } @@ -223,12 +230,10 @@ int ttsd_data_set_used_voice(int uid, const char* lang, int type) } /* Find voice */ - int vsize = g_app_list[index].m_used_voice.size(); - int i = 0; + std::list::iterator iter; - for (i = 0;i < vsize;i++) { - if (0 == strcmp(lang, g_app_list[index].m_used_voice[i].lang) && - type == g_app_list[index].m_used_voice[i].vctype) { + for (iter = g_app_list[index].m_used_voice.begin();iter != g_app_list[index].m_used_voice.end();iter++) { + if (0 == strcmp(lang, iter->lang) && type == iter->vctype) { SLOG(LOG_DEBUG, get_tag(), "[DATA] The voice is already registered (%s)(%d)", lang, type); return 0; } @@ -258,28 +263,33 @@ int ttsd_data_reset_used_voice(int uid, ttsd_used_voice_cb callback) return TTSD_ERROR_INVALID_PARAMETER; } + if (NULL == callback) { + SLOG(LOG_WARN, get_tag(), "[DATA WARNING] Used voice callback is NULL"); + } + /* Find voice */ - int vsize = g_app_list[index].m_used_voice.size(); - int i = 0; + std::list::iterator iter; - for (i = 0;i < vsize;i++) { + for (iter = g_app_list[index].m_used_voice.begin(); iter != g_app_list[index].m_used_voice.end(); iter++) { if (NULL != callback) { - callback(g_app_list[index].m_used_voice[i].lang, g_app_list[index].m_used_voice[i].vctype); - } else { - SECURE_SLOG(LOG_WARN, get_tag(), "[DATA WARNING] Used voice callback is NULL"); + callback(iter->lang, iter->vctype); } - if (NULL != g_app_list[index].m_used_voice[i].lang) { - free(g_app_list[index].m_used_voice[i].lang); + if (NULL != iter->lang) { + free(iter->lang); } } g_app_list[index].m_used_voice.clear(); +#ifdef DATA_DEBUG + __data_show_used_voice_list(index); +#endif + return TTSD_ERROR_NONE; } -int ttsd_data_add_speak_data(int uid, speak_data_s data) +int ttsd_data_add_speak_data(int uid, speak_data_s* data) { int index = 0; index = ttsd_data_is_client(uid); @@ -291,7 +301,7 @@ int ttsd_data_add_speak_data(int uid, speak_data_s data) g_app_list[index].m_speak_data.insert(g_app_list[index].m_speak_data.end(), data); - if (1 == data.utt_id) + if (1 == data->utt_id) g_app_list[index].utt_id_stopped = 0; #ifdef DATA_DEBUG @@ -300,7 +310,7 @@ int ttsd_data_add_speak_data(int uid, speak_data_s data) return TTSD_ERROR_NONE; } -int ttsd_data_get_speak_data(int uid, speak_data_s* data) +int ttsd_data_get_speak_data(int uid, speak_data_s** data) { int index = 0; index = ttsd_data_is_client(uid); @@ -317,14 +327,9 @@ int ttsd_data_get_speak_data(int uid, speak_data_s* data) return -1; } - data->lang = g_strdup(g_app_list[index].m_speak_data[0].lang); - data->vctype = g_app_list[index].m_speak_data[0].vctype; - data->speed = g_app_list[index].m_speak_data[0].speed; - - data->text = g_app_list[index].m_speak_data[0].text; - data->utt_id = g_app_list[index].m_speak_data[0].utt_id; - - g_app_list[index].m_speak_data.erase(g_app_list[index].m_speak_data.begin()); + std::list::iterator iter = g_app_list[index].m_speak_data.begin(); + *data = *iter; + g_app_list[index].m_speak_data.pop_front(); #ifdef DATA_DEBUG __data_show_text_list(index); @@ -332,7 +337,7 @@ int ttsd_data_get_speak_data(int uid, speak_data_s* data) return TTSD_ERROR_NONE; } -int ttsd_data_add_sound_data(int uid, sound_data_s data) +int ttsd_data_add_sound_data(int uid, sound_data_s* data) { int index = 0; index = ttsd_data_is_client(uid); @@ -342,15 +347,26 @@ int ttsd_data_add_sound_data(int uid, sound_data_s data) return TTSD_ERROR_INVALID_PARAMETER; } + if (NULL == data) { + SLOG(LOG_ERROR, get_tag(), "[DATA ERROR] sound data is NULL"); + return TTSD_ERROR_INVALID_PARAMETER; + } + /* mutex is locked */ + pthread_mutex_lock(&g_sound_data_mutex); + g_app_list[index].m_wav_data.insert(g_app_list[index].m_wav_data.end(), data); #ifdef DATA_DEBUG __data_show_sound_list(index); #endif + + /* mutex is unlocked */ + pthread_mutex_unlock(&g_sound_data_mutex); + return TTSD_ERROR_NONE; } -int ttsd_data_get_sound_data(int uid, sound_data_s* data) +int ttsd_data_get_sound_data(int uid, sound_data_s** data) { int index = 0; index = ttsd_data_is_client(uid); @@ -360,26 +376,29 @@ int ttsd_data_get_sound_data(int uid, sound_data_s* data) return TTSD_ERROR_INVALID_PARAMETER; } + /* mutex is locked */ + pthread_mutex_lock(&g_sound_data_mutex); + if (0 == g_app_list[index].m_wav_data.size()) { #ifdef DATA_DEBUG SLOG(LOG_DEBUG, get_tag(), "[DATA] There is no wav data"); #endif + /* mutex is unlocked */ + pthread_mutex_unlock(&g_sound_data_mutex); return -1; } - data->data = g_app_list[index].m_wav_data[0].data; - data->data_size = g_app_list[index].m_wav_data[0].data_size; - data->utt_id = g_app_list[index].m_wav_data[0].utt_id; - data->audio_type = g_app_list[index].m_wav_data[0].audio_type; - data->rate = g_app_list[index].m_wav_data[0].rate; - data->channels = g_app_list[index].m_wav_data[0].channels; - data->event = g_app_list[index].m_wav_data[0].event; - - g_app_list[index].m_wav_data.erase(g_app_list[index].m_wav_data.begin()); + std::list::iterator iter = g_app_list[index].m_wav_data.begin(); + *data = *iter; + g_app_list[index].m_wav_data.pop_front(); #ifdef DATA_DEBUG __data_show_sound_list(index); #endif + + /* mutex is unlocked */ + pthread_mutex_unlock(&g_sound_data_mutex); + return TTSD_ERROR_NONE; } @@ -407,17 +426,32 @@ int ttsd_data_clear_data(int uid) } int removed_last_uttid = -1; + speak_data_s* temp_speak = NULL; + sound_data_s* temp_sound = NULL; + /* free allocated data */ while(1) { - speak_data_s temp; - if (0 != ttsd_data_get_speak_data(uid, &temp)) { + if (0 != ttsd_data_get_speak_data(uid, &temp_speak)) { break; } - if (NULL != temp.text) free(temp.text); - if (NULL != temp.lang) free(temp.lang); + if (NULL != temp_speak) { + SLOG(LOG_DEBUG, get_tag(), "[DEBUG] utt(%d), text(%s), lang(%s), vctype(%d) speed(%d)", + temp_speak->utt_id, temp_speak->text, temp_speak->lang, temp_speak->vctype, temp_speak->speed); + + if (NULL != temp_speak->text) { + free(temp_speak->text); + temp_speak->text = NULL; + } + if (NULL != temp_speak->lang) { + free(temp_speak->lang); + temp_speak->lang = NULL; + } + removed_last_uttid = temp_speak->utt_id; - removed_last_uttid = temp.utt_id; + free(temp_speak); + temp_speak = NULL; + } } if (-1 != removed_last_uttid) { @@ -425,15 +459,21 @@ int ttsd_data_clear_data(int uid) } while(1) { - sound_data_s temp; - if (0 != ttsd_data_get_sound_data(uid, &temp)) { + if (0 != ttsd_data_get_sound_data(uid, &temp_sound)) { break; } - if (0 < temp.data_size) { - if (NULL != temp.data) free(temp.data); - } else { - SLOG(LOG_ERROR, get_tag(), "Sound data is NULL"); + if (NULL != temp_sound) { + SLOG(LOG_ERROR, get_tag(), "[DEBUG][%p] uid(%d), event(%d) data(%p) size(%d) rate(%d) utt(%d)", + temp_sound, uid, temp_sound->event, temp_sound->data, temp_sound->data_size, temp_sound->rate, temp_sound->utt_id); + + if (NULL != temp_sound->data) { + free(temp_sound->data); + temp_sound->data = NULL; + } + + free(temp_sound); + temp_sound = NULL; } } @@ -605,23 +645,33 @@ int ttsd_data_save_error_log(int uid, FILE* fp) unsigned int i; index = ttsd_data_is_client(uid); + if (0 > index) { + SLOG(LOG_ERROR, get_tag(), "[ERROR] Invalid client"); + return -1; + } /* get sound data */ fprintf(fp, "----- Sound list -----"); - - for (i=0 ; i < g_app_list[index].m_wav_data.size() ; i++) { - fprintf(fp, "[%dth] data size(%d), uttid(%d), type(%d)", - i+1, g_app_list[index].m_wav_data[i].data_size, g_app_list[index].m_wav_data[i].utt_id, g_app_list[index].m_wav_data[i].audio_type ); + + i = 0; + std::list::iterator iter; + for (iter = g_app_list[index].m_wav_data.begin(); iter != g_app_list[index].m_wav_data.end(); iter++) { + SLOG(LOG_DEBUG, get_tag(), "[%dth][%p] data(%p) data size(%ld), uttid(%d), type(%d)", + i, *iter, (*iter)->data, (*iter)->data_size, (*iter)->utt_id, (*iter)->audio_type); + i++; } + fprintf(fp, "----------------------"); /* get speck data */ fprintf(fp, "----- Text list -----"); - for (i=0 ; i< g_app_list[index].m_speak_data.size() ; i++) { - fprintf(fp, "[%dth] lang(%s), vctype(%d), speed(%d), uttid(%d), text(%s)", - i+1, g_app_list[index].m_speak_data[i].lang, g_app_list[index].m_speak_data[i].vctype, g_app_list[index].m_speak_data[i].speed, - g_app_list[index].m_speak_data[i].utt_id, g_app_list[index].m_speak_data[i].text ); + i = 0; + std::list::iterator iter_speak; + for (iter_speak = g_app_list[index].m_speak_data.begin(); iter_speak != g_app_list[index].m_speak_data.end(); iter_speak++) { + SLOG(LOG_DEBUG, get_tag(), "[%dth][%p] lang(%s), vctype(%d), speed(%d), uttid(%d), text(%s)", + i, *iter_speak, (*iter_speak)->lang, (*iter_speak)->vctype, (*iter_speak)->speed, (*iter_speak)->utt_id, (*iter_speak)->text); + i++; } fprintf(fp, "---------------------"); diff --git a/server/ttsd_data.h b/server/ttsd_data.h index 1c94ebf..8039e9e 100644 --- a/server/ttsd_data.h +++ b/server/ttsd_data.h @@ -62,16 +62,16 @@ int ttsd_data_get_client_count(); int ttsd_data_get_pid(int uid); /* speak data */ -int ttsd_data_add_speak_data(int uid, speak_data_s data); +int ttsd_data_add_speak_data(int uid, speak_data_s* data); -int ttsd_data_get_speak_data(int uid, speak_data_s* data); +int ttsd_data_get_speak_data(int uid, speak_data_s** data); int ttsd_data_get_speak_data_size(int uid); /* sound data */ -int ttsd_data_add_sound_data(int uid, sound_data_s data); +int ttsd_data_add_sound_data(int uid, sound_data_s* data); -int ttsd_data_get_sound_data(int uid, sound_data_s* data); +int ttsd_data_get_sound_data(int uid, sound_data_s** data); int ttsd_data_get_sound_data_size(int uid); @@ -95,8 +95,6 @@ int ttsd_data_foreach_clients(ttsd_data_get_client_cb callback, void* user_data) bool ttsd_data_is_uttid_valid(int uid, int uttid); -int ttsd_data_is_current_playing(); - int ttsd_data_get_same_pid_client_count(int pid); /* For error handing */ diff --git a/server/ttsd_dbus.c b/server/ttsd_dbus.c index f15c6d4..7ada226 100644 --- a/server/ttsd_dbus.c +++ b/server/ttsd_dbus.c @@ -27,7 +27,7 @@ static DBusConnection* g_conn_listener = NULL; static Ecore_Fd_Handler* g_dbus_fd_handler = NULL; -static int g_waiting_time = 3000; +//static int g_waiting_time = 3000; static char *g_service_name = NULL; static char *g_service_object = NULL; @@ -64,12 +64,10 @@ int ttsdc_send_hello(int pid, int uid) char service_name[64]; memset(service_name, 0, 64); - /*snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid); */ - snprintf(service_name, 64, "%s", TTS_CLIENT_SERVICE_NAME); + snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid); char target_if_name[64]; - /*snprintf(target_if_name, sizeof(target_if_name), "%s%d", TTS_CLIENT_SERVICE_INTERFACE, pid); */ - snprintf(target_if_name, sizeof(target_if_name), "%s", TTS_CLIENT_SERVICE_INTERFACE); + snprintf(target_if_name, sizeof(target_if_name), "%s%d", TTS_CLIENT_SERVICE_INTERFACE, pid); DBusMessage* msg; @@ -129,16 +127,12 @@ int ttsdc_send_message(int pid, int uid, int data, const char *method) return -1; } - char target_if_name[64]; - memset(target_if_name, 0, 64); - snprintf(target_if_name, sizeof(target_if_name), "%s", TTS_CLIENT_SERVICE_INTERFACE); - DBusMessage* msg = NULL; - /* create a message & check for errors */ + /* create a message */ msg = dbus_message_new_signal( TTS_CLIENT_SERVICE_OBJECT_PATH, /* object name of the signal */ - target_if_name, /* interface name of the signal */ + TTS_CLIENT_SERVICE_INTERFACE, /* interface name of the signal */ method); /* name of the signal */ if (NULL == msg) { @@ -158,6 +152,8 @@ int ttsdc_send_message(int pid, int uid, int data, const char *method) dbus_connection_flush(g_conn_sender); } + dbus_message_unref(msg); + return 0; } @@ -183,20 +179,13 @@ int ttsdc_send_error_message(int pid, int uid, int uttid, int reason) return -1; } - char service_name[64]; - memset(service_name, 0, 64); - snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid); - - char target_if_name[128]; - snprintf(target_if_name, sizeof(target_if_name), "%s%d", TTS_CLIENT_SERVICE_INTERFACE, pid); - - DBusMessage* msg; + DBusMessage* msg = NULL; - msg = dbus_message_new_method_call( - service_name, - TTS_CLIENT_SERVICE_OBJECT_PATH, - target_if_name, - TTSD_METHOD_ERROR); + /* create a message */ + msg = dbus_message_new_signal( + TTS_CLIENT_SERVICE_OBJECT_PATH, /* object name of the signal */ + TTS_CLIENT_SERVICE_INTERFACE, /* interface name of the signal */ + TTSD_METHOD_ERROR); /* name of the signal */ if (NULL == msg) { SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail to create error message : uid(%d)", uid); @@ -289,7 +278,7 @@ int ttsd_dbus_open_connection() int ret; /* Create connection for sender */ - g_conn_sender = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + g_conn_sender = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); if (dbus_error_is_set(&err)) { SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail dbus_bus_get : %s", err.message); dbus_error_free(&err); @@ -301,10 +290,11 @@ int ttsd_dbus_open_connection() } /* connect to the bus and check for errors */ - g_conn_listener = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + g_conn_listener = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); if (dbus_error_is_set(&err)) { SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail dbus_bus_get : %s", err.message); dbus_error_free(&err); + return -1; } if (NULL == g_conn_listener) { @@ -392,6 +382,12 @@ int ttsd_dbus_close_connection() dbus_error_free(&err); } + dbus_connection_close(g_conn_sender); + dbus_connection_close(g_conn_listener); + + dbus_connection_unref(g_conn_sender); + dbus_connection_unref(g_conn_listener); + g_conn_listener = NULL; g_conn_sender = NULL; diff --git a/server/ttsd_dbus_server.c b/server/ttsd_dbus_server.c index c720e1d..fd11070 100644 --- a/server/ttsd_dbus_server.c +++ b/server/ttsd_dbus_server.c @@ -199,7 +199,7 @@ int ttsd_dbus_server_get_support_voices(DBusConnection* conn, DBusMessage* msg) } voice_list = g_list_remove_link(voice_list, iter); - + g_list_free(iter); iter = g_list_first(voice_list); } } diff --git a/server/ttsd_engine_agent.c b/server/ttsd_engine_agent.c index 3fffd78..f41d412 100644 --- a/server/ttsd_engine_agent.c +++ b/server/ttsd_engine_agent.c @@ -85,39 +85,36 @@ static synth_result_callback g_result_cb; /** Set current engine */ -int __internal_set_current_engine(const char* engine_uuid); +static int __internal_set_current_engine(const char* engine_uuid); /** Check engine id */ -int __internal_check_engine_id(const char* engine_uuid); +static int __internal_check_engine_id(const char* engine_uuid); /** Update engine list */ -int __internal_update_engine_list(); +static int __internal_update_engine_list(); /** Get engine info */ -int __internal_get_engine_info(const char* filepath, ttsengine_info_s** info); +static int __internal_get_engine_info(const char* filepath, ttsengine_info_s** info); /** Callback function for result */ bool __result_cb(ttsp_result_event_e event, const void* data, unsigned int data_size, ttsp_audio_type_e audio_type, int rate, void *user_data); /** Callback function for voice list */ -bool __supported_voice_cb(const char* language, int type, void* user_data); +static bool __supported_voice_cb(const char* language, int type, void* user_data); /** Free voice list */ -void __free_voice_list(GList* voice_list); +static void __free_voice_list(GList* voice_list); /** Callback function for engine info */ -void __engine_info_cb(const char* engine_uuid, const char* engine_name, const char* setting_ug_name, +static void __engine_info_cb(const char* engine_uuid, const char* engine_name, const char* setting_ug_name, bool use_network, void* user_data); -/** Callback fucntion for engine setting */ -bool __engine_setting_cb(const char* key, const char* value, void* user_data); - /** Print list */ -int ttsd_print_enginelist(); +static int ttsd_print_enginelist(); -int ttsd_print_voicelist(); +static int ttsd_print_voicelist(); static const char* __ttsd_get_engine_error_code(ttsp_error_e err) { @@ -326,7 +323,7 @@ int ttsd_engine_agent_initialize_current_engine() return 0; } -int __internal_check_engine_id(const char* engine_uuid) +static int __internal_check_engine_id(const char* engine_uuid) { GList *iter = NULL; ttsengine_s *data = NULL; @@ -365,7 +362,7 @@ void __engine_info_cb(const char* engine_uuid, const char* engine_name, const ch return; } -int __internal_get_engine_info(const char* filepath, ttsengine_info_s** info) +static int __internal_get_engine_info(const char* filepath, ttsengine_info_s** info) { char *error; void* handle; @@ -445,7 +442,7 @@ int __internal_get_engine_info(const char* filepath, ttsengine_info_s** info) return 0; } -int __internal_update_engine_list() +static int __internal_update_engine_list() { /* relsease engine list */ GList *iter = NULL; @@ -459,6 +456,7 @@ int __internal_update_engine_list() if (data != NULL) free(data); g_engine_list = g_list_remove_link(g_engine_list, iter); + g_list_free(iter); iter = g_list_first(g_engine_list); } } @@ -555,7 +553,7 @@ int __internal_update_engine_list() return 0; } -int __internal_set_current_engine(const char* engine_uuid) +static int __internal_set_current_engine(const char* engine_uuid) { /* check whether engine id is valid or not. */ GList *iter = NULL; @@ -620,7 +618,53 @@ int __internal_set_current_engine(const char* engine_uuid) return 0; } -bool __set_voice_info_cb(const char* language, int type, void* user_data) +int __ttsd_get_mode(ttsp_mode_e* mode) +{ + if (NULL == mode) { + SLOG(LOG_ERROR, get_tag(), "[ERROR] Input parameter is null"); + return TTSP_ERROR_INVALID_PARAMETER; + } + + switch (ttsd_get_mode()) { + case TTSD_MODE_DEFAULT: *mode = TTSP_MODE_DEFAULT; break; + case TTSD_MODE_NOTIFICATION: *mode = TTSP_MODE_NOTIFICATION; break; + case TTSD_MODE_SCREEN_READER: *mode = TTSP_MODE_SCREEN_READER; break; + default: + SLOG(LOG_ERROR, get_tag(), "[ERROR] tts mode is NOT valid"); + } + + return 0; +} + +int __ttsd_engine_agent_get_speed_range(int* min, int* normal, int* max) +{ + if (NULL == min || NULL == normal || NULL == max) { + SLOG(LOG_ERROR, get_tag(), "[ERROR] Input parameter is null"); + return TTSP_ERROR_INVALID_PARAMETER; + } + + *min = TTS_SPEED_MIN; + *normal = TTS_SPEED_NORMAL; + *max = TTS_SPEED_MAX; + + return 0; +} + +int __ttsd_engine_agent_get_pitch_range(int* min, int* normal, int* max) +{ + if (NULL == min || NULL == normal || NULL == max) { + SLOG(LOG_ERROR, get_tag(), "[ERROR] Input parameter is null"); + return TTSP_ERROR_INVALID_PARAMETER; + } + + *min = TTS_PITCH_MIN; + *normal = TTS_PITCH_NORMAL; + *max = TTS_PITCH_MAX; + + return 0; +} + +static bool __set_voice_info_cb(const char* language, int type, void* user_data) { if (NULL == language) { SLOG(LOG_ERROR, get_tag(), "[Engine Agent ERROR] Input parameter is NULL in voice list callback!!!!"); @@ -628,6 +672,10 @@ bool __set_voice_info_cb(const char* language, int type, void* user_data) } ttsvoice_s* voice = calloc(1, sizeof(ttsvoice_s)); + if (NULL == voice) { + SLOG(LOG_ERROR, get_tag(), "[Engine Agent ERROR] Fail to allocate memory"); + return false; + } voice->lang = strdup(language); voice->type = type; @@ -646,7 +694,7 @@ bool __set_voice_info_cb(const char* language, int type, void* user_data) return true; } -int __update_voice_list() +static int __update_voice_list() { /* Get voice list */ g_cur_voices = NULL; @@ -706,6 +754,9 @@ int ttsd_engine_agent_load_current_engine() /* load engine */ g_cur_engine.pdfuncs->version = 1; g_cur_engine.pdfuncs->size = sizeof(ttspd_funcs_s); + g_cur_engine.pdfuncs->get_mode = __ttsd_get_mode; + g_cur_engine.pdfuncs->get_speed_range = __ttsd_engine_agent_get_speed_range; + g_cur_engine.pdfuncs->get_pitch_range = __ttsd_engine_agent_get_pitch_range; int ret = 0; ret = g_cur_engine.ttsp_load_engine(g_cur_engine.pdfuncs, g_cur_engine.pefuncs); @@ -764,10 +815,21 @@ int ttsd_engine_agent_load_current_engine() g_cur_engine.default_lang, g_cur_engine.default_vctype); } else { SLOG(LOG_WARN, get_tag(), "[Engine Agent ERROR] Fail to load default voice : lang(%s), type(%d) result(%s)", - g_cur_engine.default_lang, g_cur_engine.default_vctype, __ttsd_get_engine_error_code(ret)); + g_cur_engine.default_lang, g_cur_engine.default_vctype, __ttsd_get_engine_error_code(ret)); + + return TTSD_ERROR_OPERATION_FAILED; + } + } + /* set default pitch */ + if (NULL != g_cur_engine.pefuncs->set_pitch) { + ret = g_cur_engine.pefuncs->set_pitch(g_cur_engine.default_pitch); + if (0 != ret) { + SLOG(LOG_ERROR, get_tag(), "[Engine Agent ERROR] Fail to set pitch : pitch(%d), result(%s)", + g_cur_engine.default_pitch, __ttsd_get_engine_error_code(ret)); return TTSD_ERROR_OPERATION_FAILED; } + SLOG(LOG_DEBUG, get_tag(), "[Engine Agent SUCCESS] Set default pitch : pitch(%d)", g_cur_engine.default_pitch); } #if 0 @@ -1477,6 +1539,10 @@ bool __supported_voice_cb(const char* language, int type, void* user_data) } voice_s* voice = calloc(1, sizeof(voice_s)); + if (NULL == voice) { + SLOG(LOG_ERROR, get_tag(), "[Engine Agent ERROR] Fail to allocate memory"); + return false; + } voice->language = strdup(language); voice->type = type; @@ -1556,7 +1622,7 @@ void __free_voice_list(GList* voice_list) } voice_list = g_list_remove_link(voice_list, iter); - + g_list_free(iter); iter = g_list_first(voice_list); } } diff --git a/server/ttsd_player.c b/server/ttsd_player.c index de4762f..256eca2 100644 --- a/server/ttsd_player.c +++ b/server/ttsd_player.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "ttsd_main.h" #include "ttsd_player.h" @@ -39,8 +40,8 @@ typedef struct { bool is_paused_data; int idx; - sound_data_s paused_data; -} player_s; + sound_data_s* paused_data; +}player_s; #define SOUND_BUFFER_LENGTH 2048 @@ -132,7 +133,7 @@ static int __create_audio_out(ttsp_audio_type_e type, int rate) sample_type = AUDIO_SAMPLE_TYPE_U8; } - ret = audio_out_create(rate, AUDIO_CHANNEL_MONO, sample_type, SOUND_TYPE_MEDIA, &g_audio_h); + ret = audio_out_create(rate, AUDIO_CHANNEL_MONO, sample_type, SOUND_TYPE_VOICE, &g_audio_h); if (AUDIO_IO_ERROR_NONE != ret) { g_audio_state = AUDIO_STATE_NONE; g_audio_h = NULL; @@ -195,7 +196,30 @@ static int __destroy_audio_out() static void __end_play_thread(void *data, Ecore_Thread *thread) { - SLOG(LOG_DEBUG, get_tag(), "===== End thread"); + SLOG(LOG_ERROR, get_tag(), "===== End thread"); +} + +static void __set_volume_using_voice_policy(int volume) +{ +/* + SLOG(LOG_WARN, get_tag(), "[Player WARNING] set volume policy"); + int ret = sound_manager_set_volume_voice_policy(volume); + if (SOUND_MANAGER_ERROR_NONE != ret) { + SLOG(LOG_WARN, get_tag(), "[Player WARNING] Fail to set volume policy"); + } +*/ + return; +} + +static void __unset_volume_using_voice_policy() +{ +/* + SLOG(LOG_WARN, get_tag(), "[Player WARNING] unset volume policy"); + int ret = sound_manager_unset_volume_voice_policy(); + if (SOUND_MANAGER_ERROR_NONE != ret) { + SLOG(LOG_WARN, get_tag(), "[Player WARNING] Fail to unset volume policy"); + } +*/ return; } @@ -209,32 +233,26 @@ static void __play_thread(void *data, Ecore_Thread *thread) } player_s* player = g_playing_info; - sound_data_s wdata; + sound_data_s* sound_data = NULL; int ret = -1; int len = SOUND_BUFFER_LENGTH; int idx = 0; + /* set volume policy as 40% */ + __set_volume_using_voice_policy(40); while (1) { if (true == player->is_paused_data) { /* Resume player */ - wdata.data = player->paused_data.data; - wdata.data_size = player->paused_data.data_size; - wdata.utt_id = player->paused_data.utt_id; - wdata.audio_type = player->paused_data.audio_type; - wdata.rate = player->paused_data.rate; - wdata.channels = player->paused_data.channels; - wdata.event = player->paused_data.event; + sound_data = player->paused_data; + player->paused_data = NULL; idx = player->idx; player->is_paused_data = false; player->idx = 0; - } else { - if (0 != ttsd_data_get_sound_data(player->uid, &wdata)) { - g_playing_info = NULL; - SLOG(LOG_DEBUG, get_tag(), "[Player] No sound data. Finish thread"); + if (NULL == sound_data) { /* Request unprepare */ ret = audio_out_unprepare(g_audio_h); if (AUDIO_IO_ERROR_NONE != ret) { @@ -244,74 +262,122 @@ static void __play_thread(void *data, Ecore_Thread *thread) } g_audio_state = AUDIO_STATE_READY; + + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } + SLOG(LOG_INFO, get_tag(), "[Player] Sound info : id(%d) data(%p) size(%d) audiotype(%d) rate(%d) event(%d)", + sound_data->utt_id, sound_data->data, sound_data->data_size, sound_data->audio_type, sound_data->rate, sound_data->event); + } else { + sound_data = NULL; + ret = ttsd_data_get_sound_data(player->uid, &sound_data); + if (0 != ret || NULL == sound_data) { + /* empty queue */ + SLOG(LOG_DEBUG, get_tag(), "[Player] No sound data. Waiting mode"); + /* release audio & recover session */ + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret); + } else { + SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Unprepare audio"); + } + g_audio_state = AUDIO_STATE_READY; + + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); + + /* wait for new audio data come */ + while (1) { + usleep(10000); + if (NULL == g_playing_info) { + /* current playing uid is replaced */ + SLOG(LOG_DEBUG, get_tag(), "[Player] Finish thread"); + return; + } else if (0 < ttsd_data_get_sound_data_size(player->uid)) { + /* new audio data come */ + SLOG(LOG_DEBUG, get_tag(), "[Player] Resume thread"); + break; + } + } + + /* set volume policy as 40%, when resume play thread*/ + __set_volume_using_voice_policy(40); + + /* resume play thread */ + player->state = APP_STATE_PLAYING; + continue; + } /* If wdata's event is 'start', current wdata is first data of engine for synthesis. * If wdata's event is 'finish', player should check previous event to know whether this wdata is first or not. * When previous wdata's event is 'finish' and current wdata's event is 'finish', * the player should send utt started event. */ - if (TTSP_RESULT_EVENT_START == wdata.event || - (TTSP_RESULT_EVENT_FINISH == player->event && TTSP_RESULT_EVENT_FINISH == wdata.event)) { + if (TTSP_RESULT_EVENT_START == sound_data->event || + (TTSP_RESULT_EVENT_FINISH == player->event && TTSP_RESULT_EVENT_FINISH == sound_data->event)) { int pid = ttsd_data_get_pid(player->uid); if (pid <= 0) { SLOG(LOG_WARN, get_tag(), "[Send WARNIING] Current player is not valid"); + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } - if (0 != ttsdc_send_utt_start_message(pid, player->uid, wdata.utt_id)) { + if (0 != ttsdc_send_utt_start_message(pid, player->uid, sound_data->utt_id)) { SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Start Signal : pid(%d), uid(%d), uttid(%d)", - pid, player->uid, wdata.utt_id); + pid, player->uid, sound_data->utt_id); } - SLOG(LOG_DEBUG, get_tag(), "[Player] Start utterance : uid(%d), uttid(%d)", player->uid, wdata.utt_id); + SLOG(LOG_DEBUG, get_tag(), "[Player] Start utterance : uid(%d), uttid(%d)", player->uid, sound_data->utt_id); } /* Save last event to check utterance start */ - player->event = wdata.event; + player->event = sound_data->event; idx = 0; - if (NULL == wdata.data || 0 >= wdata.data_size) { - if (TTSP_RESULT_EVENT_FINISH == wdata.event) { + if (NULL == sound_data->data || 0 >= sound_data->data_size) { + if (TTSP_RESULT_EVENT_FINISH == sound_data->event) { SLOG(LOG_DEBUG, get_tag(), "No sound data"); /* send utterence finish signal */ int pid = ttsd_data_get_pid(player->uid); if (pid <= 0) { SLOG(LOG_WARN, get_tag(), "[Send WARNIING] Current player is not valid"); + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } - if (0 != ttsdc_send_utt_finish_message(pid, player->uid, wdata.utt_id)) { - SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%d), uttid(%d)", pid, player->uid, wdata.utt_id); + if (0 != ttsdc_send_utt_finish_message(pid, player->uid, sound_data->utt_id)) { + SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%d), uttid(%d)", + pid, player->uid, sound_data->utt_id); } } - SLOG(LOG_DEBUG, get_tag(), "[Player] Finish utterance : uid(%d), uttid(%d)", player->uid, wdata.utt_id); + SLOG(LOG_DEBUG, get_tag(), "[Player] Finish utterance : uid(%d), uttid(%d)", player->uid, sound_data->utt_id); continue; } } - SLOG(LOG_DEBUG, get_tag(), "[Player] Sound info : id(%d) size(%d) audiotype(%d) rate(%d) event(%d)", - wdata.utt_id, wdata.data_size, wdata.audio_type, wdata.rate, wdata.event); - - if (g_sampling_rate != wdata.rate || g_audio_type != wdata.audio_type) { + if (g_sampling_rate != sound_data->rate || g_audio_type != sound_data->audio_type) { SLOG(LOG_DEBUG, get_tag(), "[Player] Change audio handle : org type(%d) org rate(%d)", g_audio_type, g_sampling_rate); if (NULL != g_audio_h) { __destroy_audio_out(); } - if (0 > __create_audio_out(wdata.audio_type, wdata.rate)) { + if (0 > __create_audio_out(sound_data->audio_type, sound_data->rate)) { SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to create audio out"); + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } } while (APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) { - if ((unsigned int)idx >= wdata.data_size) + if ((unsigned int)idx >= sound_data->data_size) break; - if ((unsigned int)idx + SOUND_BUFFER_LENGTH > wdata.data_size) { - len = wdata.data_size - idx; + if ((unsigned int)idx + SOUND_BUFFER_LENGTH > sound_data->data_size) { + len = sound_data->data_size - idx; } else { len = SOUND_BUFFER_LENGTH; } @@ -322,13 +388,15 @@ static void __play_thread(void *data, Ecore_Thread *thread) if (AUDIO_IO_ERROR_NONE != ret) { SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to prepare audio : %d", ret); g_playing_info = NULL; + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Prepare audio"); g_audio_state = AUDIO_STATE_PLAY; } - char* temp_data = wdata.data; + char* temp_data = sound_data->data; ret = audio_out_write(g_audio_h, &temp_data[idx], len); if (0 > ret) { SLOG(LOG_WARN, get_tag(), "[Player WARNING] Fail to audio write - %d", ret); @@ -336,15 +404,32 @@ static void __play_thread(void *data, Ecore_Thread *thread) idx += len; } + if (NULL == g_playing_info && APP_STATE_PAUSED != player->state) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Current player is NULL"); + g_audio_state = AUDIO_STATE_READY; + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret); + } + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); + + if (NULL != sound_data) { + if (NULL != sound_data->data) { + free(sound_data->data); + sound_data->data = NULL; + } + + free(sound_data); + sound_data = NULL; + } + + return; + } + if (APP_STATE_PAUSED == player->state) { /* Save data */ - player->paused_data.data = wdata.data; - player->paused_data.data_size = wdata.data_size; - player->paused_data.utt_id = wdata.utt_id; - player->paused_data.audio_type = wdata.audio_type; - player->paused_data.rate = wdata.rate; - player->paused_data.channels = wdata.channels; - player->paused_data.event = wdata.event; + player->paused_data = sound_data; player->is_paused_data = true; player->idx = idx; @@ -359,16 +444,14 @@ static void __play_thread(void *data, Ecore_Thread *thread) } else { SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Unprepare audio"); } + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } } - if (NULL != wdata.data) { - free(wdata.data); - wdata.data = NULL; - } - - if (APP_STATE_READY == player->state) { + if (NULL == g_playing_info && APP_STATE_READY == player->state) { + /* player_stop */ g_audio_state = AUDIO_STATE_READY; SLOG(LOG_DEBUG, get_tag(), "[Player] Stop player thread"); @@ -379,25 +462,65 @@ static void __play_thread(void *data, Ecore_Thread *thread) } else { SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Unprepare audio"); } + + if (NULL != sound_data) { + if (NULL != sound_data->data) { + free(sound_data->data); + sound_data->data = NULL; + } + + free(sound_data); + sound_data = NULL; + } + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } - if (TTSP_RESULT_EVENT_FINISH == wdata.event) { + if ((APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) && + (TTSP_RESULT_EVENT_FINISH == sound_data->event)) { /* send utterence finish signal */ int pid = ttsd_data_get_pid(player->uid); if (pid <= 0) { SLOG(LOG_WARN, get_tag(), "[Send WARNIING] Current player is not valid"); + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } - if (0 != ttsdc_send_utt_finish_message(pid, player->uid, wdata.utt_id)) { + if (0 != ttsdc_send_utt_finish_message(pid, player->uid, sound_data->utt_id)) { SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%d), uttid(%d)", - pid, player->uid, wdata.utt_id); + pid, player->uid, sound_data->utt_id); + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); return; } - SLOG(LOG_DEBUG, get_tag(), "[Player] Finish utterance : uid(%d), uttid(%d)", player->uid, wdata.utt_id); + SLOG(LOG_DEBUG, get_tag(), "[Player] Finish utterance : uid(%d), uttid(%d)", player->uid, sound_data->utt_id); + } + + if (NULL != sound_data) { + if (NULL != sound_data->data) { + free(sound_data->data); + sound_data->data = NULL; + } + + free(sound_data); + sound_data = NULL; + } + + if (NULL == g_playing_info) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Current player is NULL"); + g_audio_state = AUDIO_STATE_READY; + ret = audio_out_unprepare(g_audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret); + } + /* unset volume policy, volume will be 100% */ + __unset_volume_using_voice_policy(); + + return; } } } @@ -447,10 +570,6 @@ int ttsd_player_release(void) int ret; - ret = __destroy_audio_out(); - if (0 != ret) - return -1; - SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] =========================="); SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] Active thread count : %d", ecore_thread_active_get()); SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] =========================="); @@ -462,7 +581,7 @@ int ttsd_player_release(void) usleep(10000); count++; - if (100 == count) { + if (20 == count) { SLOG(LOG_WARN, get_tag(), "[Player WARNING!!] Thread is blocked. Player release continue."); break; } @@ -472,6 +591,10 @@ int ttsd_player_release(void) SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] Thread is released"); + ret = __destroy_audio_out(); + if (0 != ret) + return -1; + /* clear g_player_list */ g_playing_info = NULL; g_player_init = false; @@ -493,15 +616,19 @@ int ttsd_player_create_instance(int uid) } player_s* new_client = (player_s*)calloc(1, sizeof(player_s)); + if (NULL == new_client) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to allocate memory"); + return TTSP_ERROR_OUT_OF_MEMORY; + } new_client->uid = uid; new_client->event = TTSP_RESULT_EVENT_FINISH; new_client->state = APP_STATE_READY; new_client->is_paused_data = false; new_client->idx = 0; - new_client->paused_data.data = NULL; - - SLOG(LOG_DEBUG, get_tag(), "[Player] Create player : uid(%d)", uid); + new_client->paused_data = NULL; + + SECURE_SLOG(LOG_DEBUG, get_tag(), "[Player] Create player : uid(%d)", uid); g_player_list = g_list_append(g_player_list, new_client); @@ -544,6 +671,7 @@ int ttsd_player_destroy_instance(int uid) if (uid == data->uid) { g_player_list = g_list_remove_link(g_player_list, iter); free(data); + g_list_free(iter); break; } } @@ -569,6 +697,9 @@ int ttsd_player_play(int uid) if (uid == g_playing_info->uid) { SLOG(LOG_DEBUG, get_tag(), "[Player] uid(%d) has already played", g_playing_info->uid); return 0; + } else { + SLOG(LOG_WARN, get_tag(), "[Player WARNING] stop old player (%d)", g_playing_info->uid); + ttsd_player_stop(g_playing_info->uid); } } @@ -628,9 +759,14 @@ int ttsd_player_stop(int uid) } if (true == current->is_paused_data) { - if (NULL != current->paused_data.data) { - free(current->paused_data.data); - current->paused_data.data = NULL; + if (NULL != current->paused_data) { + if (NULL != current->paused_data->data) { + free(current->paused_data->data); + current->paused_data->data = NULL; + } + + free(current->paused_data); + current->paused_data = NULL; } } @@ -639,11 +775,73 @@ int ttsd_player_stop(int uid) current->is_paused_data = false; current->idx = 0; + if (NULL == g_playing_info) { + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + SLOG(LOG_ERROR, get_tag(), "[Player] Active thread count : %d", ecore_thread_active_get()); + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + + /* The thread should be released */ + int thread_count = ecore_thread_active_get(); + int count = 0; + while (0 < thread_count) { + usleep(10000); + + count++; + if (30 == count) { + SLOG(LOG_WARN, get_tag(), "[Player WARNING!!] Thread is blocked. Player release continue."); + break; + } + + thread_count = ecore_thread_active_get(); + } + + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + SLOG(LOG_ERROR, get_tag(), "[Player] Active thread count : %d", ecore_thread_active_get()); + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + } + SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Stop player : uid(%d)", uid); return 0; } +int ttsd_player_clear(int uid) +{ + if (false == g_player_init) { + SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized"); + return -1; + } + + /* Check uid */ + player_s* current; + current = __player_get_item(uid); + if (NULL == current) { + SECURE_SLOG(LOG_ERROR, get_tag(), "[Player ERROR] uid(%d) is not valid", uid); + return -1; + } + + if (true == current->is_paused_data) { + if (NULL != current->paused_data) { + if (NULL != current->paused_data->data) { + free(current->paused_data->data); + current->paused_data->data = NULL; + } + + free(current->paused_data); + current->paused_data = NULL; + } + } + + current->event = TTSP_RESULT_EVENT_FINISH; + current->state = APP_STATE_READY; + current->is_paused_data = false; + current->idx = 0; + + SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Clear player : uid(%d)", uid); + + return 0; +} + int ttsd_player_pause(int uid) { SLOG(LOG_DEBUG, get_tag(), "[Player] pause player : uid(%d)", uid); @@ -672,6 +870,31 @@ int ttsd_player_pause(int uid) } current->state = APP_STATE_PAUSED; + + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + SLOG(LOG_ERROR, get_tag(), "[Player] Active thread count : %d", ecore_thread_active_get()); + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + + /* The thread should be released */ + int thread_count = ecore_thread_active_get(); + int count = 0; + while (0 < thread_count) { + usleep(10000); + + count++; + if (30 == count) { + SLOG(LOG_WARN, get_tag(), "[Player WARNING!!] Thread is blocked. Player release continue."); + break; + } + + thread_count = ecore_thread_active_get(); + } + + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + SLOG(LOG_ERROR, get_tag(), "[Player] Active thread count : %d", ecore_thread_active_get()); + SLOG(LOG_DEBUG, get_tag(), "[Player] =========================="); + + SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Pause player : uid(%d)", uid); return 0; } @@ -739,9 +962,14 @@ int ttsd_player_all_stop() data->state = APP_STATE_READY; if (true == data->is_paused_data) { - if (NULL != data->paused_data.data) { - free(data->paused_data.data); - data->paused_data.data = NULL; + if (NULL != data->paused_data) { + if (NULL != data->paused_data->data) { + free(data->paused_data->data); + data->paused_data->data = NULL; + } + + free(data->paused_data); + data->paused_data = NULL; } } diff --git a/server/ttsd_player.h b/server/ttsd_player.h index 5fcbbe5..4662b4e 100644 --- a/server/ttsd_player.h +++ b/server/ttsd_player.h @@ -47,6 +47,8 @@ int ttsd_player_play(int uid); int ttsd_player_stop(int uid); +int ttsd_player_clear(int uid); + int ttsd_player_pause(int uid); int ttsd_player_resume(int uid); diff --git a/server/ttsd_server.c b/server/ttsd_server.c index 7b452fe..1d740c4 100644 --- a/server/ttsd_server.c +++ b/server/ttsd_server.c @@ -47,6 +47,8 @@ static Ecore_Timer* g_wait_timer = NULL; static utterance_t g_utt; +static GList *g_proc_list = NULL; + /* Function definitions */ static int __synthesis(int uid); @@ -88,33 +90,45 @@ static int __synthesis(int uid) { SLOG(LOG_DEBUG, get_tag(), "===== SYNTHESIS START"); - speak_data_s sdata; - if (0 == ttsd_data_get_speak_data(uid, &sdata)) { + speak_data_s* speak_data = NULL; + if (0 == ttsd_data_get_speak_data(uid, &speak_data)) { + if (NULL == speak_data) { + return 0; + } - if (NULL == sdata.lang || NULL == sdata.text) { + if (NULL == speak_data->lang || NULL == speak_data->text) { SLOG(LOG_ERROR, get_tag(), "[Server ERROR] Current data is NOT valid"); ttsd_server_stop(uid); int pid = ttsd_data_get_pid(uid); ttsdc_send_set_state_message(pid, uid, APP_STATE_READY); - if (NULL != sdata.lang) free(sdata.lang); + if (NULL != speak_data) { + if (NULL != speak_data->lang) free(speak_data->lang); + if (NULL != speak_data->text) free(speak_data->text); + + speak_data->lang = NULL; + speak_data->text = NULL; + + free(speak_data); + speak_data = NULL; + } return 0; } g_utt.uid = uid; - g_utt.uttid = sdata.utt_id; + g_utt.uttid = speak_data->utt_id; SLOG(LOG_DEBUG, get_tag(), "-----------------------------------------------------------"); - SLOG(LOG_DEBUG, get_tag(), "ID : uid (%d), uttid(%d) ", g_utt.uid, g_utt.uttid); - SLOG(LOG_DEBUG, get_tag(), "Voice : langauge(%s), type(%d), speed(%d)", sdata.lang, sdata.vctype, sdata.speed); - SLOG(LOG_DEBUG, get_tag(), "Text : %s", sdata.text); + SECURE_SLOG(LOG_DEBUG, get_tag(), "ID : uid (%d), uttid(%d) ", g_utt.uid, g_utt.uttid); + SECURE_SLOG(LOG_DEBUG, get_tag(), "Voice : langauge(%s), type(%d), speed(%d)", speak_data->lang, speak_data->vctype, speak_data->speed); + SECURE_SLOG(LOG_DEBUG, get_tag(), "Text : %s", speak_data->text); SLOG(LOG_DEBUG, get_tag(), "-----------------------------------------------------------"); int ret = 0; __server_set_synth_control(TTSD_SYNTHESIS_CONTROL_DOING); - ret = ttsd_engine_start_synthesis(sdata.lang, sdata.vctype, sdata.text, sdata.speed, NULL); + ret = ttsd_engine_start_synthesis(speak_data->lang, speak_data->vctype, speak_data->text, speak_data->speed, NULL); if (0 != ret) { SLOG(LOG_ERROR, get_tag(), "[Server ERROR] * FAIL to start SYNTHESIS !!!! * "); @@ -128,8 +142,16 @@ static int __synthesis(int uid) g_wait_timer = ecore_timer_add(0, __wait_synthesis, NULL); } - free(sdata.lang); - free(sdata.text); + if (NULL != speak_data) { + if (NULL != speak_data->lang) free(speak_data->lang); + if (NULL != speak_data->text) free(speak_data->text); + + speak_data->lang = NULL; + speak_data->text = NULL; + + free(speak_data); + speak_data = NULL; + } } SLOG(LOG_DEBUG, get_tag(), "===== SYNTHESIS END"); @@ -151,10 +173,19 @@ int __synthesis_result_callback(ttsp_result_event_e event, const void* data, uns /* Synthesis is success */ if (TTSP_RESULT_EVENT_START == event || TTSP_RESULT_EVENT_CONTINUE == event || TTSP_RESULT_EVENT_FINISH == event) { + + if (TTSP_RESULT_EVENT_START == event) { + SLOG(LOG_DEBUG, get_tag(), "[SERVER] Event : TTSP_RESULT_EVENT_START"); + SECURE_SLOG(LOG_DEBUG, get_tag(), "[SERVER] Result Info : uid(%d), utt(%d), data(%p), data size(%d) audiotype(%d) rate(%d)", + uid, uttid, data, data_size, audio_type, rate); + } else if (TTSP_RESULT_EVENT_FINISH == event) { + SLOG(LOG_DEBUG, get_tag(), "[SERVER] Event : TTSP_RESULT_EVENT_FINISH"); + SECURE_SLOG(LOG_DEBUG, get_tag(), "[SERVER] Result Info : uid(%d), utt(%d), data(%p), data size(%d) audiotype(%d) rate(%d)", + uid, uttid, data, data_size, audio_type, rate); + } else { + /*if (TTSP_RESULT_EVENT_CONTINUE == event) SLOG(LOG_DEBUG, get_tag(), "[SERVER] Event : TTSP_RESULT_EVENT_CONTINUE");*/ + } - if (TTSP_RESULT_EVENT_START == event) SLOG(LOG_DEBUG, get_tag(), "[SERVER] Event : TTSP_RESULT_EVENT_START"); - if (TTSP_RESULT_EVENT_CONTINUE == event) SLOG(LOG_DEBUG, get_tag(), "[SERVER] Event : TTSP_RESULT_EVENT_CONTINUE"); - if (TTSP_RESULT_EVENT_FINISH == event) SLOG(LOG_DEBUG, get_tag(), "[SERVER] Event : TTSP_RESULT_EVENT_FINISH"); if (false == ttsd_data_is_uttid_valid(uid, uttid)) { __server_set_synth_control(TTSD_SYNTHESIS_CONTROL_DONE); @@ -164,9 +195,6 @@ int __synthesis_result_callback(ttsp_result_event_e event, const void* data, uns return 0; } - SLOG(LOG_DEBUG, get_tag(), "[SERVER] Result Info : uid(%d), utt(%d), data(%p), data size(%d) audiotype(%d) rate(%d)", - uid, uttid, data, data_size, audio_type, rate); - if (rate <= 0 || audio_type < 0 || audio_type > TTSP_AUDIO_TYPE_MAX) { __server_set_synth_control(TTSD_SYNTHESIS_CONTROL_DONE); SLOG(LOG_ERROR, get_tag(), "[SERVER ERROR] audio data is invalid"); @@ -176,26 +204,38 @@ int __synthesis_result_callback(ttsp_result_event_e event, const void* data, uns } /* add wav data */ - sound_data_s temp_data; - temp_data.data = NULL; - temp_data.rate = 0; - temp_data.data_size = 0; + sound_data_s* temp_sound_data = NULL; + temp_sound_data = (sound_data_s*)calloc(1, sizeof(sound_data_s)); + if (NULL == temp_sound_data) { + SLOG(LOG_ERROR, get_tag(), "[SERVER ERROR] Out of memory"); + return 0; + } + + temp_sound_data->data = NULL; + temp_sound_data->rate = 0; + temp_sound_data->data_size = 0; if (0 < data_size) { - temp_data.data = (char*)calloc(data_size, sizeof(char)); - memcpy(temp_data.data, data, data_size); + temp_sound_data->data = (char*)calloc(data_size + 5, sizeof(char)); + if (NULL != temp_sound_data->data) { + memcpy(temp_sound_data->data, data, data_size); + temp_sound_data->data_size = data_size; + SLOG(LOG_ERROR, get_tag(), "[DEBUG][free] uid(%d), event(%d) sound_data(%p) data(%p) size(%d)", + uid, event, temp_sound_data, temp_sound_data->data, temp_sound_data->data_size); + } else { + SLOG(LOG_ERROR, get_tag(), "Fail to allocate memory"); + } } else { SLOG(LOG_ERROR, get_tag(), "Sound data is NULL"); } - temp_data.data_size = data_size; - temp_data.utt_id = uttid; - temp_data.event = event; - temp_data.audio_type = audio_type; - temp_data.rate = rate; + temp_sound_data->utt_id = uttid; + temp_sound_data->event = event; + temp_sound_data->audio_type = audio_type; + temp_sound_data->rate = rate; - if (0 != ttsd_data_add_sound_data(uid, temp_data)) { - SLOG(LOG_ERROR, get_tag(), "[SERVER ERROR] Fail to add sound data : uid(%d)", uid); + if (0 != ttsd_data_add_sound_data(uid, temp_sound_data)) { + SECURE_SLOG(LOG_ERROR, get_tag(), "[SERVER ERROR] Fail to add sound data : uid(%d)", uid); } if (event == TTSP_RESULT_EVENT_FINISH) { @@ -218,8 +258,8 @@ int __synthesis_result_callback(ttsp_result_event_e event, const void* data, uns } - SLOG(LOG_DEBUG, get_tag(), "===== SYNTHESIS RESULT CALLBACK END"); - SLOG(LOG_DEBUG, get_tag(), " "); + /*SLOG(LOG_DEBUG, get_tag(), "===== SYNTHESIS RESULT CALLBACK END"); + SLOG(LOG_DEBUG, get_tag(), " ");*/ return 0; } @@ -402,6 +442,16 @@ int ttsd_initialize() int ttsd_finalize() { + GList *iter = NULL; + if (0 < g_list_length(g_proc_list)) { + iter = g_list_first(g_proc_list); + while (NULL != iter) { + g_proc_list = g_list_remove_link(g_proc_list, iter); + g_list_free(iter); + iter = g_list_first(g_proc_list); + } + } + ttsd_config_finalize(); ttsd_player_release(); @@ -411,8 +461,70 @@ int ttsd_finalize() return TTSD_ERROR_NONE; } +static void __read_proc() +{ + DIR *dp = NULL; + struct dirent entry; + struct dirent *dirp = NULL; + int ret = -1; + int tmp; + + GList *iter = NULL; + if (0 < g_list_length(g_proc_list)) { + iter = g_list_first(g_proc_list); + while (NULL != iter) { + g_proc_list = g_list_remove_link(g_proc_list, iter); + g_list_free(iter); + iter = g_list_first(g_proc_list); + } + } + + dp = opendir("/proc"); + if (NULL == dp) { + SLOG(LOG_ERROR, get_tag(), "[ERROR] Fail to open proc"); + } else { + do { + ret = readdir_r(dp, &entry, &dirp); + if (0 != ret) { + SLOG(LOG_ERROR, get_tag(), "[ERROR] Fail to readdir"); + break; + } + + if (NULL != dirp) { + tmp = atoi(dirp->d_name); + if (0 >= tmp) continue; + g_proc_list = g_list_append(g_proc_list, GINT_TO_POINTER(tmp)); + } + } while (NULL != dirp); + closedir(dp); + } + return; +} + bool __get_client_for_clean_up(int pid, int uid, app_state_e state, void* user_data) { + bool exist = false; + int i = 0; + + GList *iter = NULL; + for (i = 0; i < g_list_length(g_proc_list); i++) { + iter = g_list_nth(g_proc_list, i); + if (NULL != iter) { + if (pid == GPOINTER_TO_INT(iter->data)) { + SLOG(LOG_DEBUG, get_tag(), "uid (%d) is running", uid); + exist = true; + break; + } + } + } + + if (false == exist) { + SLOG(LOG_ERROR, get_tag(), "uid (%d) should be removed", uid); + ttsd_server_finalize(uid); + } + + return true; +#if 0 char appid[128] = {0, }; if (0 != aul_app_get_appid_bypid(pid, appid, sizeof(appid))) { SLOG(LOG_ERROR, get_tag(), "[Server ERROR] Fail to get app id"); @@ -434,12 +546,14 @@ bool __get_client_for_clean_up(int pid, int uid, app_state_e state, void* user_d } } return true; +#endif } Eina_Bool ttsd_cleanup_client(void *data) { SLOG(LOG_DEBUG, get_tag(), "===== CLEAN UP CLIENT START"); + __read_proc(); ttsd_data_foreach_clients(__get_client_for_clean_up, NULL); SLOG(LOG_DEBUG, get_tag(), "====="); SLOG(LOG_DEBUG, get_tag(), " "); @@ -511,7 +625,8 @@ int ttsd_server_finalize(int uid) } ttsd_server_stop(uid); - + ttsd_player_stop(uid); + ttsd_player_destroy_instance(uid); /* Need to unload voice when used voice is unregistered */ @@ -552,21 +667,38 @@ int ttsd_server_add_queue(int uid, const char* text, const char* lang, int voice SLOG(LOG_ERROR, get_tag(), "[Server ERROR] Fail to select valid voice : result lang is NULL"); return TTSD_ERROR_INVALID_VOICE; } + + speak_data_s* speak_data = NULL; + speak_data = (speak_data_s*)calloc(1, sizeof(speak_data_s)); + if (NULL == speak_data) { + SLOG(LOG_ERROR, get_tag(), "[Server ERROR] Fail to allocate memory"); + if (NULL != temp_lang) free(temp_lang); + return TTSD_ERROR_OPERATION_FAILED; + } - speak_data_s data; - - data.lang = strdup(lang); - data.vctype = voice_type; + speak_data->lang = strdup(lang); + speak_data->vctype = voice_type; - data.speed = speed; - data.utt_id = utt_id; + speak_data->speed = speed; + speak_data->utt_id = utt_id; - data.text = strdup(text); + speak_data->text = strdup(text); /* if state is APP_STATE_READY , APP_STATE_PAUSED , only need to add speak data to queue*/ - if (0 != ttsd_data_add_speak_data(uid, data)) { + if (0 != ttsd_data_add_speak_data(uid, speak_data)) { SLOG(LOG_ERROR, get_tag(), "[Server ERROR] Fail to add speak data"); if (NULL != temp_lang) free(temp_lang); + if (NULL != speak_data) { + if (NULL != speak_data->lang) free(speak_data->lang); + if (NULL != speak_data->text) free(speak_data->text); + + speak_data->lang = NULL; + speak_data->text = NULL; + + free(speak_data); + speak_data = NULL; + } + return TTSD_ERROR_OPERATION_FAILED; } @@ -638,6 +770,7 @@ int ttsd_server_play(int uid) } int current_uid = ttsd_data_get_current_playing(); + SLOG(LOG_ERROR, get_tag(), "[Server] playing uid (%d)", current_uid); if (uid != current_uid && -1 != current_uid) { if (TTSD_MODE_DEFAULT != ttsd_get_mode()) { @@ -648,6 +781,9 @@ int ttsd_server_play(int uid) if (0 != ttsd_server_stop(current_uid)) { SLOG(LOG_WARN, get_tag(), "[Server ERROR] Fail to stop : uid (%d)", current_uid); } + if (0 != ttsd_player_stop(current_uid)) { + SLOG(LOG_WARN, get_tag(), "[Server ERROR] Fail to player stop : uid (%d)", current_uid); + } ecore_timer_add(0, __send_interrupt_client, (void*)current_uid); } else { @@ -714,7 +850,7 @@ int ttsd_server_stop(int uid) __server_set_synth_control(TTSD_SYNTHESIS_CONTROL_EXPIRED); - if (0 != ttsd_player_stop(uid)) + if (0 != ttsd_player_clear(uid)) SLOG(LOG_WARN, get_tag(), "[Server] Fail to ttsd_player_stop()"); ttsd_data_set_client_state(uid, APP_STATE_READY); diff --git a/server/ttsp.h b/server/ttsp.h index 9414d25..929b86b 100644 --- a/server/ttsp.h +++ b/server/ttsp.h @@ -60,19 +60,14 @@ typedef enum { TTSP_RESULT_EVENT_FINISH = 3 /**< event when the sound data is last data or sound data is only one result */ }ttsp_result_event_e; -/** -* @brief Defines of speaking speed. -*/ -#define TTSP_SPEED_MIN 1 -#define TTSP_SPEED_NORMAL 8 -#define TTSP_SPEED_MAX 15 - -/** -* @brief Defines of speaking pitch. +/** +* @brief Enumerations of TTS mode. */ -#define TTSP_PITCH_MIN 1 -#define TTSP_PITCH_NORMAL 8 -#define TTSP_PITCH_MAX 15 +typedef enum { + TTSP_MODE_DEFAULT = 0, /**< Default mode for normal application */ + TTSP_MODE_NOTIFICATION = 1, /**< Notification mode */ + TTSP_MODE_SCREEN_READER = 2 /**< Accessibiliity mode */ +}ttsp_mode_e; /** * @brief Defines of voice type. @@ -257,6 +252,47 @@ typedef int (* ttspe_start_synthesis)(const char* language, int type, const char */ typedef int (* ttspe_cancel_synthesis)(void); + +/** +* @brief Gets the mode. +* +* @param[out] mode The tts daemon mode +* +* @return 0 on success, otherwise a negative error value +* @retval #TTSP_ERROR_NONE Successful +* @retval #TTSP_ERROR_INVALID_PARAMETER Invalid parameter +* +*/ +typedef int (* ttspd_get_mode)(ttsp_mode_e* mode); + +/** +* @brief Gets the speed range. +* +* @param[out] min The minimun speed value +* @param[out] normal The normal speed value +* @param[out] max The maximum speed value +* +* @return 0 on success, otherwise a negative error value +* @retval #TTSP_ERROR_NONE Successful +* @retval #TTSP_ERROR_INVALID_PARAMETER Invalid parameter +* +*/ +typedef int (* ttspd_get_speed_range)(int* min, int* normal, int* max); + +/** +* @brief Gets the pitch range. +* +* @param[out] min The minimun pitch value +* @param[out] normal The normal pitch value +* @param[out] max The maximum pitch value +* +* @return 0 on success, otherwise a negative error value +* @retval #TTSP_ERROR_NONE Successful +* @retval #TTSP_ERROR_INVALID_PARAMETER Invalid parameter +* +*/ +typedef int (* ttspd_get_pitch_range)(int* min, int* normal, int* max); + /** * @brief A structure of the engine functions */ @@ -288,6 +324,9 @@ typedef struct { int size; /**< size */ int version; /**< version */ + ttspd_get_mode get_mode; /**< Get mode */ + ttspd_get_speed_range get_speed_range; /**< Get speed range */ + ttspd_get_pitch_range get_pitch_range; /**< Get pitch range */ }ttspd_funcs_s; /** diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b23f449..eb9b623 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,7 +11,8 @@ FOREACH(flag ${pkgs_test_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") FIND_PROGRAM(UNAME NAMES uname) EXEC_PROGRAM("${UNAME}" ARGS "-m" OUTPUT_VARIABLE "ARCH") @@ -24,4 +25,4 @@ ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_test_LDFLAGS} tts) -INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /opt/usr/devel/bin) \ No newline at end of file +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/share/voice/test) diff --git a/test/test_main.c b/test/test_main.c index 0c04033..113d898 100644 --- a/test/test_main.c +++ b/test/test_main.c @@ -45,37 +45,70 @@ static bool __tts_test_get_text_from_file(const char* path, char** text) int text_len = ftell(fp); if (0 >= text_len) { - SLOG(LOG_ERROR, tts_tag(), "File has no contents\n"); + SLOG(LOG_ERROR, tts_tag(), "File has no contents"); fclose(fp); return 0; } - SLOG(LOG_ERROR, tts_tag(), "text_len(%d)\n", text_len); + SLOG(LOG_ERROR, tts_tag(), "text_len(%d)", text_len); rewind(fp); - *text = (char*)calloc(1, text_len+1); + char* temp = NULL; + temp = (char*)calloc(1, text_len+1); - if (text == NULL) { - SLOG(LOG_ERROR, tts_tag(), "Fail to memory allocation\n"); + if (temp == NULL) { + SLOG(LOG_ERROR, tts_tag(), "Fail to memory allocation"); fclose(fp); return 0; } int result_len = 1; while (!feof(fp)) { - result_len = fread(*text, sizeof(char), text_len, fp); + result_len = fread(temp, sizeof(char), text_len, fp); if (result_len != text_len) { - SLOG(LOG_ERROR, tts_tag(), "Fail to read\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to read : result(%d) text_len(%d)", result_len, text_len); fclose(fp); + if (NULL != temp) { + free(temp); + temp = NULL; + } return 0; } } - *text[result_len] = '\0'; + temp[result_len] = '\0'; + + text = &temp; fclose(fp); return 1; } +Eina_Bool __tts_test_resume(void *data) +{ + int ret = tts_play(g_tts); + if (TTS_ERROR_NONE != ret) { + SLOG(LOG_ERROR, tts_tag(), "Fail to resume"); + ecore_timer_add(0, __tts_test_destroy, NULL); + return EINA_FALSE; + } + + return EINA_FALSE; +} + +Eina_Bool __tts_test_pause(void *data) +{ + int ret = tts_pause(g_tts); + if (TTS_ERROR_NONE != ret) { + SLOG(LOG_ERROR, tts_tag(), "Fail to pause"); + ecore_timer_add(0, __tts_test_destroy, NULL); + return EINA_FALSE; + } + + ecore_timer_add(3, __tts_test_resume, data); + + return EINA_FALSE; +} + Eina_Bool __tts_test_play(void *data) { int utt_id; @@ -86,41 +119,43 @@ Eina_Bool __tts_test_play(void *data) ret = tts_add_text(g_tts, g_text, lang, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &utt_id); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to add text\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to add text"); ecore_timer_add(0, __tts_test_destroy, NULL); return EINA_FALSE; } - SLOG(LOG_ERROR, tts_tag(), "Play : utt id(%d)\n", utt_id); + SLOG(LOG_ERROR, tts_tag(), "Play : utt id(%d)", utt_id); ret = tts_play(g_tts); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to play\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to play"); ecore_timer_add(0, __tts_test_destroy, NULL); return EINA_FALSE; } +// ecore_timer_add(1, __tts_test_pause, data); + return EINA_FALSE; } Eina_Bool __tts_test_destroy(void *data) { int ret; - SLOG(LOG_ERROR, tts_tag(), "Stop\n"); + SLOG(LOG_ERROR, tts_tag(), "Stop"); ret = tts_stop(g_tts); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to stop\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to stop"); } - SLOG(LOG_ERROR, tts_tag(), "Unprepare (Disconnection)\n"); + SLOG(LOG_ERROR, tts_tag(), "Unprepare (Disconnection)"); ret = tts_unprepare(g_tts); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to unprepare\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to unprepare"); } - SLOG(LOG_ERROR, tts_tag(), "Destory tts client\n"); + SLOG(LOG_ERROR, tts_tag(), "Destory tts client"); ret = tts_destroy(g_tts); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to destroy\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to destroy"); } ecore_main_loop_quit(); @@ -131,7 +166,7 @@ Eina_Bool __tts_test_destroy(void *data) static void __tts_test_state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data) { if (TTS_STATE_CREATED == previous && TTS_STATE_READY == current) { - SLOG(LOG_ERROR, tts_tag(), "State is ready after prepare\n"); + SLOG(LOG_ERROR, tts_tag(), "State is ready after prepare"); ecore_timer_add(0, __tts_test_play, user_data); } @@ -140,25 +175,24 @@ static void __tts_test_state_changed_cb(tts_h tts, tts_state_e previous, tts_sta static void __tts_test_utt_started_cb(tts_h tts, int utt_id, void* user_data) { - SLOG(LOG_DEBUG, tts_tag(), "Utterance started : utt id(%d) \n", utt_id); + SLOG(LOG_DEBUG, tts_tag(), "Utterance started : utt id(%d)", utt_id); return; } static void __tts_test_utt_completed_cb(tts_h tts, int utt_id, void* user_data) { - SLOG(LOG_DEBUG, tts_tag(), "Utterance completed : utt id(%d) \n", utt_id); + SLOG(LOG_DEBUG, tts_tag(), "Utterance completed : utt id(%d)", utt_id); ecore_timer_add(0, __tts_test_destroy, NULL); return; } -int main(int argc, char *argv[]) +int main (int argc, char *argv[]) { if (1 == argc || 5 < argc) { - SLOG(LOG_DEBUG, tts_tag(), "Please check parameter\n"); - SLOG(LOG_DEBUG, tts_tag(), "Ex> tts-test 'text'\n"); - SLOG(LOG_DEBUG, tts_tag(), "Specific mode> tts-test 'text' '-sr || -noti'\n"); + SLOG(LOG_DEBUG, tts_tag(), "Please check parameter"); + SLOG(LOG_DEBUG, tts_tag(), "Ex> tts-test -t 'text'"); return 0; } @@ -169,36 +203,34 @@ int main(int argc, char *argv[]) while (NULL != argv[n]) { - if (!strcmp("-h", argv[n])) { - SLOG(LOG_DEBUG, tts_tag(), "\n"); - SLOG(LOG_DEBUG, tts_tag(), " ==========================================\n"); - SLOG(LOG_DEBUG, tts_tag(), " TTS test usage\n"); - SLOG(LOG_DEBUG, tts_tag(), " ==========================================\n\n"); - SLOG(LOG_DEBUG, tts_tag(), " -t : Synthesize text \n"); - SLOG(LOG_DEBUG, tts_tag(), " -l : Determine langage to synthesize text, ex) en_US, ko_KR ...\n"); - SLOG(LOG_DEBUG, tts_tag(), " -f : Determine file path which include text\n\n"); - SLOG(LOG_DEBUG, tts_tag(), " ***************************************************\n"); - SLOG(LOG_DEBUG, tts_tag(), " Example : #tts-test -l en_US -t \"1 2 3 4\" \n"); - SLOG(LOG_DEBUG, tts_tag(), " ***************************************************\n"); - SLOG(LOG_DEBUG, tts_tag(), "\n"); + if(!strcmp("-h", argv[n])) { + SLOG(LOG_DEBUG, tts_tag(), " =========================================="); + SLOG(LOG_DEBUG, tts_tag(), " TTS test usage"); + SLOG(LOG_DEBUG, tts_tag(), " =========================================="); + SLOG(LOG_DEBUG, tts_tag(), " -t : Synthesize text"); + SLOG(LOG_DEBUG, tts_tag(), " -l : Determine langage to synthesize text, ex) en_US, ko_KR ..."); + SLOG(LOG_DEBUG, tts_tag(), " -f : Determine file path which include text"); + SLOG(LOG_DEBUG, tts_tag(), " ***************************************************"); + SLOG(LOG_DEBUG, tts_tag(), " Example : #tts-test -l en_US -t \"1 2 3 4\" "); + SLOG(LOG_DEBUG, tts_tag(), " ***************************************************"); return 0; } /* check langage option */ if (!strcmp("-l", argv[n])) { lang = TTS_STRDUP(argv[n+1]); - SLOG(LOG_ERROR, tts_tag(), "Language : %s\n", lang); + SLOG(LOG_ERROR, tts_tag(), "Language : %s", lang); } /* check text to synthesize */ else if (!strcmp("-t", argv[n])) { g_text = TTS_STRDUP(argv[n+1]); - SLOG(LOG_ERROR, tts_tag(), "Text : %s\n", g_text); + SLOG(LOG_ERROR, tts_tag(), "Text : %s", g_text); } /* check file path to synthesize */ else if (!strcmp("-f", argv[n])) { src_path = TTS_STRDUP(argv[n+1]); - SLOG(LOG_ERROR, tts_tag(), "File path : %s\n", src_path); - if (!__tts_test_get_text_from_file(src_path, &g_text)) { + SLOG(LOG_ERROR, tts_tag(), "File path : %s", src_path); + if(!__tts_test_get_text_from_file(src_path, &g_text)) { return 0; } } @@ -216,60 +248,60 @@ int main(int argc, char *argv[]) SLOG(LOG_DEBUG, tts_tag(), " "); SLOG(LOG_DEBUG, tts_tag(), " "); - SLOG(LOG_DEBUG, tts_tag(), "===== TTS Sample start =====\n"); + SLOG(LOG_DEBUG, tts_tag(), "===== TTS Sample start ====="); - SLOG(LOG_DEBUG, tts_tag(), "Input text : %s\n", g_text ? g_text : "NULL"); - SLOG(LOG_DEBUG, tts_tag(), "Input lang : %s\n", lang ? lang : "NULL"); - SLOG(LOG_DEBUG, tts_tag(), "Input file path : %s\n", src_path ? src_path : "NULL"); + SLOG(LOG_DEBUG, tts_tag(), "Input text : %s", g_text ? g_text : "NULL"); + SLOG(LOG_DEBUG, tts_tag(), "Input lang : %s", lang ? lang : "NULL"); + SLOG(LOG_DEBUG, tts_tag(), "Input file path : %s", src_path ? src_path : "NULL"); if (!ecore_init()) { - SLOG(LOG_ERROR, tts_tag(), "[Main ERROR] Fail ecore_init()\n"); + SLOG(LOG_ERROR, tts_tag(), "[Main ERROR] Fail ecore_init()"); return 0; } int ret; - SLOG(LOG_DEBUG, tts_tag(), "Create tts client\n"); + SLOG(LOG_DEBUG, tts_tag(), "Create tts client"); ret = tts_create(&g_tts); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to create\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to create"); return 0; } - SLOG(LOG_DEBUG, tts_tag(), "Set tts mode - %d\n", mode); + SLOG(LOG_DEBUG, tts_tag(), "Set tts mode - %d", mode); ret = tts_set_mode(g_tts, mode); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to set mode\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to set mode"); tts_destroy(g_tts); return 0; } - SLOG(LOG_DEBUG, tts_tag(), "Set Callback func\n"); + SLOG(LOG_DEBUG, tts_tag(), "Set Callback func"); ret = tts_set_state_changed_cb(g_tts, __tts_test_state_changed_cb, (void*)lang); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to set state changed cb\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to set state changed cb"); tts_destroy(g_tts); return 0; } ret = tts_set_utterance_started_cb(g_tts, __tts_test_utt_started_cb, NULL); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to set utt started cb\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to set utt started cb"); tts_destroy(g_tts); return 0; } ret = tts_set_utterance_completed_cb(g_tts, __tts_test_utt_completed_cb, NULL); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to set utt completed cb\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to set utt completed cb"); tts_destroy(g_tts); return 0; } - SLOG(LOG_DEBUG, tts_tag(), "Prepare (Daemon Connection) asynchronously : Wait for ready state \n"); + SLOG(LOG_DEBUG, tts_tag(), "Prepare (Daemon Connection) asynchronously : Wait for ready state"); ret = tts_prepare(g_tts); if (TTS_ERROR_NONE != ret) { - SLOG(LOG_ERROR, tts_tag(), "Fail to prepare\n"); + SLOG(LOG_ERROR, tts_tag(), "Fail to prepare"); tts_destroy(g_tts); return 0; } @@ -282,7 +314,7 @@ int main(int argc, char *argv[]) if (lang) free(lang); if (g_text) free(g_text); - SLOG(LOG_DEBUG, tts_tag(), "===== TTS END =====\n\n\n"); + SLOG(LOG_DEBUG, tts_tag(), "===== TTS END ====="); return 0; } -- 2.7.4