Send synthesized PCM data from TTS engine to client
[platform/core/uifw/tts.git] / server / ttsd_server.c
index d47a778..d87b4ce 100644 (file)
@@ -22,6 +22,7 @@
 #include "ttsd_engine_agent.h"
 #include "ttsd_main.h"
 #include "ttsd_player.h"
+#include "ttsd_state.h"
 #include "ttsd_server.h"
 
 
 #define TIME_DIFF(start, end) \
        ((uint64_t)((end).tv_sec - (start).tv_sec) * 1000000 + (((end).tv_nsec - (start).tv_nsec) / 1000)) / 1000
 
-static struct timespec g_request_playing, g_start_playing;
+static struct timespec g_request_playing, g_start_playing, g_finish_playing;
 static double g_avg_latency;
 static double g_min_latency;
 static double g_max_latency;
 static int g_file_num;
+static int g_total_data_size;
 
 typedef struct {
        unsigned int uid;
        int uttid;
 } utterance_t;
 
+typedef struct {
+       ttsd_state_e before;
+       ttsd_state_e current;
+} state_changed_args_t;
+
 /* If current engine exist */
 //static bool  g_is_engine;
 
 static Ecore_Timer* g_check_client_timer = NULL;
 static Ecore_Timer* g_wait_timer = NULL;
 static Ecore_Timer* g_quit_loop_timer = NULL;
+static Ecore_Timer* g_notify_state_timer = NULL;
 
 static utterance_t g_utt;
 
@@ -55,6 +63,7 @@ static GList *g_proc_list = NULL;
 
 static bool g_is_terminated = false;
 
+static int g_activated_mode = 0;
 
 /* Function definitions */
 static int __stop_and_send_ready_state(unsigned int uid)
@@ -158,6 +167,13 @@ static void __synthesis(unsigned int uid)
                g_wait_timer = ecore_timer_add(0.05, __wait_synthesis, (void*)credential);
        }
 
+       if (ttsd_data_get_synth_control() == TTSD_SYNTHESIS_CONTROL_DOING && ttsd_state_get_state() == TTSD_STATE_READY) {
+               int ret = vconf_set_bool(TTS_PLAYING_STATUS_KEY, 1);
+               SLOG(LOG_INFO, tts_tag(), "[Server] Synthesis starting. Set playing status (True). ret(%d)", ret);
+
+               ttsd_state_set_state(TTSD_STATE_SYNTHESIZING);
+       }
+
        free(credential);
        credential = NULL;
        ttsd_data_destroy_speak_data(speak_data);
@@ -198,6 +214,23 @@ int ttsd_send_error(ttse_error_e error, const char* msg)
        return 0;
 }
 
+static int ttsd_convert_audio_type_to_bytes(ttse_audio_type_e audio_type)
+{
+       int ret = 0;
+       switch (audio_type) {
+       case TTSE_AUDIO_TYPE_RAW_S16:
+               ret = 2; // 16bit
+               break;
+       case TTSE_AUDIO_TYPE_RAW_U8:
+               ret = 1; // 8bit
+               break;
+       default:
+               ret = 2; // Default 16bit
+               break;
+       }
+       return ret;
+}
+
 int ttsd_send_result(ttse_result_event_e event, const void* data, unsigned int data_size, ttse_audio_type_e audio_type, int rate, void* user_data)
 {
        SLOG(LOG_DEBUG, tts_tag(), "@@@ SEND SYNTHESIS RESULT START");
@@ -254,27 +287,51 @@ int ttsd_send_result(ttse_result_event_e event, const void* data, unsigned int d
                g_min_latency = (d_latency < g_min_latency) ? d_latency : g_min_latency;
                g_max_latency = (d_latency > g_max_latency) ? d_latency : g_max_latency;
                g_file_num++;
+               g_total_data_size = 0;
+               g_total_data_size += data_size;
                SLOG(LOG_INFO, tts_tag(), "[Server] File num(%d), Avg Latency(%lf), Min(%lf), Max(%lf)", g_file_num, (g_avg_latency / (double)g_file_num), g_min_latency, g_max_latency);
        } else if (TTSE_RESULT_EVENT_FINISH == event) {
                SLOG(LOG_INFO, tts_tag(), "[SERVER] Event : TTSE_RESULT_EVENT_FINISH");
                SECURE_SLOG(LOG_DEBUG, tts_tag(), "[SERVER] Result Info : uid(%u), utt(%d), data(%p), data size(%d) audiotype(%d) rate(%d)",
                        uid, uttid, data, data_size, audio_type, rate);
+
+               g_total_data_size += data_size;
+               int audio_type_bytes = ttsd_convert_audio_type_to_bytes(audio_type);
+               /* Calculate xRT */
+               clock_gettime(CLOCK_MONOTONIC_RAW, &g_finish_playing);
+               long long int time_processing = (uint64_t)TIME_DIFF(g_request_playing, g_finish_playing);
+               long long int time_speech = (long long int)(1000 * g_total_data_size * sizeof(short) / (rate * audio_type_bytes));
+               double xRT = (double)(time_processing) / (double)time_speech;
+               SLOG(LOG_INFO, tts_tag(), "[SERVER] time_processing : %lld, time_speech : %lld, total data size: %d", time_processing, time_speech, g_total_data_size);
+               SLOG(LOG_INFO, tts_tag(), "[SERVER] xRT : %lf", xRT);
        } else {
                /*if (TTSE_RESULT_EVENT_CONTINUE == event)  SLOG(LOG_DEBUG, tts_tag(), "[SERVER] Event : TTSE_RESULT_EVENT_CONTINUE");*/
+               g_total_data_size += data_size;
        }
 
-       /* add wav data */
-       sound_data_s* sound_data = ttsd_data_create_sound_data(uttid, data, data_size, event, audio_type, rate, 0);
-       if (NULL == sound_data) {
-               SLOG(LOG_ERROR, tts_tag(), "[SERVER ERROR] Out of memory");
-               return TTSD_ERROR_OUT_OF_MEMORY;
-       }
+       ttsd_playing_mode_e playing_mode = ttsd_data_get_playing_mode(uid);
+       SLOG(LOG_DEBUG, tts_tag(), "[SERVER] uid(%d), playing mode(%d)", uid, playing_mode);
+       if (TTSD_PLAYING_MODE_BY_SERVICE == playing_mode) {
+               /* add wav data */
+               sound_data_s* sound_data = ttsd_data_create_sound_data(uttid, data, data_size, event, audio_type, rate, 0);
+               if (NULL == sound_data) {
+                       SLOG(LOG_ERROR, tts_tag(), "[SERVER ERROR] Out of memory");
+                       return TTSD_ERROR_OUT_OF_MEMORY;
+               }
 
-       if (0 != ttsd_data_add_sound_data(uid, sound_data)) {
-               SECURE_SLOG(LOG_ERROR, tts_tag(), "[SERVER ERROR] Fail to add sound data : uid(%u)", uid);
-               ttsd_data_destroy_sound_data(sound_data);
+               if (0 != ttsd_data_add_sound_data(uid, sound_data)) {
+                       SECURE_SLOG(LOG_ERROR, tts_tag(), "[SERVER ERROR] Fail to add sound data : uid(%u)", uid);
+                       ttsd_data_destroy_sound_data(sound_data);
 
-               return TTSD_ERROR_OPERATION_FAILED;
+                       return TTSD_ERROR_OPERATION_FAILED;
+               }
+       } else { /* TTSD_PLAYING_MODE_BY_CLIENT */
+               /* send pcm data to client */
+               int tmp_pid = ttsd_data_get_pid(uid);
+               if (0 != ttsdc_ipc_send_pcm(tmp_pid, uid, uttid, event, data, data_size, audio_type, rate)) {
+                       SLOG(LOG_ERROR, tts_tag(), "[SERVER ERROR] Fail to send pcm data to client");
+                       return TTSD_ERROR_OPERATION_FAILED;
+               }
        }
 
        if (event == TTSE_RESULT_EVENT_FINISH) {
@@ -543,6 +600,49 @@ static Eina_Bool __cleanup_client(void *data)
        return EINA_TRUE;
 }
 
+static bool __notify_state_changed_event(int pid, unsigned int uid, app_tts_state_e state, void* user_data)
+{
+       state_changed_args_t* args = (state_changed_args_t*)user_data;
+       if (NULL == args) {
+               return false;
+       }
+
+       if (ttsd_data_is_service_state_changed_cb_set(uid)) {
+               ttsdc_ipc_send_set_service_state_message(pid, uid, args->before, args->current);
+       }
+
+       return true;
+}
+
+static Eina_Bool __state_changed_timer_cb(void *data)
+{
+       if (NULL == data) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server] Invalid data passed.");
+               return ECORE_CALLBACK_CANCEL;
+       }
+
+       int ret = ttsd_data_foreach_clients(__notify_state_changed_event, data);
+       if (TTSD_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server] Fail to notify state change.");
+       }
+
+       free(data);
+       g_notify_state_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
+}
+
+static void __state_changed_cb(ttsd_state_e before, ttsd_state_e current)
+{
+       state_changed_args_t* args = (state_changed_args_t*)calloc(1, sizeof(state_changed_args_t));
+       if (NULL != args) {
+               args->before = before;
+               args->current = current;
+       }
+
+       SLOG(LOG_INFO, tts_tag(), "[Server] Notify state chanaged from (%d) to (%d).", before, current);
+       g_notify_state_timer = ecore_timer_add(0.0, __state_changed_timer_cb, args);
+}
+
 /*
 * Server APIs
 */
@@ -555,6 +655,10 @@ int ttsd_initialize(ttse_request_callback_s *callback)
                SLOG(LOG_ERROR, tts_tag(), "[Server WARNING] Fail to initialize config.");
        }
 
+       if (TTSD_ERROR_NONE != ttsd_state_initialize(__state_changed_cb)) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server WARNING] Fail to initialize state.");
+       }
+
        /* player init */
        if (ttsd_player_init()) {
                SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to initialize player init.");
@@ -573,16 +677,11 @@ int ttsd_initialize(ttse_request_callback_s *callback)
        }
 
        /* Engine Agent initialize */
-       if (0 != ttsd_engine_agent_init()) {
+       if (TTSD_ERROR_NONE != ttsd_engine_agent_init(callback)) {
                SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to engine agent initialize.");
                return TTSD_ERROR_OPERATION_FAILED;
        }
 
-       if (0 != ttsd_engine_agent_load_current_engine(callback)) {
-               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to load current engine");
-               return TTSD_ERROR_OPERATION_FAILED;
-       }
-
        ttsd_data_set_synth_control(TTSD_SYNTHESIS_CONTROL_EXPIRED);
        ttsd_config_set_screen_reader_callback(__screen_reader_changed_cb);
 
@@ -591,6 +690,8 @@ int ttsd_initialize(ttse_request_callback_s *callback)
                SLOG(LOG_WARN, tts_tag(), "[WARNING] Fail to create timer");
        }
 
+       g_activated_mode = 0;
+
        return TTSD_ERROR_NONE;
 }
 
@@ -608,6 +709,14 @@ int ttsd_finalize()
                }
        }
 
+       if (g_notify_state_timer) {
+               void* data = ecore_timer_del(g_notify_state_timer);
+               g_notify_state_timer = NULL;
+
+               free(data);
+               SLOG(LOG_INFO, tts_tag(), "[INFO] Delete ecore notify state timer handle");
+       }
+
        if (g_wait_timer) {
                ecore_timer_del(g_wait_timer);
                g_wait_timer = NULL;
@@ -627,6 +736,7 @@ int ttsd_finalize()
        }
 
        ttsd_config_finalize();
+       ttsd_state_finalize();
 
        int ret = TTSD_ERROR_NONE;
        ret = ttsd_player_release();
@@ -677,7 +787,52 @@ int ttsd_server_is_already_initialized(int pid, unsigned int uid, bool* is_initi
        return TTSD_ERROR_NONE;
 }
 
-int ttsd_server_initialize(int pid, unsigned int uid, ttsd_mode_e mode, tts_ipc_method_e method, bool* credential_needed)
+static void __set_and_notify_activated_mode()
+{
+       int activated_mode = ttsd_data_get_activated_mode();
+       if (g_activated_mode == activated_mode) {
+               return;
+       }
+
+       SLOG(LOG_INFO, tts_tag(), "[Server] Activated mode is changed from(%d) to (%d)", g_activated_mode, activated_mode);
+
+       g_activated_mode = activated_mode;
+       int ret = ttsd_engine_notify_activated_mode_changed(g_activated_mode);
+       if (TTSD_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to notify activated mode changed event.(%d)", ret);
+       }
+}
+
+static int __check_app_agreed(int pid, unsigned int uid, bool credential_needed)
+{
+       if (false == credential_needed) {
+               return TTSD_ERROR_NONE;
+       }
+
+       char* appid = NULL;
+       if (APP_MANAGER_ERROR_NONE != app_manager_get_app_id(pid, &appid)) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to get app id, pid(%d)", pid);
+       }
+
+       bool is_agreed = false;
+       int ret = ttsd_engine_check_app_agreed(appid, &is_agreed);
+       free(appid);
+       appid = NULL;
+
+       if (TTSD_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, tts_tag(), "Server ERROR] Fail to check app agreed");
+               return TTSD_ERROR_OPERATION_FAILED;
+       }
+
+       if (false == is_agreed) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] App is not agreed");
+               return TTSD_ERROR_PERMISSION_DENIED;
+       }
+
+       return TTSD_ERROR_NONE;
+}
+
+int ttsd_server_initialize(int pid, unsigned int uid, ttsd_mode_e mode, ttsd_playing_mode_e playing_mode, int registered_event_mask, tts_ipc_method_e method, ttsd_state_e* service_state, bool* credential_needed)
 {
        SLOG(LOG_INFO, tts_tag(), "[Server] Server initialize");
 
@@ -686,37 +841,43 @@ int ttsd_server_initialize(int pid, unsigned int uid, ttsd_mode_e mode, tts_ipc_
                return TTSD_ERROR_NONE;
        }
 
-       if (0 != ttsd_engine_agent_is_credential_needed(uid, credential_needed)) {
-               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to get credential necessity");
+       if (TTSD_ERROR_NONE != ttsd_data_new_client(pid, uid, mode, playing_mode, registered_event_mask, method)) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to add client info");
                return TTSD_ERROR_OPERATION_FAILED;
        }
 
-       if (true == *credential_needed) {
-               char* appid = NULL;
-               if (0 != app_manager_get_app_id(pid, &appid)) {
-                       SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to get app id, pid(%d)", pid);
-               }
-               bool is_agreed = false;
-               if (0 != ttsd_engine_check_app_agreed(appid, &is_agreed)) {
-                       SLOG(LOG_ERROR, tts_tag(), "Server ERROR] Fail to check app agreed");
-                       if (!appid)
-                               free(appid);
-                       return TTSD_ERROR_OPERATION_FAILED;
-               }
-               if (!appid)
-                       free(appid);
+       __set_and_notify_activated_mode();
 
-               if (false == is_agreed) {
-                       SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] App is not agreed");
-                       return TTSD_ERROR_PERMISSION_DENIED;
-               }
+       if (TTSD_ERROR_NONE != ttsd_engine_agent_load_current_engine()) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to load current engine");
+               ttsd_data_delete_client(uid);
+               return TTSD_ERROR_OPERATION_FAILED;
        }
 
-       if (0 != ttsd_data_new_client(pid, uid, mode, method)) {
-               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to add client info");
+       bool is_needed = false;
+       if (TTSD_ERROR_NONE != ttsd_engine_agent_is_credential_needed(uid, &is_needed)) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to get credential necessity");
+               ttsd_data_delete_client(uid);
+               return TTSD_ERROR_OPERATION_FAILED;
+       }
+
+       int ret = __check_app_agreed(pid, uid, is_needed);
+       if (TTSD_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Checking credential is finished(%d)", ret);
+               ttsd_data_delete_client(uid);
+               return ret;
+       }
+
+       ttsd_state_e tmp_service_state = ttsd_state_get_state();
+       if (TTSD_STATE_INVALID == tmp_service_state) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to get state");
+               ttsd_data_delete_client(uid);
                return TTSD_ERROR_OPERATION_FAILED;
        }
 
+       *credential_needed = is_needed;
+       *service_state = tmp_service_state;
+
        return TTSD_ERROR_NONE;
 }
 
@@ -749,6 +910,7 @@ int ttsd_server_finalize(unsigned int uid)
        }
 
        ttsd_data_delete_client(uid);
+       __set_and_notify_activated_mode();
 
        /* unload engine, if ref count of client is 0 */
        if (0 == ttsd_data_get_client_count()) {
@@ -763,6 +925,28 @@ int ttsd_server_finalize(unsigned int uid)
        return TTSD_ERROR_NONE;
 }
 
+int ttsd_server_update_instant_reprepare_client()
+{
+       SLOG(LOG_INFO, tts_tag(), "[Server] Update instant reprepare client");
+       unsigned int instant_reprepare_uid = TTS_INVALID_UID;
+       ttsd_config_get_instant_reprepare_client(&instant_reprepare_uid);
+
+       if (0 <= ttsd_data_is_client(instant_reprepare_uid)) {
+               SLOG(LOG_INFO, tts_tag(), "[Server] Uid(%u) is valid. Still no need to changee the value", instant_reprepare_uid);
+               return TTSD_ERROR_NONE;
+       }
+
+       unsigned int new_instant_reprepare_uid = ttsd_data_get_first_client_uid();
+       int ret = ttsd_config_set_instant_reprepare_client(new_instant_reprepare_uid);
+       if (TTSD_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server] Fail to set UID(%u) of instant reprepare client", instant_reprepare_uid);
+               return TTSD_ERROR_OPERATION_FAILED;
+       }
+       SLOG(LOG_INFO, tts_tag(), "[Server] Update UID(%u) of instant reprepare client", instant_reprepare_uid);
+
+       return TTSD_ERROR_NONE;
+}
+
 static bool __is_connected_to_network()
 {
        /* Check network */
@@ -1160,6 +1344,26 @@ int ttsd_set_private_data_requested_cb(ttse_private_data_requested_cb callback)
        return ret;
 }
 
+int ttsd_get_activated_mode(int* activated_mode)
+{
+       if (NULL == activated_mode) {
+               return TTSD_ERROR_INVALID_PARAMETER;
+       }
+
+       *activated_mode = ttsd_data_get_activated_mode();
+       return TTSD_ERROR_NONE;
+}
+
+int ttsd_set_activated_mode_changed_cb(ttse_activated_mode_changed_cb callback)
+{
+       int ret = ttsd_engine_agent_set_activated_mode_changed_cb(callback);
+       if (TTSD_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to set private data requested cb : ret(%d)", ret);
+       }
+
+       return ret;
+}
+
 int ttsd_server_play_pcm(unsigned int uid)
 {
        app_tts_state_e state = ttsd_data_get_client_state(uid);
@@ -1242,3 +1446,16 @@ int ttsd_server_add_pcm(unsigned int uid, int event, void* data, int data_size,
 
        return TTSD_ERROR_NONE;
 }
+
+int ttsd_server_get_service_state(unsigned int uid, int* service_state)
+{
+       if (0 > ttsd_data_is_client(uid)) {
+               SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] ttsd_server_get_service_state : uid is not valid");
+               return TTSD_ERROR_INVALID_PARAMETER;
+       }
+
+       *service_state = (int)ttsd_state_get_state();
+       SLOG(LOG_DEBUG, tts_tag(), "[Server] Get current service state. service state(%d) ", *service_state);
+
+       return TTSD_ERROR_NONE;
+}