+++ /dev/null
-/*
-* Copyright (c) 2011-2016 Samsung Electronics Co., Ltd All Rights Reserved
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-* http://www.apache.org/licenses/LICENSE-2.0
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#include <audio_io.h>
-#include <Ecore.h>
-#include <sound_manager.h>
-#include <sound_manager_internal.h>
-#include <pthread.h>
-#include <time.h>
-
-#include "ttsd_main.h"
-#include "ttsd_player.h"
-#include "ttsd_data.h"
-#include "ttsd_dbus.h"
-#include "ttsd_ipc.h"
-
-#include "tts_internal.h"
-#include "ttsd_server.h"
-
-/*
-* Internal data structure
-*/
-
-typedef enum {
- AUDIO_STATE_NONE = 0,
- AUDIO_STATE_READY,
- AUDIO_STATE_WAIT_FOR_PLAYING,
- AUDIO_STATE_PLAY
-} audio_state_e;
-
-typedef struct {
- unsigned int uid; /** client id */
- app_tts_state_e state; /** client state */
-
- /* Current utterance information */
- ttse_result_event_e event; /** event of last utterance */
-
- bool is_paused_data;
- int idx;
- sound_data_s* paused_data;
-} player_s;
-
-#define SOUND_BUFFER_LENGTH 2048
-#define FOCUS_SERVER_READY "/tmp/.sound_server_ready"
-
-static const intptr_t CHECK_TIMER_DELETE = 1;
-static const int EXTRA_INFO_LENGTH = 20;
-
-/* Sound buf save for test */
-/*
-#define BUF_SAVE_MODE
-*/
-
-#ifdef BUF_SAVE_MODE
-static char g_temp_file_name[128] = {'\0',};
-static FILE* g_pFile;
-static int g_count = 0;
-static pthread_mutex_t g_buf_save_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-/** player init info */
-static bool g_player_init = false;
-
-/** Client list */
-static GList *g_player_list;
-
-/** current player information */
-static player_s* g_playing_info;
-
-/* player state */
-static audio_state_e g_audio_state;
-
-static ttse_audio_type_e g_audio_type;
-
-static int g_sampling_rate;
-
-static audio_out_h g_audio_h;
-
-static sound_stream_info_h g_stream_info_h;
-
-static sound_stream_ducking_h g_media_stream_ducking;
-//static sound_stream_ducking_h g_system_stream_ducking;
-static sound_stream_ducking_h g_notification_stream_ducking;
-static sound_stream_ducking_h g_alarm_stream_ducking;
-
-static bool g_is_set_policy;
-
-// static bool ducking_flag;
-
-/* CAUTION!
-If you change this constant value. Please check the function '__set_timer_for_delay_recover()'.
-If you choose too big value, it may cause integer overflow issue.
-*/
-#define SND_MGR_DUCKING_DURATION 500
-
-static struct timespec g_policy_set_time;
-static Ecore_Timer* g_delayed_unset_policy_timer = NULL;
-static Ecore_Timer* g_modify_background_volume = NULL;
-
-static double g_bg_volume_ratio;
-
-static pthread_mutex_t g_play_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t g_player_control_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static pthread_cond_t g_play_thread_cond = PTHREAD_COND_INITIALIZER;
-/*
-* Internal Interfaces
-*/
-static void __set_playing_status(bool is_playing)
-{
- int ret = vconf_set_bool(TTS_PLAYING_STATUS_KEY, is_playing ? 1 : 0);
- SLOG(LOG_INFO, tts_tag(), "[Player] Set playing status (%s). ret(%d)", is_playing ? "True" : "False", ret);
-}
-
-#ifdef BUF_SAVE_MODE
-static void __open_buffer_dump_file()
-{
- pthread_mutex_lock(&g_buf_save_mutex);
- if (g_pFile) {
- SLOG(LOG_ERROR, tts_tag(), "[Buffer Dump] File is already opened(%s)", g_temp_file_name);
- pthread_mutex_unlock(&g_buf_save_mutex);
- return;
- }
-
- g_count++;
- while (1) {
- snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/tts_temp_%d_%d", getpid(), g_count);
- int ret = access(g_temp_file_name, 0);
-
- if (0 == ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Recorder ERROR] File is already exist");
- if (0 == remove(g_temp_file_name)) {
- SLOG(LOG_DEBUG, tts_tag(), "[Recorder] Remove file");
- break;
- } else {
- g_count++;
- }
- } else {
- break;
- }
- }
-
- SECURE_SLOG(LOG_DEBUG, tts_tag(), "[Recorder] Temp file name=[%s]", g_temp_file_name);
-
- /* open test file */
- g_pFile = fopen(g_temp_file_name, "wb+x");
- if (NULL == g_pFile) {
- SLOG(LOG_ERROR, tts_tag(), "[Recorder ERROR] File not found!");
- }
-
- pthread_mutex_unlock(&g_buf_save_mutex);
-}
-
-static void __close_buffer_dump_file()
-{
- pthread_mutex_lock(&g_buf_save_mutex);
-
- if (g_pFile) {
- fclose(g_pFile);
- g_pFile = NULL;
- }
-
- pthread_mutex_unlock(&g_buf_save_mutex);
-}
-
-static void __write_buffer_dump_file(const void* buffer, size_t length)
-{
- pthread_mutex_lock(&g_buf_save_mutex);
-
- if (g_pFile) {
- size_t ret = fwrite(buffer, 1, length, g_pFile);
- SLOG(LOG_DEBUG, tts_tag(), "[Buffer Dump] Stored size(%zu / %zu)", ret, length);
- } else {
- SLOG(LOG_ERROR, tts_tag(), "[Buffer Dump] File is not opened. Please check the file open");
- }
-
- pthread_mutex_unlock(&g_buf_save_mutex);
-}
-#endif
-
-static bool __is_player_valid(player_s* player)
-{
- if (NULL == player || NULL == g_playing_info) {
- SLOG(LOG_ERROR, tts_tag(), "[ERROR] player is NULL");
- return false;
- }
-
- if (g_playing_info != player || g_playing_info->uid != player->uid) {
- SLOG(LOG_ERROR, tts_tag(), "[ERROR] player is not current player");
- return false;
- }
-
- return true;
-}
-
-player_s* __player_get_item(unsigned int uid)
-{
- GList *iter = NULL;
- player_s *data = NULL;
-
- if (0 < g_list_length(g_player_list)) {
- /* Get a first item */
- iter = g_list_first(g_player_list);
-
- while (NULL != iter) {
- /* Get handle data from list */
- data = (player_s*)iter->data;
-
- /* compare uid */
- if (uid == data->uid)
- return data;
-
- /* Get next item */
- iter = g_list_next(iter);
- }
- }
-
- return NULL;
-}
-
-static bool __is_focus_released_on_playing(sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state)
-{
- if (NULL == g_playing_info) {
- SLOG(LOG_INFO, tts_tag(), "[Player] No current player");
- return false;
- }
-
- if (APP_STATE_PLAYING != g_playing_info->state || AUDIO_STATE_NONE == g_audio_state || AUDIO_STATE_READY == g_audio_state) {
- SLOG(LOG_INFO, tts_tag(), "[Player] Audio is not played");
- return false;
- }
-
- if (SOUND_STREAM_FOCUS_FOR_PLAYBACK != focus_mask || SOUND_STREAM_FOCUS_STATE_RELEASED != focus_state) {
- SLOG(LOG_INFO, tts_tag(), "[Player] Playback focus is not released");
- return false;
- }
-
- return true;
-}
-
-static void __player_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
- sound_stream_focus_change_reason_e reason_for_change, int sound_behavior, const char *extra_info, void *user_data)
-{
- SLOG(LOG_DEBUG, tts_tag(), "@@@ Focus state changed cb");
- SLOG(LOG_WARN, tts_tag(), "[Player] focus state changed to (%d) with reason(%d) and extra info(%s)", (int)focus_state, (int)reason_for_change, extra_info);
-
- if (stream_info != g_stream_info_h) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Invalid stream info handle");
- return;
- }
-
- if (false == __is_focus_released_on_playing(focus_mask, focus_state)) {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Playback focus is not released on playing");
- return;
- }
-
- unsigned int uid = g_playing_info->uid;
- ttsd_mode_e mode = ttsd_data_get_mode(uid);
-
- switch (mode) {
- case TTSD_MODE_DEFAULT:
- SLOG(LOG_DEBUG, tts_tag(), "[Player] Pause current player - mode(%d)", mode);
- g_audio_state = AUDIO_STATE_READY;
-
- if (0 != ttsd_player_pause(uid)) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to pause the player");
- break;
- }
-
- ttsd_data_set_client_state(uid, APP_STATE_PAUSED);
- int pid = ttsd_data_get_pid(uid);
- if (pid <= 0) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to get pid. uid(%u)", uid);
- } else {
- /* send message to client about changing state */
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Player paused. pid(%d), uid(%u)", pid, uid);
- ttsdc_ipc_send_set_state_message(pid, uid, APP_STATE_PAUSED);
- }
- break;
- case TTSD_MODE_NOTIFICATION:
- case TTSD_MODE_SCREEN_READER:
- SLOG(LOG_DEBUG, tts_tag(), "[Player] Stop current player - mode(%d)", mode);
- g_audio_state = AUDIO_STATE_READY;
- ttsd_send_all_stop();
- break;
- case TTSD_MODE_INTERRUPT:
- SLOG(LOG_DEBUG, tts_tag(), "[Player] Ignore focus release - mode(%d)", mode);
- break;
- default:
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Invalid mode - mode(%d)", mode);
- break;
- }
-
- SLOG(LOG_DEBUG, tts_tag(), "@@@");
-
- return;
-}
-
-void __sound_stream_ducking_state_changed_cb(sound_stream_ducking_h stream_ducking, bool is_ducked, void *user_data)
-{
- SLOG(LOG_DEBUG, tts_tag(), "@@@ ducking state changed cb");
- SLOG(LOG_ERROR, tts_tag(), "[Player] ducking_h(%p) is ducked : %d", stream_ducking, is_ducked);
- // ducking_flag = true;
- return;
-}
-
-static char* __get_ducking_stream(sound_stream_type_e stream_type)
-{
- if (SOUND_STREAM_TYPE_MEDIA == stream_type)
- return "Media stream";
- else if (SOUND_STREAM_TYPE_SYSTEM == stream_type)
- return "System stream";
- else if (SOUND_STREAM_TYPE_NOTIFICATION == stream_type)
- return "Notification stream";
- else if (SOUND_STREAM_TYPE_ALARM == stream_type)
- return "Alarm stream";
- return "Non matched stream";
-}
-
-static int __activate_ducking_sound_stream(sound_stream_type_e stream_type, sound_stream_ducking_h stream_ducking_h, unsigned int duration)
-{
- bool is_ducked = false;
- int ret = sound_manager_is_ducked(stream_ducking_h, &is_ducked);
- if (is_ducked) {
- SLOG(LOG_DEBUG, tts_tag(), "[Player] The %s is already ducked", __get_ducking_stream(stream_type));
- } else {
- ret = sound_manager_activate_ducking(stream_ducking_h, duration, g_bg_volume_ratio);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to activate ducking for %s", __get_ducking_stream(stream_type));
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Activate ducking for %s", __get_ducking_stream(stream_type));
- }
- }
- return ret;
-}
-
-static void __change_background_volume(unsigned int duration)
-{
- SLOG(LOG_INFO, tts_tag(), "[BG] Change background volume");
- SLOG(LOG_INFO, tts_tag(), "[Player] volume ratio(%lf)", g_bg_volume_ratio);
- if (1.0 > g_bg_volume_ratio) {
- __activate_ducking_sound_stream(SOUND_STREAM_TYPE_MEDIA, g_media_stream_ducking, duration);
-// __activate_ducking_sound_stream(SOUND_STREAM_TYPE_SYSTEM, g_system_stream_ducking, duration);
- __activate_ducking_sound_stream(SOUND_STREAM_TYPE_NOTIFICATION, g_notification_stream_ducking, duration);
- __activate_ducking_sound_stream(SOUND_STREAM_TYPE_ALARM, g_alarm_stream_ducking, duration);
- }
-}
-
-static void __change_background_volume_async(void* data)
-{
- __change_background_volume(SND_MGR_DUCKING_DURATION);
-}
-
-static int __deactivate_ducking_sound_stream(sound_stream_type_e stream_type, sound_stream_ducking_h stream_ducking_h)
-{
- bool is_ducked = false;
- int ret = sound_manager_is_ducked(stream_ducking_h, &is_ducked);
- if (!is_ducked) {
- SLOG(LOG_DEBUG, tts_tag(), "[Player] The %s is already recovered from ducking", __get_ducking_stream(stream_type));
- } else {
- ret = sound_manager_deactivate_ducking(stream_ducking_h);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to deactivate ducking for %s", __get_ducking_stream(stream_type));
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Deactivate ducking for %s", __get_ducking_stream(stream_type));
- }
- }
- return ret;
-}
-
-static void __recover_background_volume()
-{
- __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_MEDIA, g_media_stream_ducking);
-// __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_SYSTEM, g_system_stream_ducking);
- __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_NOTIFICATION, g_notification_stream_ducking);
- __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_ALARM, g_alarm_stream_ducking);
-}
-
-static int __create_audio_out(ttse_audio_type_e type, int rate)
-{
- int ret = -1;
- audio_sample_type_e sample_type;
-
- if (TTSE_AUDIO_TYPE_RAW_S16 == type) {
- sample_type = AUDIO_SAMPLE_TYPE_S16_LE;
- } else {
- sample_type = AUDIO_SAMPLE_TYPE_U8;
- }
-
- ret = audio_out_create_new(rate, AUDIO_CHANNEL_MONO, sample_type, &g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- g_audio_state = AUDIO_STATE_NONE;
- g_audio_h = NULL;
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create audio");
- return -1;
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Create audio");
- }
-
- g_audio_type = type;
- g_sampling_rate = rate;
-
- g_audio_state = AUDIO_STATE_READY;
-
- return 0;
-}
-
-static int __destroy_audio_out()
-{
- if (NULL == g_audio_h) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Current handle is not valid");
- return -1;
- }
-
- int ret = -1;
- ret = audio_out_destroy(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to destroy audio");
- return -1;
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Destroy audio");
- }
-
- g_audio_type = 0;
- g_sampling_rate = 0;
-
- g_audio_state = AUDIO_STATE_NONE;
- g_audio_h = NULL;
-
- return 0;
-}
-
-static void __end_play_thread(void *data, Ecore_Thread *thread)
-{
- SLOG(LOG_ERROR, tts_tag(), "@@@ End thread");
-}
-
-static void __del_timer_for_delayed_recover(void* data)
-{
- if (NULL != g_delayed_unset_policy_timer) {
- int result = (intptr_t)ecore_timer_del(g_delayed_unset_policy_timer);
- g_delayed_unset_policy_timer = NULL;
- SLOG(LOG_ERROR, tts_tag(), "[BG] Remove timer (%d)", result);
- }
-}
-
-static void __set_policy_for_playing(void)
-{
- ecore_main_loop_thread_safe_call_async(__del_timer_for_delayed_recover, NULL);
-
- /* Set stream info */
- char* extra_info = NULL;
- if (TTSD_MODE_INTERRUPT == ttsd_get_mode()) {
- extra_info = "TTSD_MODE_INTERRUPT";
- }
-
- int ret = sound_manager_acquire_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, extra_info);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to acquire focus");
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Success to acquire focus");
- }
-
- ret = audio_out_set_sound_stream_info(g_audio_h, g_stream_info_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to set stream info");
- }
-
- ecore_main_loop_thread_safe_call_async(__change_background_volume_async, NULL);
-
- g_is_set_policy = true;
- SLOG(LOG_ERROR, tts_tag(), "[BG] g_is_set_policy(%d)", g_is_set_policy);
-
- clock_gettime(CLOCK_MONOTONIC, &g_policy_set_time);
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] set policy for playing");
-
- return;
-}
-
-static Eina_Bool __delay_recover_background_volume(void* data)
-{
- __recover_background_volume();
- SLOG(LOG_INFO, tts_tag(), "[BG] Delayed unset policy success");
-
- g_delayed_unset_policy_timer = NULL;
- return EINA_FALSE;
-}
-
-static long long int __get_duration_from_last_volume_change()
-{
- struct timespec current_time;
- clock_gettime(CLOCK_MONOTONIC, ¤t_time);
-
- long long int diff = ((long long int)current_time.tv_sec - (long long int)g_policy_set_time.tv_sec) * 1000
- + ((long long int)current_time.tv_nsec - (long long int)g_policy_set_time.tv_nsec) / 1000000;
- SLOG(LOG_INFO, tts_tag(), "[BG] Time Diff(%lld)", diff);
-
- return diff;
-}
-
-static void __set_timer_for_delay_recover(void* data)
-{
- if (NULL != g_delayed_unset_policy_timer) {
- return;
- }
-
- long long int diff = __get_duration_from_last_volume_change();
- if (diff > SND_MGR_DUCKING_DURATION) {
- SLOG(LOG_INFO, tts_tag(), "[BG] Direct unset policy");
- __recover_background_volume();
- } else {
- double delay = (double)(SND_MGR_DUCKING_DURATION - diff) / 1000.0;
- g_delayed_unset_policy_timer = ecore_timer_add(delay, __delay_recover_background_volume, (void*)CHECK_TIMER_DELETE);
- SLOG(LOG_INFO, tts_tag(), "[BG] Delayed unset policy (%p), delay(%f)", g_delayed_unset_policy_timer, delay);
- }
-}
-
-static void __unset_policy_for_playing()
-{
- /* Unset stream info */
- sound_stream_focus_state_e state_for_playing = SOUND_STREAM_FOCUS_STATE_ACQUIRED;
- int ret = sound_manager_get_focus_state(g_stream_info_h, &state_for_playing, NULL);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to get focus state: %d", ret);
- }
-
- if (SOUND_STREAM_FOCUS_STATE_ACQUIRED == state_for_playing) {
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] release focus (mode: %d)", ttsd_get_mode());
- ret = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to release focus: %d", ret);
- }
- }
-
- ecore_main_loop_thread_safe_call_async(__set_timer_for_delay_recover, NULL);
-
- g_is_set_policy = false;
- SLOG(LOG_ERROR, tts_tag(), "[BG] g_is_set_policy(%d)", g_is_set_policy);
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] unset policy for playing");
-
- return;
-}
-
-static bool __does_interrupt_have_focus(sound_stream_focus_change_reason_e reason, int sound_behavior, char *extra_info)
-{
- SLOG(LOG_DEBUG, tts_tag(), "[Player] current Playback focus: extra_info(%s), reason(%d), sound_behavior(%d)", extra_info, reason, sound_behavior);
- if (SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION != reason) {
- return false;
- }
-
- if (NULL == extra_info || 0 >= strlen(extra_info) || 0 != strncmp(extra_info, "TTSD_MODE_INTERRUPT", EXTRA_INFO_LENGTH)) {
- return false;
- }
-
- return true;
-}
-
-bool ttsd_player_does_interrupt_have_playback_focus()
-{
- sound_stream_focus_change_reason_e reason;
- int sound_behavior = 0;
- char *extra_info = NULL;
- if (SOUND_MANAGER_ERROR_NONE != sound_manager_get_current_playback_focus(&reason, &sound_behavior, &extra_info)) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to get focus information");
- return false;
- }
-
- bool result = __does_interrupt_have_focus(reason, sound_behavior, extra_info);
- free(extra_info);
- return result;
-}
-
-static void __play_thread_old(void *data, Ecore_Thread *thread)
-{
- SLOG(LOG_DEBUG, tts_tag(), "@@@ Start thread");
-
- if (NULL == g_playing_info) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] No current player");
- return;
- }
-
- player_s* player = g_playing_info;
- sound_data_s* sound_data = NULL;
-
- int ret = -1;
- int len = SOUND_BUFFER_LENGTH;
- int idx = 0;
-
- /* set volume policy as 40% */
- __set_policy_for_playing();
- while (1) { // 1st while(1)
- /* check g_playing_info one more time */
- if (false == __is_player_valid(player)) {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Player is not valid");
- g_audio_state = AUDIO_STATE_READY;
- ret = audio_out_unprepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- }
- __unset_policy_for_playing();
- return;
- }
-
- if (true == player->is_paused_data && NULL != player->paused_data) {
- /* Resume player */
- sound_data_s* paused_data = player->paused_data;
- player->paused_data = NULL;
-
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = ttsd_data_create_sound_data(paused_data->utt_id, paused_data->data, paused_data->data_size,
- paused_data->event, paused_data->audio_type, paused_data->rate, paused_data->channels);
- if (NULL == sound_data || player->paused_data->data_size <= 0) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Out of memory OR paused_data is empty");
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = paused_data;
- } else { // NULL != sound_data && NULL != temp && player->paused_data->data_size > 0
- ttsd_data_destroy_sound_data(paused_data);
- }
-
- idx = player->idx;
-
- player->is_paused_data = false;
- player->idx = 0;
-
- if (NULL == sound_data) {
- /* Request unprepare */
- ret = audio_out_unprepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
- }
-
- g_audio_state = AUDIO_STATE_READY;
-
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- return;
- }
- __set_playing_status(true);
-
- SLOG(LOG_INFO, tts_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 { // NO player->is_paused_data
- sound_data = NULL;
- ret = ttsd_data_get_sound_data(player->uid, &sound_data);
- if (0 != ret || NULL == sound_data) {
- /* empty queue */
- SLOG(LOG_ERROR, tts_tag(), "[Player] No sound data. Waiting mode");
-
- /* wait for new audio data come */
- while (1) { // 2nd while(1)
- usleep(10000);
- if (false == __is_player_valid(player)) {
- /* current playing uid is replaced */
- SLOG(LOG_INFO, tts_tag(), "[Player] Finish thread");
- if (AUDIO_STATE_PLAY == g_audio_state) {
- /* release audio & recover session */
- ret = audio_out_unprepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
- }
- g_audio_state = AUDIO_STATE_READY;
- }
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- return;
- } else if (0 < ttsd_data_get_sound_data_size(player->uid)) {
- /* new audio data come */
- SLOG(LOG_INFO, tts_tag(), "[Player] Resume thread");
- break; // exit from 2nd while(1)
- }
-
- /* If engine is not on processing */
- ttsd_synthesis_control_e synth_control = ttsd_get_synth_control();
- if (TTSD_SYNTHESIS_CONTROL_DOING != synth_control) {
- SLOG(LOG_INFO, tts_tag(), "[Server INFO] synth_control(%d)", synth_control);
- if (AUDIO_STATE_PLAY == g_audio_state) {
- /* release audio & recover session */
- ret = audio_out_unprepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
- }
- g_audio_state = AUDIO_STATE_READY;
-
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- }
- }
- } // end of 2nd while(1). waiting for new audio data come
-
- SLOG(LOG_INFO, tts_tag(), "[Player] Finish to wait for new audio data come");
-
- if (AUDIO_STATE_READY == g_audio_state || AUDIO_STATE_WAIT_FOR_PLAYING == g_audio_state) {
- /* set volume policy as 40%, when resume play thread*/
- __set_policy_for_playing();
- }
-
- /* resume play thread */
- player->state = APP_STATE_PLAYING;
- continue;
- } // NULL == sound_data
-
- /* 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 (TTSE_RESULT_EVENT_START == sound_data->event ||
- (TTSE_RESULT_EVENT_FINISH == player->event && TTSE_RESULT_EVENT_FINISH == sound_data->event)) {
- int pid = ttsd_data_get_pid(player->uid);
- if (pid <= 0) {
- SLOG(LOG_WARN, tts_tag(), "[Send WARNIING] Current player is not valid. uid(%u)", player->uid);
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
-
-#ifdef BUF_SAVE_MODE
- __open_buffer_dump_file();
-#endif
-
- __set_playing_status(true);
- if (0 != ttsdc_ipc_send_utt_start_message(pid, player->uid, sound_data->utt_id)) {
- SLOG(LOG_ERROR, tts_tag(), "[Send ERROR] Fail to send Utterance Start Signal : pid(%d), uid(%u), uttid(%d)",
- pid, player->uid, sound_data->utt_id);
- }
- SLOG(LOG_INFO, tts_tag(), "[Player] Start utterance : uid(%u), uttid(%d)", player->uid, sound_data->utt_id);
- } // (TTSE_RESULT_EVENT_START == sound_data->event || (TTSE_RESULT_EVENT_FINISH == player->event && TTSE_RESULT_EVENT_FINISH == sound_data->event))
-
- /* Save last event to check utterance start */
- player->event = sound_data->event;
- idx = 0;
-
- if (NULL == sound_data->data || 0 >= sound_data->data_size) {
- if (TTSE_RESULT_EVENT_FINISH == sound_data->event) {
- SLOG(LOG_DEBUG, tts_tag(), "No sound data");
- /* send utterence finish signal */
- int pid = ttsd_data_get_pid(player->uid);
-
- if (pid <= 0) {
- SLOG(LOG_WARN, tts_tag(), "[Send WARNIING] Current player is not valid. uid(%u)", player->uid);
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
-
- __unset_policy_for_playing();
-
-#ifdef BUF_SAVE_MODE
- __close_buffer_dump_file();
-#endif
-
- __set_playing_status(false);
- if (0 != ttsdc_ipc_send_utt_finish_message(pid, player->uid, sound_data->utt_id)) {
- SLOG(LOG_ERROR, tts_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%u), uttid(%d)",
- pid, player->uid, sound_data->utt_id);
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player] Finish utterance : uid(%u), uttid(%d)", player->uid, sound_data->utt_id);
- }
- } // TTSE_RESULT_EVENT_FINISH == sound_data->event
- SLOG(LOG_INFO, tts_tag(), "[Player] Event(%d) utterance : uid(%u), uttid(%d)", sound_data->event, player->uid, sound_data->utt_id);
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- continue;
- } // (NULL == sound_data->data || 0 >= sound_data->data_size)
- } // NO player->is_paused_data
-
- // If there is any change in audio format, recreate audio handle
- if (g_sampling_rate != sound_data->rate || g_audio_type != sound_data->audio_type) {
- SLOG(LOG_INFO, tts_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(sound_data->audio_type, sound_data->rate)) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create audio out");
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
-
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
-
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Success to destroy and recreate audio out");
- __set_policy_for_playing();
- }
-
- while (APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) {
- if ((unsigned int)idx >= sound_data->data_size)
- break;
-
- if ((unsigned int)idx + SOUND_BUFFER_LENGTH > sound_data->data_size) {
- len = sound_data->data_size - idx;
- } else {
- len = SOUND_BUFFER_LENGTH;
- }
-
- // Check whether set_policy is done or not
- if (false == g_is_set_policy) {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Set policy");
- __set_policy_for_playing();
- }
-
- if (AUDIO_STATE_READY == g_audio_state || AUDIO_STATE_WAIT_FOR_PLAYING == g_audio_state) {
- /* Request prepare */
- ret = audio_out_prepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to prepare audio : %d", ret);
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
-
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Prepare audio");
- g_audio_state = AUDIO_STATE_PLAY;
- } // (AUDIO_STATE_READY == g_audio_state || AUDIO_STATE_WAIT_FOR_PLAYING == g_audio_state)
-
- char* temp_data = sound_data->data;
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Before audio_out_write. data(%p), data[%d](%p), uid(%u), utt_id(%d), len(%d)",
- temp_data, idx, &temp_data[idx], player->uid, sound_data->utt_id, len);
-#ifdef BUF_SAVE_MODE
- __write_buffer_dump_file(&temp_data[idx], len);
-#endif
- ret = audio_out_write(g_audio_h, &temp_data[idx], len);
- if (0 > ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to audio write - %d", ret);
- } else {
- idx += len;
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] After audio_out_write");
- }
-
- if (NULL == g_playing_info && APP_STATE_PAUSED != player->state) {
- SLOG(LOG_ERROR, tts_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, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- }
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
-
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- } // (NULL == g_playing_info && APP_STATE_PAUSED != player->state)
-
- if (APP_STATE_PAUSED == player->state) {
- /* Save data */
- SLOG(LOG_DEBUG, tts_tag(), "[Player] player(%p)", player);
- ttsd_data_destroy_sound_data(player->paused_data);
- player->paused_data = sound_data;
-
- player->is_paused_data = true;
- player->idx = idx;
-
- g_audio_state = AUDIO_STATE_READY;
-
- SLOG(LOG_INFO, tts_tag(), "[Player] Stop player thread by pause");
-
- /* Request prepare */
- ret = audio_out_unprepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
- }
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- return;
- } // (APP_STATE_PAUSED == player->state)
- } // while (APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state)
-
- if (NULL == g_playing_info && APP_STATE_READY == player->state) {
- /* player_stop */
- g_audio_state = AUDIO_STATE_READY;
- SLOG(LOG_DEBUG, tts_tag(), "[Player] Stop player thread");
-
- /* Request prepare */
- ret = audio_out_unprepare(g_audio_h);
- if (AUDIO_IO_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
- }
-
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- } // (NULL == g_playing_info && APP_STATE_READY == player->state)
-
- if ((APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) &&
- (TTSE_RESULT_EVENT_FINISH == sound_data->event)) {
- /* send utterence finish signal */
- int pid = ttsd_data_get_pid(player->uid);
-
- if (pid <= 0) {
- SLOG(LOG_WARN, tts_tag(), "[Send WARNIING] Current player is not valid. uid(%u)", player->uid);
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
-
-#ifdef BUF_SAVE_MODE
- __close_buffer_dump_file();
-#endif
- __set_playing_status(false);
- if (0 != ttsdc_ipc_send_utt_finish_message(pid, player->uid, sound_data->utt_id)) {
- SLOG(LOG_ERROR, tts_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%u), uttid(%d)",
- pid, player->uid, sound_data->utt_id);
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
-
- SLOG(LOG_INFO, tts_tag(), "[Player] Finish utterance : uid(%u), uttid(%d)", player->uid, sound_data->utt_id);
- } // ((APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) && (TTSE_RESULT_EVENT_FINISH == sound_data->event))
-
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
-
- if (NULL == g_playing_info) {
- SLOG(LOG_ERROR, tts_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, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
- }
- /* unset volume policy, volume will be 100% */
- __unset_policy_for_playing();
- ttsd_data_destroy_sound_data(sound_data);
- sound_data = NULL;
- return;
- }
- } // end of 1st while(1)
-}
-
-static void __play_thread(void *data, Ecore_Thread *thread)
-{
- SLOG(LOG_INFO, tts_tag(), "[Player] play thread is on");
-
- while (g_player_init) {
- SLOG(LOG_INFO, tts_tag(), "[Player] Wait play request...");
- pthread_cond_wait(&g_play_thread_cond, &g_play_thread_mutex);
- if (false == g_player_init) {
- SLOG(LOG_INFO, tts_tag(), "[Player] Player is released");
- pthread_mutex_unlock(&g_play_thread_mutex);
- break;
- }
-
- __play_thread_old(data, thread);
- pthread_mutex_unlock(&g_play_thread_mutex);
- pthread_mutex_lock(&g_player_control_mutex);
- g_playing_info = NULL;
- pthread_mutex_unlock(&g_player_control_mutex);
- }
-}
-
-int __create_ducking_handle(void)
-{
- int ret = -1;
- if (NULL == g_media_stream_ducking) {
- ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_MEDIA, __sound_stream_ducking_state_changed_cb, NULL, &g_media_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret)
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for type media, ret(%d)", ret);
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for media stream is already created");
- }
-
-/* if (NULL == g_system_stream_ducking) {
- ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_SYSTEM, __sound_stream_ducking_state_changed_cb, NULL, &g_system_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret)
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for system type, ret(%d)", ret);
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for system stream is already created");
- }
-*/
- if (NULL == g_notification_stream_ducking) {
- ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_NOTIFICATION, __sound_stream_ducking_state_changed_cb, NULL, &g_notification_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret)
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for notification type, ret(%d)", ret);
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for notification stream is already created");
- }
-
- if (NULL == g_alarm_stream_ducking) {
- ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_ALARM, __sound_stream_ducking_state_changed_cb, NULL, &g_alarm_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret)
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for alarm type, ret(%d)", ret);
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for alarm stream is already created");
- }
-
- return ret;
-}
-
-/*
-* Player Interfaces
-*/
-int ttsd_player_init()
-{
- pthread_mutex_lock(&g_player_control_mutex);
- g_playing_info = NULL;
- g_audio_state = AUDIO_STATE_NONE;
- g_audio_h = NULL;
-
- int ret;
-
- ecore_thread_max_set(1);
-
- int cnt = 0;
- while (1) {
- if (0 == access(FOCUS_SERVER_READY, F_OK)) {
- SLOG(LOG_ERROR, tts_tag(), "[Player SUCCESS] focus server is available");
- break;
- } else {
- if (0 == cnt++ % 10)
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] focus server is not available");
- usleep(50000);
- }
- }
-
- ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOICE_INFORMATION, __player_focus_state_cb, NULL, &g_stream_info_h);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create stream info");
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Create stream info");
- }
-
- ret = __create_ducking_handle();
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create ducking handle, ret(%d)", ret);
- } else {
- SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Create ducking handle");
- }
-
- ecore_thread_max_set(1);
-
- ret = __create_audio_out(TTSE_AUDIO_TYPE_RAW_S16, 16000);
- if (0 != ret) {
- sound_manager_destroy_stream_information(g_stream_info_h);
- g_stream_info_h = NULL;
- pthread_mutex_unlock(&g_player_control_mutex);
-
- return -1;
- }
-
- ecore_thread_run(__play_thread, __end_play_thread, NULL, NULL);
-
- g_player_init = true;
-
- pthread_mutex_unlock(&g_player_control_mutex);
-
- return 0;
-}
-
-static void __destroy_all_ducking_handles()
-{
- SLOG(LOG_INFO, tts_tag(), "[Player] Destroy stream ducking");
- if (__get_duration_from_last_volume_change() <= SND_MGR_DUCKING_DURATION) {
- usleep(500000);
- }
-
- __recover_background_volume();
-
- int ret = -1;
- ret = sound_manager_destroy_stream_ducking(g_media_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
- }
- g_media_stream_ducking = NULL;
-
-/* ret = sound_manager_destroy_stream_ducking(g_system_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
- }
- g_system_stream_ducking = NULL;
-*/
- ret = sound_manager_destroy_stream_ducking(g_notification_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
- }
- g_notification_stream_ducking = NULL;
-
- ret = sound_manager_destroy_stream_ducking(g_alarm_stream_ducking);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
- }
- g_alarm_stream_ducking = NULL;
-}
-
-int ttsd_player_release(void)
-{
-#ifdef BUF_SAVE_MODE
- __close_buffer_dump_file();
-#endif
-
- __set_playing_status(false);
- pthread_mutex_lock(&g_player_control_mutex);
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- pthread_mutex_unlock(&g_player_control_mutex);
- return TTSD_ERROR_OPERATION_FAILED;
- }
-
- int ret;
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] @@@@@");
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Active thread count : %d", ecore_thread_active_get());
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] @@@@@");
-
- /* The thread should be released */
- int thread_count = ecore_thread_active_get();
- int count = 0;
- while (0 < thread_count) {
- usleep(10000);
-
- count++;
- if (20 == count) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING!!] Thread is blocked. Player release continue.");
- break;
- }
-
- thread_count = ecore_thread_active_get();
- }
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Thread is released");
-
- ret = __destroy_audio_out();
- if (0 != ret) {
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- ret = sound_manager_destroy_stream_information(g_stream_info_h);
- if (SOUND_MANAGER_ERROR_NONE != ret) {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy stream info");
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Destroy stream info");
- }
-
- __destroy_all_ducking_handles();
-
- /* clear g_player_list */
- g_playing_info = NULL;
- g_player_init = false;
- pthread_cond_broadcast(&g_play_thread_cond);
-
- g_stream_info_h = NULL;
-
- pthread_mutex_unlock(&g_player_control_mutex);
-
- return 0;
-}
-
-int ttsd_player_create_instance(unsigned int uid)
-{
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- return -1;
- }
-
- /* Check uid is duplicated */
- if (NULL != __player_get_item(uid)) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is already registered", uid);
- return -1;
- }
-
- player_s* new_client = (player_s*)calloc(1, sizeof(player_s));
- if (NULL == new_client) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to allocate memory");
- return TTSE_ERROR_OUT_OF_MEMORY;
- }
-
- new_client->uid = uid;
- new_client->event = TTSE_RESULT_EVENT_FINISH;
- new_client->state = APP_STATE_READY;
- new_client->is_paused_data = false;
- new_client->idx = 0;
- new_client->paused_data = NULL;
-
- SECURE_SLOG(LOG_DEBUG, tts_tag(), "[Player] Create player : uid(%u)", uid);
-
- g_player_list = g_list_append(g_player_list, new_client);
-
- return 0;
-}
-
-int ttsd_player_destroy_instance(unsigned int uid)
-{
- pthread_mutex_lock(&g_player_control_mutex);
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- player_s* current;
- current = __player_get_item(uid);
- if (NULL == current) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- if (NULL != g_playing_info) {
- if (uid == g_playing_info->uid) {
- g_playing_info = NULL;
- }
- }
-
- GList *iter = NULL;
- player_s *data = NULL;
-
- if (0 < g_list_length(g_player_list)) {
- /* Get a first item */
- iter = g_list_first(g_player_list);
-
- while (NULL != iter) {
- /* Get handle data from list */
- data = (player_s*)iter->data;
-
- if (NULL != data) {
- /* compare uid */
- if (uid == data->uid) {
- g_player_list = g_list_remove_link(g_player_list, iter);
- free(data);
- data = NULL;
- g_list_free(iter);
- break;
- }
- }
-
- /* Get next item */
- iter = g_list_next(iter);
- }
- }
- pthread_mutex_unlock(&g_player_control_mutex);
-
- SLOG(LOG_DEBUG, tts_tag(), "[PLAYER Success] Destroy instance");
-
- return 0;
-}
-
-int ttsd_player_play(unsigned int uid)
-{
- pthread_mutex_lock(&g_player_control_mutex);
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- if (NULL != g_playing_info) {
- if (uid == g_playing_info->uid) {
- SLOG(LOG_DEBUG, tts_tag(), "[Player] uid(%u) has already played", g_playing_info->uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- return 0;
- } else {
- SLOG(LOG_WARN, tts_tag(), "[Player WARNING] stop old player (%u)", g_playing_info->uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- ttsd_player_stop(g_playing_info->uid);
- pthread_mutex_lock(&g_player_control_mutex);
- }
- }
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player] start play : uid(%u)", uid);
-
- /* Check uid */
- player_s* current;
- current = __player_get_item(uid);
- if (NULL == current) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- current->state = APP_STATE_PLAYING;
- g_playing_info = current;
-
- SLOG(LOG_INFO, tts_tag(), "[Player] Run thread");
- pthread_cond_broadcast(&g_play_thread_cond);
-
- pthread_mutex_unlock(&g_player_control_mutex);
- return 0;
-}
-
-int ttsd_player_stop(unsigned int uid)
-{
- pthread_mutex_lock(&g_player_control_mutex);
-
- /* check whether uid is current playing or not */
- if (NULL != g_playing_info) {
- if (uid == g_playing_info->uid) {
- /* release current playing info */
- g_playing_info = NULL;
- }
- } else {
- SLOG(LOG_DEBUG, tts_tag(), "[Player] No current playing");
- }
-
- if (NULL == g_playing_info) {
- pthread_mutex_lock(&g_play_thread_mutex);
- SLOG(LOG_ERROR, tts_tag(), "[Player] Active thread count : %d", ecore_thread_active_get());
- pthread_mutex_unlock(&g_play_thread_mutex);
- }
-
-#ifdef BUF_SAVE_MODE
- __close_buffer_dump_file();
-#endif
-
- __set_playing_status(false);
- int ret = ttsd_player_clear(uid);
- if (0 != ret) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to stop player, ret(%d)", ret);
- pthread_mutex_unlock(&g_player_control_mutex);
- return ret;
- }
-
- SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Stop player : uid(%u)", uid);
-
- pthread_mutex_unlock(&g_player_control_mutex);
- return 0;
-}
-
-int ttsd_player_clear(unsigned int uid)
-{
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- return -1;
- }
-
- /* Check uid */
- player_s* current;
- current = __player_get_item(uid);
- if (NULL == current) {
- SECURE_SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
- return -1;
- }
-
- if (true == current->is_paused_data) {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Clear paused data");
- ttsd_data_destroy_sound_data(current->paused_data);
- current->paused_data = NULL;
- }
-
- current->event = TTSE_RESULT_EVENT_FINISH;
- current->state = APP_STATE_READY;
- current->is_paused_data = false;
- current->idx = 0;
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Clear player : uid(%u)", uid);
-
- return 0;
-}
-
-int ttsd_player_pause(unsigned int uid)
-{
- pthread_mutex_lock(&g_player_control_mutex);
- SLOG(LOG_DEBUG, tts_tag(), "[Player] pause player : uid(%u)", uid);
-
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- /* Check uid */
- player_s* current;
- current = __player_get_item(uid);
- if (NULL == current) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] ttsd_player_pause() : uid(%u) is not valid", uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- /* check whether uid is current playing or not */
- if (NULL != g_playing_info) {
- if (uid == g_playing_info->uid) {
- /* release current playing info */
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] release current playing info (%u)", uid);
- g_playing_info = NULL;
- } else {
- /* error case */
- }
- }
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] current player (%p), g_playing_info(%p)", current, g_playing_info);
-
- current->state = APP_STATE_PAUSED;
-
- if (NULL == g_playing_info) {
- pthread_mutex_lock(&g_play_thread_mutex);
- SLOG(LOG_ERROR, tts_tag(), "[Player] Active thread count : %d", ecore_thread_active_get());
- pthread_mutex_unlock(&g_play_thread_mutex);
- }
-
-#ifdef BUF_SAVE_MODE
- __close_buffer_dump_file();
-#endif
-
- __set_playing_status(false);
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Pause player : uid(%u)", uid);
-
- pthread_mutex_unlock(&g_player_control_mutex);
- return 0;
-}
-
-int ttsd_player_resume(unsigned int uid)
-{
- pthread_mutex_lock(&g_player_control_mutex);
- SLOG(LOG_DEBUG, tts_tag(), "[Player] Resume player : uid(%u)", uid);
-
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- /* Check id */
- player_s* current;
- current = __player_get_item(uid);
- if (NULL == current) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- /* check current player */
- if (NULL != g_playing_info)
- g_playing_info = NULL;
-
- current->state = APP_STATE_PLAYING;
- g_playing_info = current;
-
- SLOG(LOG_INFO, tts_tag(), "[Player] Resume to run thread");
- pthread_cond_broadcast(&g_play_thread_cond);
-
- pthread_mutex_unlock(&g_player_control_mutex);
- return 0;
-}
-
-int ttsd_player_all_stop()
-{
- pthread_mutex_lock(&g_player_control_mutex);
- if (false == g_player_init) {
- SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
- pthread_mutex_unlock(&g_player_control_mutex);
- return -1;
- }
-
- g_playing_info = NULL;
-
- GList *iter = NULL;
- player_s *data = NULL;
-
- if (0 < g_list_length(g_player_list)) {
- /* Get a first item */
- iter = g_list_first(g_player_list);
-
- while (NULL != iter) {
- /* Get handle data from list */
- data = (player_s*)iter->data;
-
- app_tts_state_e state;
- if (0 > ttsd_data_get_client_state(data->uid, &state)) {
- SLOG(LOG_ERROR, tts_tag(), "[player ERROR] uid(%u) is not valid", data->uid);
- pthread_mutex_unlock(&g_player_control_mutex);
- ttsd_player_destroy_instance(data->uid);
- pthread_mutex_lock(&g_player_control_mutex);
- iter = g_list_next(iter);
- continue;
- }
-
- if (APP_STATE_PLAYING == state || APP_STATE_PAUSED == state) {
- data->event = TTSE_RESULT_EVENT_FINISH;
- data->state = APP_STATE_READY;
-
- if (true == data->is_paused_data) {
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] Clear paused data");
- ttsd_data_destroy_sound_data(data->paused_data);
- data->paused_data = NULL;
- }
-
- data->is_paused_data = false;
- data->idx = 0;
- }
-
- /* Get next item */
- iter = g_list_next(iter);
- }
- }
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] player all stop!!");
-
- pthread_mutex_unlock(&g_player_control_mutex);
- return 0;
-}
-
-int ttsd_player_get_background_volume_ratio(double* ratio)
-{
- if (NULL == ratio)
- return -1;
- else
- *ratio = g_bg_volume_ratio;
-
- return TTSD_ERROR_NONE;
-}
-
-static Eina_Bool __modify_background_volume_async(void* data)
-{
- __recover_background_volume();
- __change_background_volume(0);
- SLOG(LOG_INFO, tts_tag(), "[BG] Modify background volume with delay");
-
- g_modify_background_volume = NULL;
- return EINA_FALSE;
-}
-
-static void __modify_background_volume(void* data)
-{
- if (NULL != g_delayed_unset_policy_timer) {
- SLOG(LOG_INFO, tts_tag(), "[BG] Background volume is going to recover soon. Skip modification");
- return;
- }
-
- if (NULL != g_modify_background_volume) {
- int result = (intptr_t)ecore_timer_del(g_modify_background_volume);
- g_modify_background_volume = NULL;
- SLOG(LOG_ERROR, tts_tag(), "[BG] Remove modify background volume timer (%d)", result);
- }
-
- long long int diff = __get_duration_from_last_volume_change();
- if (diff > SND_MGR_DUCKING_DURATION) {
- __recover_background_volume();
- __change_background_volume(0);
- SLOG(LOG_INFO, tts_tag(), "[BG] Direct modify background volume");
- } else {
- double delay = (double)(SND_MGR_DUCKING_DURATION - diff) / 1000.0;
- g_modify_background_volume = ecore_timer_add(delay, __modify_background_volume_async, (void*)CHECK_TIMER_DELETE);
- SLOG(LOG_INFO, tts_tag(), "[BG] Delay modifying background volume (%p), delay(%f)", g_modify_background_volume, delay);
- }
-}
-
-int ttsd_player_set_background_volume_ratio(double ratio)
-{
- SLOG(LOG_INFO, tts_tag(), "[Player DEBUG] ttsd_player_set_background_volume_ratio : %lf", ratio);
-
- double prev_ratio = g_bg_volume_ratio;
- g_bg_volume_ratio = ratio;
-
- SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Check whether sound is ducked and Change volume. as-is(%lf), to-be(%lf)", prev_ratio, g_bg_volume_ratio);
- if (prev_ratio == g_bg_volume_ratio) {
- return TTSD_ERROR_NONE;
- }
-
- if (g_is_set_policy) {
- SLOG(LOG_INFO, tts_tag(), "[BG] Direct modify background volume");
- ecore_main_loop_thread_safe_call_async(__modify_background_volume, NULL);
- }
-
- return TTSD_ERROR_NONE;
-}
-
-int ttsd_player_wait_to_play(unsigned int uid)
-{
- SLOG(LOG_INFO, tts_tag(), "[Player INFO] wait to play (%u)", uid);
-
- g_audio_state = AUDIO_STATE_WAIT_FOR_PLAYING;
-
- return TTSD_ERROR_NONE;
-}
--- /dev/null
+/*
+* Copyright (c) 2011-2016 Samsung Electronics Co., Ltd All Rights Reserved
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <audio_io.h>
+#include <Ecore.h>
+#include <sound_manager.h>
+#include <sound_manager_internal.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "ttsd_main.h"
+#include "ttsd_player.h"
+#include "ttsd_data.h"
+#include "ttsd_dbus.h"
+#include "ttsd_ipc.h"
+
+#include "tts_internal.h"
+#include "ttsd_server.h"
+
+/*
+* Internal data structure
+*/
+
+typedef enum {
+ AUDIO_STATE_NONE = 0,
+ AUDIO_STATE_READY,
+ AUDIO_STATE_WAIT_FOR_PLAYING,
+ AUDIO_STATE_PLAY
+} audio_state_e;
+
+typedef struct {
+ unsigned int uid; /** client id */
+ app_tts_state_e state; /** client state */
+
+ /* Current utterance information */
+ ttse_result_event_e event; /** event of last utterance */
+
+ bool is_paused_data;
+ int idx;
+ sound_data_s* paused_data;
+} player_s;
+
+#define SOUND_BUFFER_LENGTH 2048
+#define FOCUS_SERVER_READY "/tmp/.sound_server_ready"
+
+static const intptr_t CHECK_TIMER_DELETE = 1;
+static const int EXTRA_INFO_LENGTH = 20;
+
+/* Sound buf save for test */
+/*
+#define BUF_SAVE_MODE
+*/
+
+#ifdef BUF_SAVE_MODE
+static char g_temp_file_name[128] = {'\0',};
+static FILE* g_pFile;
+static int g_count = 0;
+static pthread_mutex_t g_buf_save_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+/** player init info */
+static bool g_player_init = false;
+
+/** Client list */
+static GList *g_player_list;
+
+/** current player information */
+static player_s* g_playing_info;
+
+/* player state */
+static audio_state_e g_audio_state;
+
+static ttse_audio_type_e g_audio_type;
+
+static int g_sampling_rate;
+
+static audio_out_h g_audio_h;
+
+static sound_stream_info_h g_stream_info_h;
+
+static sound_stream_ducking_h g_media_stream_ducking;
+//static sound_stream_ducking_h g_system_stream_ducking;
+static sound_stream_ducking_h g_notification_stream_ducking;
+static sound_stream_ducking_h g_alarm_stream_ducking;
+
+static bool g_is_set_policy;
+
+// static bool ducking_flag;
+
+/* CAUTION!
+If you change this constant value. Please check the function '__set_timer_for_delay_recover()'.
+If you choose too big value, it may cause integer overflow issue.
+*/
+#define SND_MGR_DUCKING_DURATION 500
+
+static struct timespec g_policy_set_time;
+static Ecore_Timer* g_delayed_unset_policy_timer = NULL;
+static Ecore_Timer* g_modify_background_volume = NULL;
+
+static double g_bg_volume_ratio;
+
+static pthread_mutex_t g_play_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t g_player_control_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_cond_t g_play_thread_cond = PTHREAD_COND_INITIALIZER;
+/*
+* Internal Interfaces
+*/
+static void __set_playing_status(bool is_playing)
+{
+ int ret = vconf_set_bool(TTS_PLAYING_STATUS_KEY, is_playing ? 1 : 0);
+ SLOG(LOG_INFO, tts_tag(), "[Player] Set playing status (%s). ret(%d)", is_playing ? "True" : "False", ret);
+}
+
+#ifdef BUF_SAVE_MODE
+static void __open_buffer_dump_file()
+{
+ pthread_mutex_lock(&g_buf_save_mutex);
+ if (g_pFile) {
+ SLOG(LOG_ERROR, tts_tag(), "[Buffer Dump] File is already opened(%s)", g_temp_file_name);
+ pthread_mutex_unlock(&g_buf_save_mutex);
+ return;
+ }
+
+ g_count++;
+ while (1) {
+ snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/tts_temp_%d_%d", getpid(), g_count);
+ int ret = access(g_temp_file_name, 0);
+
+ if (0 == ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Recorder ERROR] File is already exist");
+ if (0 == remove(g_temp_file_name)) {
+ SLOG(LOG_DEBUG, tts_tag(), "[Recorder] Remove file");
+ break;
+ } else {
+ g_count++;
+ }
+ } else {
+ break;
+ }
+ }
+
+ SECURE_SLOG(LOG_DEBUG, tts_tag(), "[Recorder] Temp file name=[%s]", g_temp_file_name);
+
+ /* open test file */
+ g_pFile = fopen(g_temp_file_name, "wb+x");
+ if (NULL == g_pFile) {
+ SLOG(LOG_ERROR, tts_tag(), "[Recorder ERROR] File not found!");
+ }
+
+ pthread_mutex_unlock(&g_buf_save_mutex);
+}
+
+static void __close_buffer_dump_file()
+{
+ pthread_mutex_lock(&g_buf_save_mutex);
+
+ if (g_pFile) {
+ fclose(g_pFile);
+ g_pFile = NULL;
+ }
+
+ pthread_mutex_unlock(&g_buf_save_mutex);
+}
+
+static void __write_buffer_dump_file(const void* buffer, size_t length)
+{
+ pthread_mutex_lock(&g_buf_save_mutex);
+
+ if (g_pFile) {
+ size_t ret = fwrite(buffer, 1, length, g_pFile);
+ SLOG(LOG_DEBUG, tts_tag(), "[Buffer Dump] Stored size(%zu / %zu)", ret, length);
+ } else {
+ SLOG(LOG_ERROR, tts_tag(), "[Buffer Dump] File is not opened. Please check the file open");
+ }
+
+ pthread_mutex_unlock(&g_buf_save_mutex);
+}
+#endif
+
+static bool __is_player_valid(player_s* player)
+{
+ if (NULL == player || NULL == g_playing_info) {
+ SLOG(LOG_ERROR, tts_tag(), "[ERROR] player is NULL");
+ return false;
+ }
+
+ if (g_playing_info != player || g_playing_info->uid != player->uid) {
+ SLOG(LOG_ERROR, tts_tag(), "[ERROR] player is not current player");
+ return false;
+ }
+
+ return true;
+}
+
+player_s* __player_get_item(unsigned int uid)
+{
+ GList *iter = NULL;
+ player_s *data = NULL;
+
+ if (0 < g_list_length(g_player_list)) {
+ /* Get a first item */
+ iter = g_list_first(g_player_list);
+
+ while (NULL != iter) {
+ /* Get handle data from list */
+ data = (player_s*)iter->data;
+
+ /* compare uid */
+ if (uid == data->uid)
+ return data;
+
+ /* Get next item */
+ iter = g_list_next(iter);
+ }
+ }
+
+ return NULL;
+}
+
+static bool __is_focus_released_on_playing(sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state)
+{
+ if (NULL == g_playing_info) {
+ SLOG(LOG_INFO, tts_tag(), "[Player] No current player");
+ return false;
+ }
+
+ if (APP_STATE_PLAYING != g_playing_info->state || AUDIO_STATE_NONE == g_audio_state || AUDIO_STATE_READY == g_audio_state) {
+ SLOG(LOG_INFO, tts_tag(), "[Player] Audio is not played");
+ return false;
+ }
+
+ if (SOUND_STREAM_FOCUS_FOR_PLAYBACK != focus_mask || SOUND_STREAM_FOCUS_STATE_RELEASED != focus_state) {
+ SLOG(LOG_INFO, tts_tag(), "[Player] Playback focus is not released");
+ return false;
+ }
+
+ return true;
+}
+
+static void __player_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
+ sound_stream_focus_change_reason_e reason_for_change, int sound_behavior, const char *extra_info, void *user_data)
+{
+ SLOG(LOG_DEBUG, tts_tag(), "@@@ Focus state changed cb");
+ SLOG(LOG_WARN, tts_tag(), "[Player] focus state changed to (%d) with reason(%d) and extra info(%s)", (int)focus_state, (int)reason_for_change, extra_info);
+
+ if (stream_info != g_stream_info_h) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Invalid stream info handle");
+ return;
+ }
+
+ if (false == __is_focus_released_on_playing(focus_mask, focus_state)) {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Playback focus is not released on playing");
+ return;
+ }
+
+ unsigned int uid = g_playing_info->uid;
+ ttsd_mode_e mode = ttsd_data_get_mode(uid);
+
+ switch (mode) {
+ case TTSD_MODE_DEFAULT:
+ {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] Pause current player - mode(%d)", mode);
+ g_audio_state = AUDIO_STATE_READY;
+
+ if (0 != ttsd_player_pause(uid)) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to pause the player");
+ break;
+ }
+
+ ttsd_data_set_client_state(uid, APP_STATE_PAUSED);
+ int pid = ttsd_data_get_pid(uid);
+ if (pid <= 0) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to get pid. uid(%u)", uid);
+ } else {
+ /* send message to client about changing state */
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Player paused. pid(%d), uid(%u)", pid, uid);
+ ttsdc_ipc_send_set_state_message(pid, uid, APP_STATE_PAUSED);
+ }
+ break;
+ }
+
+ case TTSD_MODE_NOTIFICATION:
+ case TTSD_MODE_SCREEN_READER:
+ {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] Stop current player - mode(%d)", mode);
+ g_audio_state = AUDIO_STATE_READY;
+ ttsd_send_all_stop();
+ break;
+ }
+
+ case TTSD_MODE_INTERRUPT:
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] Ignore focus release - mode(%d)", mode);
+ break;
+
+ default:
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Invalid mode - mode(%d)", mode);
+ break;
+ }
+
+ SLOG(LOG_DEBUG, tts_tag(), "@@@");
+
+ return;
+}
+
+void __sound_stream_ducking_state_changed_cb(sound_stream_ducking_h stream_ducking, bool is_ducked, void *user_data)
+{
+ SLOG(LOG_DEBUG, tts_tag(), "@@@ ducking state changed cb");
+ SLOG(LOG_ERROR, tts_tag(), "[Player] ducking_h(%p) is ducked : %d", stream_ducking, is_ducked);
+ // ducking_flag = true;
+ return;
+}
+
+static const char* __get_ducking_stream(sound_stream_type_e stream_type)
+{
+ const char* type = nullptr;
+ if (SOUND_STREAM_TYPE_MEDIA == stream_type)
+ type = "Media stream";
+ else if (SOUND_STREAM_TYPE_SYSTEM == stream_type)
+ type = "System stream";
+ else if (SOUND_STREAM_TYPE_NOTIFICATION == stream_type)
+ type = "Notification stream";
+ else if (SOUND_STREAM_TYPE_ALARM == stream_type)
+ type = "Alarm stream";
+ else
+ type = "Non matched stream";
+
+ return type;
+}
+
+static int __activate_ducking_sound_stream(sound_stream_type_e stream_type, sound_stream_ducking_h stream_ducking_h, unsigned int duration)
+{
+ bool is_ducked = false;
+ int ret = sound_manager_is_ducked(stream_ducking_h, &is_ducked);
+ if (is_ducked) {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] The %s is already ducked", __get_ducking_stream(stream_type));
+ } else {
+ ret = sound_manager_activate_ducking(stream_ducking_h, duration, g_bg_volume_ratio);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to activate ducking for %s", __get_ducking_stream(stream_type));
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Activate ducking for %s", __get_ducking_stream(stream_type));
+ }
+ }
+ return ret;
+}
+
+static void __change_background_volume(unsigned int duration)
+{
+ SLOG(LOG_INFO, tts_tag(), "[BG] Change background volume");
+ SLOG(LOG_INFO, tts_tag(), "[Player] volume ratio(%lf)", g_bg_volume_ratio);
+ if (1.0 > g_bg_volume_ratio) {
+ __activate_ducking_sound_stream(SOUND_STREAM_TYPE_MEDIA, g_media_stream_ducking, duration);
+// __activate_ducking_sound_stream(SOUND_STREAM_TYPE_SYSTEM, g_system_stream_ducking, duration);
+ __activate_ducking_sound_stream(SOUND_STREAM_TYPE_NOTIFICATION, g_notification_stream_ducking, duration);
+ __activate_ducking_sound_stream(SOUND_STREAM_TYPE_ALARM, g_alarm_stream_ducking, duration);
+ }
+}
+
+static void __change_background_volume_async(void* data)
+{
+ __change_background_volume(SND_MGR_DUCKING_DURATION);
+}
+
+static int __deactivate_ducking_sound_stream(sound_stream_type_e stream_type, sound_stream_ducking_h stream_ducking_h)
+{
+ bool is_ducked = false;
+ int ret = sound_manager_is_ducked(stream_ducking_h, &is_ducked);
+ if (!is_ducked) {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] The %s is already recovered from ducking", __get_ducking_stream(stream_type));
+ } else {
+ ret = sound_manager_deactivate_ducking(stream_ducking_h);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to deactivate ducking for %s", __get_ducking_stream(stream_type));
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Deactivate ducking for %s", __get_ducking_stream(stream_type));
+ }
+ }
+ return ret;
+}
+
+static void __recover_background_volume()
+{
+ __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_MEDIA, g_media_stream_ducking);
+// __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_SYSTEM, g_system_stream_ducking);
+ __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_NOTIFICATION, g_notification_stream_ducking);
+ __deactivate_ducking_sound_stream(SOUND_STREAM_TYPE_ALARM, g_alarm_stream_ducking);
+}
+
+static int __create_audio_out(ttse_audio_type_e type, int rate)
+{
+ int ret = -1;
+ audio_sample_type_e sample_type;
+
+ if (TTSE_AUDIO_TYPE_RAW_S16 == type) {
+ sample_type = AUDIO_SAMPLE_TYPE_S16_LE;
+ } else {
+ sample_type = AUDIO_SAMPLE_TYPE_U8;
+ }
+
+ ret = audio_out_create_new(rate, AUDIO_CHANNEL_MONO, sample_type, &g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ g_audio_state = AUDIO_STATE_NONE;
+ g_audio_h = NULL;
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create audio");
+ return -1;
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Create audio");
+ }
+
+ g_audio_type = type;
+ g_sampling_rate = rate;
+
+ g_audio_state = AUDIO_STATE_READY;
+
+ return 0;
+}
+
+static int __destroy_audio_out()
+{
+ if (NULL == g_audio_h) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Current handle is not valid");
+ return -1;
+ }
+
+ int ret = -1;
+ ret = audio_out_destroy(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to destroy audio");
+ return -1;
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Destroy audio");
+ }
+
+ g_audio_type = TTSE_AUDIO_TYPE_RAW_S16;
+ g_sampling_rate = 0;
+
+ g_audio_state = AUDIO_STATE_NONE;
+ g_audio_h = NULL;
+
+ return 0;
+}
+
+static void __end_play_thread(void *data, Ecore_Thread *thread)
+{
+ SLOG(LOG_ERROR, tts_tag(), "@@@ End thread");
+}
+
+static void __del_timer_for_delayed_recover(void* data)
+{
+ if (NULL != g_delayed_unset_policy_timer) {
+ int result = (intptr_t)ecore_timer_del(g_delayed_unset_policy_timer);
+ g_delayed_unset_policy_timer = NULL;
+ SLOG(LOG_ERROR, tts_tag(), "[BG] Remove timer (%d)", result);
+ }
+}
+
+static void __set_policy_for_playing(void)
+{
+ ecore_main_loop_thread_safe_call_async(__del_timer_for_delayed_recover, NULL);
+
+ /* Set stream info */
+ const char* extra_info = NULL;
+ if (TTSD_MODE_INTERRUPT == ttsd_get_mode()) {
+ extra_info = "TTSD_MODE_INTERRUPT";
+ }
+
+ int ret = sound_manager_acquire_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, extra_info);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to acquire focus");
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Success to acquire focus");
+ }
+
+ ret = audio_out_set_sound_stream_info(g_audio_h, g_stream_info_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to set stream info");
+ }
+
+ ecore_main_loop_thread_safe_call_async(__change_background_volume_async, NULL);
+
+ g_is_set_policy = true;
+ SLOG(LOG_ERROR, tts_tag(), "[BG] g_is_set_policy(%d)", g_is_set_policy);
+
+ clock_gettime(CLOCK_MONOTONIC, &g_policy_set_time);
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] set policy for playing");
+
+ return;
+}
+
+static Eina_Bool __delay_recover_background_volume(void* data)
+{
+ __recover_background_volume();
+ SLOG(LOG_INFO, tts_tag(), "[BG] Delayed unset policy success");
+
+ g_delayed_unset_policy_timer = NULL;
+ return EINA_FALSE;
+}
+
+static long long int __get_duration_from_last_volume_change()
+{
+ struct timespec current_time;
+ clock_gettime(CLOCK_MONOTONIC, ¤t_time);
+
+ long long int diff = ((long long int)current_time.tv_sec - (long long int)g_policy_set_time.tv_sec) * 1000
+ + ((long long int)current_time.tv_nsec - (long long int)g_policy_set_time.tv_nsec) / 1000000;
+ SLOG(LOG_INFO, tts_tag(), "[BG] Time Diff(%lld)", diff);
+
+ return diff;
+}
+
+static void __set_timer_for_delay_recover(void* data)
+{
+ if (NULL != g_delayed_unset_policy_timer) {
+ return;
+ }
+
+ long long int diff = __get_duration_from_last_volume_change();
+ if (diff > SND_MGR_DUCKING_DURATION) {
+ SLOG(LOG_INFO, tts_tag(), "[BG] Direct unset policy");
+ __recover_background_volume();
+ } else {
+ double delay = (double)(SND_MGR_DUCKING_DURATION - diff) / 1000.0;
+ g_delayed_unset_policy_timer = ecore_timer_add(delay, __delay_recover_background_volume, (void*)CHECK_TIMER_DELETE);
+ SLOG(LOG_INFO, tts_tag(), "[BG] Delayed unset policy (%p), delay(%f)", g_delayed_unset_policy_timer, delay);
+ }
+}
+
+static void __unset_policy_for_playing()
+{
+ /* Unset stream info */
+ sound_stream_focus_state_e state_for_playing = SOUND_STREAM_FOCUS_STATE_ACQUIRED;
+ int ret = sound_manager_get_focus_state(g_stream_info_h, &state_for_playing, NULL);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to get focus state: %d", ret);
+ }
+
+ if (SOUND_STREAM_FOCUS_STATE_ACQUIRED == state_for_playing) {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] release focus (mode: %d)", ttsd_get_mode());
+ ret = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to release focus: %d", ret);
+ }
+ }
+
+ ecore_main_loop_thread_safe_call_async(__set_timer_for_delay_recover, NULL);
+
+ g_is_set_policy = false;
+ SLOG(LOG_ERROR, tts_tag(), "[BG] g_is_set_policy(%d)", g_is_set_policy);
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] unset policy for playing");
+
+ return;
+}
+
+static bool __does_interrupt_have_focus(sound_stream_focus_change_reason_e reason, int sound_behavior, char *extra_info)
+{
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] current Playback focus: extra_info(%s), reason(%d), sound_behavior(%d)", extra_info, reason, sound_behavior);
+ if (SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION != reason) {
+ return false;
+ }
+
+ if (NULL == extra_info || 0 >= strlen(extra_info) || 0 != strncmp(extra_info, "TTSD_MODE_INTERRUPT", EXTRA_INFO_LENGTH)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ttsd_player_does_interrupt_have_playback_focus()
+{
+ sound_stream_focus_change_reason_e reason;
+ int sound_behavior = 0;
+ char *extra_info = NULL;
+ if (SOUND_MANAGER_ERROR_NONE != sound_manager_get_current_playback_focus(&reason, &sound_behavior, &extra_info)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to get focus information");
+ return false;
+ }
+
+ bool result = __does_interrupt_have_focus(reason, sound_behavior, extra_info);
+ free(extra_info);
+ return result;
+}
+
+static void __play_thread_old(void *data, Ecore_Thread *thread)
+{
+ SLOG(LOG_DEBUG, tts_tag(), "@@@ Start thread");
+
+ if (NULL == g_playing_info) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] No current player");
+ return;
+ }
+
+ player_s* player = g_playing_info;
+ sound_data_s* sound_data = NULL;
+
+ int ret = -1;
+ int len = SOUND_BUFFER_LENGTH;
+ int idx = 0;
+
+ /* set volume policy as 40% */
+ __set_policy_for_playing();
+ while (1) { // 1st while(1)
+ /* check g_playing_info one more time */
+ if (false == __is_player_valid(player)) {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Player is not valid");
+ g_audio_state = AUDIO_STATE_READY;
+ ret = audio_out_unprepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ }
+ __unset_policy_for_playing();
+ return;
+ }
+
+ if (true == player->is_paused_data && NULL != player->paused_data) {
+ /* Resume player */
+ sound_data_s* paused_data = player->paused_data;
+ player->paused_data = NULL;
+
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = ttsd_data_create_sound_data(paused_data->utt_id, paused_data->data, paused_data->data_size,
+ paused_data->event, paused_data->audio_type, paused_data->rate, paused_data->channels);
+ if (NULL == sound_data || player->paused_data->data_size <= 0) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Out of memory OR paused_data is empty");
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = paused_data;
+ } else { // NULL != sound_data && NULL != temp && player->paused_data->data_size > 0
+ ttsd_data_destroy_sound_data(paused_data);
+ }
+
+ idx = player->idx;
+
+ player->is_paused_data = false;
+ player->idx = 0;
+
+ if (NULL == sound_data) {
+ /* Request unprepare */
+ ret = audio_out_unprepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
+ }
+
+ g_audio_state = AUDIO_STATE_READY;
+
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ return;
+ }
+ __set_playing_status(true);
+
+ SLOG(LOG_INFO, tts_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 { // NO player->is_paused_data
+ sound_data = NULL;
+ ret = ttsd_data_get_sound_data(player->uid, &sound_data);
+ if (0 != ret || NULL == sound_data) {
+ /* empty queue */
+ SLOG(LOG_ERROR, tts_tag(), "[Player] No sound data. Waiting mode");
+
+ /* wait for new audio data come */
+ while (1) { // 2nd while(1)
+ usleep(10000);
+ if (false == __is_player_valid(player)) {
+ /* current playing uid is replaced */
+ SLOG(LOG_INFO, tts_tag(), "[Player] Finish thread");
+ if (AUDIO_STATE_PLAY == g_audio_state) {
+ /* release audio & recover session */
+ ret = audio_out_unprepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
+ }
+ g_audio_state = AUDIO_STATE_READY;
+ }
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ return;
+ } else if (0 < ttsd_data_get_sound_data_size(player->uid)) {
+ /* new audio data come */
+ SLOG(LOG_INFO, tts_tag(), "[Player] Resume thread");
+ break; // exit from 2nd while(1)
+ }
+
+ /* If engine is not on processing */
+ ttsd_synthesis_control_e synth_control = ttsd_get_synth_control();
+ if (TTSD_SYNTHESIS_CONTROL_DOING != synth_control) {
+ SLOG(LOG_INFO, tts_tag(), "[Server INFO] synth_control(%d)", synth_control);
+ if (AUDIO_STATE_PLAY == g_audio_state) {
+ /* release audio & recover session */
+ ret = audio_out_unprepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
+ }
+ g_audio_state = AUDIO_STATE_READY;
+
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ }
+ }
+ } // end of 2nd while(1). waiting for new audio data come
+
+ SLOG(LOG_INFO, tts_tag(), "[Player] Finish to wait for new audio data come");
+
+ if (AUDIO_STATE_READY == g_audio_state || AUDIO_STATE_WAIT_FOR_PLAYING == g_audio_state) {
+ /* set volume policy as 40%, when resume play thread*/
+ __set_policy_for_playing();
+ }
+
+ /* resume play thread */
+ player->state = APP_STATE_PLAYING;
+ continue;
+ } // NULL == sound_data
+
+ /* 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 (TTSE_RESULT_EVENT_START == sound_data->event ||
+ (TTSE_RESULT_EVENT_FINISH == player->event && TTSE_RESULT_EVENT_FINISH == sound_data->event)) {
+ int pid = ttsd_data_get_pid(player->uid);
+ if (pid <= 0) {
+ SLOG(LOG_WARN, tts_tag(), "[Send WARNIING] Current player is not valid. uid(%u)", player->uid);
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+
+#ifdef BUF_SAVE_MODE
+ __open_buffer_dump_file();
+#endif
+
+ __set_playing_status(true);
+ if (0 != ttsdc_ipc_send_utt_start_message(pid, player->uid, sound_data->utt_id)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Send ERROR] Fail to send Utterance Start Signal : pid(%d), uid(%u), uttid(%d)",
+ pid, player->uid, sound_data->utt_id);
+ }
+ SLOG(LOG_INFO, tts_tag(), "[Player] Start utterance : uid(%u), uttid(%d)", player->uid, sound_data->utt_id);
+ } // (TTSE_RESULT_EVENT_START == sound_data->event || (TTSE_RESULT_EVENT_FINISH == player->event && TTSE_RESULT_EVENT_FINISH == sound_data->event))
+
+ /* Save last event to check utterance start */
+ player->event = sound_data->event;
+ idx = 0;
+
+ if (NULL == sound_data->data || 0 >= sound_data->data_size) {
+ if (TTSE_RESULT_EVENT_FINISH == sound_data->event) {
+ SLOG(LOG_DEBUG, tts_tag(), "No sound data");
+ /* send utterence finish signal */
+ int pid = ttsd_data_get_pid(player->uid);
+
+ if (pid <= 0) {
+ SLOG(LOG_WARN, tts_tag(), "[Send WARNIING] Current player is not valid. uid(%u)", player->uid);
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+
+ __unset_policy_for_playing();
+
+#ifdef BUF_SAVE_MODE
+ __close_buffer_dump_file();
+#endif
+
+ __set_playing_status(false);
+ if (0 != ttsdc_ipc_send_utt_finish_message(pid, player->uid, sound_data->utt_id)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%u), uttid(%d)",
+ pid, player->uid, sound_data->utt_id);
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player] Finish utterance : uid(%u), uttid(%d)", player->uid, sound_data->utt_id);
+ }
+ } // TTSE_RESULT_EVENT_FINISH == sound_data->event
+ SLOG(LOG_INFO, tts_tag(), "[Player] Event(%d) utterance : uid(%u), uttid(%d)", sound_data->event, player->uid, sound_data->utt_id);
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ continue;
+ } // (NULL == sound_data->data || 0 >= sound_data->data_size)
+ } // NO player->is_paused_data
+
+ // If there is any change in audio format, recreate audio handle
+ if (g_sampling_rate != sound_data->rate || g_audio_type != sound_data->audio_type) {
+ SLOG(LOG_INFO, tts_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(sound_data->audio_type, sound_data->rate)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create audio out");
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Success to destroy and recreate audio out");
+ __set_policy_for_playing();
+ }
+
+ while (APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) {
+ if ((unsigned int)idx >= sound_data->data_size)
+ break;
+
+ if ((unsigned int)idx + SOUND_BUFFER_LENGTH > sound_data->data_size) {
+ len = sound_data->data_size - idx;
+ } else {
+ len = SOUND_BUFFER_LENGTH;
+ }
+
+ // Check whether set_policy is done or not
+ if (false == g_is_set_policy) {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Set policy");
+ __set_policy_for_playing();
+ }
+
+ if (AUDIO_STATE_READY == g_audio_state || AUDIO_STATE_WAIT_FOR_PLAYING == g_audio_state) {
+ /* Request prepare */
+ ret = audio_out_prepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to prepare audio : %d", ret);
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Prepare audio");
+ g_audio_state = AUDIO_STATE_PLAY;
+ } // (AUDIO_STATE_READY == g_audio_state || AUDIO_STATE_WAIT_FOR_PLAYING == g_audio_state)
+
+ char* temp_data = sound_data->data;
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Before audio_out_write. data(%p), data[%d](%p), uid(%u), utt_id(%d), len(%d)",
+ temp_data, idx, &temp_data[idx], player->uid, sound_data->utt_id, len);
+#ifdef BUF_SAVE_MODE
+ __write_buffer_dump_file(&temp_data[idx], len);
+#endif
+ ret = audio_out_write(g_audio_h, &temp_data[idx], len);
+ if (0 > ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to audio write - %d", ret);
+ } else {
+ idx += len;
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] After audio_out_write");
+ }
+
+ if (NULL == g_playing_info && APP_STATE_PAUSED != player->state) {
+ SLOG(LOG_ERROR, tts_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, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ }
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ } // (NULL == g_playing_info && APP_STATE_PAUSED != player->state)
+
+ if (APP_STATE_PAUSED == player->state) {
+ /* Save data */
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] player(%p)", player);
+ ttsd_data_destroy_sound_data(player->paused_data);
+ player->paused_data = sound_data;
+
+ player->is_paused_data = true;
+ player->idx = idx;
+
+ g_audio_state = AUDIO_STATE_READY;
+
+ SLOG(LOG_INFO, tts_tag(), "[Player] Stop player thread by pause");
+
+ /* Request prepare */
+ ret = audio_out_unprepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
+ }
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ return;
+ } // (APP_STATE_PAUSED == player->state)
+ } // while (APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state)
+
+ if (NULL == g_playing_info && APP_STATE_READY == player->state) {
+ /* player_stop */
+ g_audio_state = AUDIO_STATE_READY;
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] Stop player thread");
+
+ /* Request prepare */
+ ret = audio_out_unprepare(g_audio_h);
+ if (AUDIO_IO_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Unprepare audio");
+ }
+
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ } // (NULL == g_playing_info && APP_STATE_READY == player->state)
+
+ if ((APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) &&
+ (TTSE_RESULT_EVENT_FINISH == sound_data->event)) {
+ /* send utterence finish signal */
+ int pid = ttsd_data_get_pid(player->uid);
+
+ if (pid <= 0) {
+ SLOG(LOG_WARN, tts_tag(), "[Send WARNIING] Current player is not valid. uid(%u)", player->uid);
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+
+#ifdef BUF_SAVE_MODE
+ __close_buffer_dump_file();
+#endif
+ __set_playing_status(false);
+ if (0 != ttsdc_ipc_send_utt_finish_message(pid, player->uid, sound_data->utt_id)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%u), uttid(%d)",
+ pid, player->uid, sound_data->utt_id);
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+
+ SLOG(LOG_INFO, tts_tag(), "[Player] Finish utterance : uid(%u), uttid(%d)", player->uid, sound_data->utt_id);
+ } // ((APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) && (TTSE_RESULT_EVENT_FINISH == sound_data->event))
+
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+
+ if (NULL == g_playing_info) {
+ SLOG(LOG_ERROR, tts_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, tts_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
+ }
+ /* unset volume policy, volume will be 100% */
+ __unset_policy_for_playing();
+ ttsd_data_destroy_sound_data(sound_data);
+ sound_data = NULL;
+ return;
+ }
+ } // end of 1st while(1)
+}
+
+static void __play_thread(void *data, Ecore_Thread *thread)
+{
+ SLOG(LOG_INFO, tts_tag(), "[Player] play thread is on");
+
+ while (g_player_init) {
+ SLOG(LOG_INFO, tts_tag(), "[Player] Wait play request...");
+ pthread_cond_wait(&g_play_thread_cond, &g_play_thread_mutex);
+ if (false == g_player_init) {
+ SLOG(LOG_INFO, tts_tag(), "[Player] Player is released");
+ pthread_mutex_unlock(&g_play_thread_mutex);
+ break;
+ }
+
+ __play_thread_old(data, thread);
+ pthread_mutex_unlock(&g_play_thread_mutex);
+ pthread_mutex_lock(&g_player_control_mutex);
+ g_playing_info = NULL;
+ pthread_mutex_unlock(&g_player_control_mutex);
+ }
+}
+
+int __create_ducking_handle(void)
+{
+ int ret = -1;
+ if (NULL == g_media_stream_ducking) {
+ ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_MEDIA, __sound_stream_ducking_state_changed_cb, NULL, &g_media_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret)
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for type media, ret(%d)", ret);
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for media stream is already created");
+ }
+
+/* if (NULL == g_system_stream_ducking) {
+ ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_SYSTEM, __sound_stream_ducking_state_changed_cb, NULL, &g_system_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret)
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for system type, ret(%d)", ret);
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for system stream is already created");
+ }
+*/
+ if (NULL == g_notification_stream_ducking) {
+ ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_NOTIFICATION, __sound_stream_ducking_state_changed_cb, NULL, &g_notification_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret)
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for notification type, ret(%d)", ret);
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for notification stream is already created");
+ }
+
+ if (NULL == g_alarm_stream_ducking) {
+ ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_ALARM, __sound_stream_ducking_state_changed_cb, NULL, &g_alarm_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret)
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create stream ducking for alarm type, ret(%d)", ret);
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Ducking handle for alarm stream is already created");
+ }
+
+ return ret;
+}
+
+/*
+* Player Interfaces
+*/
+int ttsd_player_init()
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+ g_playing_info = NULL;
+ g_audio_state = AUDIO_STATE_NONE;
+ g_audio_h = NULL;
+
+ int ret;
+
+ ecore_thread_max_set(1);
+
+ int cnt = 0;
+ while (1) {
+ if (0 == access(FOCUS_SERVER_READY, F_OK)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player SUCCESS] focus server is available");
+ break;
+ } else {
+ if (0 == cnt++ % 10)
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] focus server is not available");
+ usleep(50000);
+ }
+ }
+
+ ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOICE_INFORMATION, __player_focus_state_cb, NULL, &g_stream_info_h);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create stream info");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Create stream info");
+ }
+
+ ret = __create_ducking_handle();
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to create ducking handle, ret(%d)", ret);
+ } else {
+ SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Create ducking handle");
+ }
+
+ ecore_thread_max_set(1);
+
+ ret = __create_audio_out(TTSE_AUDIO_TYPE_RAW_S16, 16000);
+ if (0 != ret) {
+ sound_manager_destroy_stream_information(g_stream_info_h);
+ g_stream_info_h = NULL;
+ pthread_mutex_unlock(&g_player_control_mutex);
+
+ return -1;
+ }
+
+ ecore_thread_run(__play_thread, __end_play_thread, NULL, NULL);
+
+ g_player_init = true;
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+
+ return 0;
+}
+
+static void __destroy_all_ducking_handles()
+{
+ SLOG(LOG_INFO, tts_tag(), "[Player] Destroy stream ducking");
+ if (__get_duration_from_last_volume_change() <= SND_MGR_DUCKING_DURATION) {
+ usleep(500000);
+ }
+
+ __recover_background_volume();
+
+ int ret = -1;
+ ret = sound_manager_destroy_stream_ducking(g_media_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
+ }
+ g_media_stream_ducking = NULL;
+
+/* ret = sound_manager_destroy_stream_ducking(g_system_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
+ }
+ g_system_stream_ducking = NULL;
+*/
+ ret = sound_manager_destroy_stream_ducking(g_notification_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
+ }
+ g_notification_stream_ducking = NULL;
+
+ ret = sound_manager_destroy_stream_ducking(g_alarm_stream_ducking);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy ducking handle, ret(%d)", ret);
+ }
+ g_alarm_stream_ducking = NULL;
+}
+
+int ttsd_player_release(void)
+{
+#ifdef BUF_SAVE_MODE
+ __close_buffer_dump_file();
+#endif
+
+ __set_playing_status(false);
+ pthread_mutex_lock(&g_player_control_mutex);
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return TTSD_ERROR_OPERATION_FAILED;
+ }
+
+ int ret;
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] @@@@@");
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Active thread count : %d", ecore_thread_active_get());
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] @@@@@");
+
+ /* The thread should be released */
+ int thread_count = ecore_thread_active_get();
+ int count = 0;
+ while (0 < thread_count) {
+ usleep(10000);
+
+ count++;
+ if (20 == count) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING!!] Thread is blocked. Player release continue.");
+ break;
+ }
+
+ thread_count = ecore_thread_active_get();
+ }
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Thread is released");
+
+ ret = __destroy_audio_out();
+ if (0 != ret) {
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ ret = sound_manager_destroy_stream_information(g_stream_info_h);
+ if (SOUND_MANAGER_ERROR_NONE != ret) {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to destroy stream info");
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Destroy stream info");
+ }
+
+ __destroy_all_ducking_handles();
+
+ /* clear g_player_list */
+ g_playing_info = NULL;
+ g_player_init = false;
+ pthread_cond_broadcast(&g_play_thread_cond);
+
+ g_stream_info_h = NULL;
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+
+ return 0;
+}
+
+int ttsd_player_create_instance(unsigned int uid)
+{
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ return -1;
+ }
+
+ /* Check uid is duplicated */
+ if (NULL != __player_get_item(uid)) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is already registered", uid);
+ return -1;
+ }
+
+ player_s* new_client = (player_s*)calloc(1, sizeof(player_s));
+ if (NULL == new_client) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to allocate memory");
+ return TTSE_ERROR_OUT_OF_MEMORY;
+ }
+
+ new_client->uid = uid;
+ new_client->event = TTSE_RESULT_EVENT_FINISH;
+ new_client->state = APP_STATE_READY;
+ new_client->is_paused_data = false;
+ new_client->idx = 0;
+ new_client->paused_data = NULL;
+
+ SECURE_SLOG(LOG_DEBUG, tts_tag(), "[Player] Create player : uid(%u)", uid);
+
+ g_player_list = g_list_append(g_player_list, new_client);
+
+ return 0;
+}
+
+int ttsd_player_destroy_instance(unsigned int uid)
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ player_s* current;
+ current = __player_get_item(uid);
+ if (NULL == current) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ if (NULL != g_playing_info) {
+ if (uid == g_playing_info->uid) {
+ g_playing_info = NULL;
+ }
+ }
+
+ GList *iter = NULL;
+ player_s *data = NULL;
+
+ if (0 < g_list_length(g_player_list)) {
+ /* Get a first item */
+ iter = g_list_first(g_player_list);
+
+ while (NULL != iter) {
+ /* Get handle data from list */
+ data = (player_s*)iter->data;
+
+ if (NULL != data) {
+ /* compare uid */
+ if (uid == data->uid) {
+ g_player_list = g_list_remove_link(g_player_list, iter);
+ free(data);
+ data = NULL;
+ g_list_free(iter);
+ break;
+ }
+ }
+
+ /* Get next item */
+ iter = g_list_next(iter);
+ }
+ }
+ pthread_mutex_unlock(&g_player_control_mutex);
+
+ SLOG(LOG_DEBUG, tts_tag(), "[PLAYER Success] Destroy instance");
+
+ return 0;
+}
+
+int ttsd_player_play(unsigned int uid)
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ if (NULL != g_playing_info) {
+ if (uid == g_playing_info->uid) {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] uid(%u) has already played", g_playing_info->uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return 0;
+ } else {
+ SLOG(LOG_WARN, tts_tag(), "[Player WARNING] stop old player (%u)", g_playing_info->uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ ttsd_player_stop(g_playing_info->uid);
+ pthread_mutex_lock(&g_player_control_mutex);
+ }
+ }
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] start play : uid(%u)", uid);
+
+ /* Check uid */
+ player_s* current;
+ current = __player_get_item(uid);
+ if (NULL == current) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ current->state = APP_STATE_PLAYING;
+ g_playing_info = current;
+
+ SLOG(LOG_INFO, tts_tag(), "[Player] Run thread");
+ pthread_cond_broadcast(&g_play_thread_cond);
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return 0;
+}
+
+int ttsd_player_stop(unsigned int uid)
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+
+ /* check whether uid is current playing or not */
+ if (NULL != g_playing_info) {
+ if (uid == g_playing_info->uid) {
+ /* release current playing info */
+ g_playing_info = NULL;
+ }
+ } else {
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] No current playing");
+ }
+
+ if (NULL == g_playing_info) {
+ pthread_mutex_lock(&g_play_thread_mutex);
+ SLOG(LOG_ERROR, tts_tag(), "[Player] Active thread count : %d", ecore_thread_active_get());
+ pthread_mutex_unlock(&g_play_thread_mutex);
+ }
+
+#ifdef BUF_SAVE_MODE
+ __close_buffer_dump_file();
+#endif
+
+ __set_playing_status(false);
+ int ret = ttsd_player_clear(uid);
+ if (0 != ret) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to stop player, ret(%d)", ret);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return ret;
+ }
+
+ SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Stop player : uid(%u)", uid);
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return 0;
+}
+
+int ttsd_player_clear(unsigned int uid)
+{
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ return -1;
+ }
+
+ /* Check uid */
+ player_s* current;
+ current = __player_get_item(uid);
+ if (NULL == current) {
+ SECURE_SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
+ return -1;
+ }
+
+ if (true == current->is_paused_data) {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Clear paused data");
+ ttsd_data_destroy_sound_data(current->paused_data);
+ current->paused_data = NULL;
+ }
+
+ current->event = TTSE_RESULT_EVENT_FINISH;
+ current->state = APP_STATE_READY;
+ current->is_paused_data = false;
+ current->idx = 0;
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Clear player : uid(%u)", uid);
+
+ return 0;
+}
+
+int ttsd_player_pause(unsigned int uid)
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] pause player : uid(%u)", uid);
+
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ /* Check uid */
+ player_s* current;
+ current = __player_get_item(uid);
+ if (NULL == current) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] ttsd_player_pause() : uid(%u) is not valid", uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ /* check whether uid is current playing or not */
+ if (NULL != g_playing_info) {
+ if (uid == g_playing_info->uid) {
+ /* release current playing info */
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] release current playing info (%u)", uid);
+ g_playing_info = NULL;
+ } else {
+ /* error case */
+ }
+ }
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] current player (%p), g_playing_info(%p)", current, g_playing_info);
+
+ current->state = APP_STATE_PAUSED;
+
+ if (NULL == g_playing_info) {
+ pthread_mutex_lock(&g_play_thread_mutex);
+ SLOG(LOG_ERROR, tts_tag(), "[Player] Active thread count : %d", ecore_thread_active_get());
+ pthread_mutex_unlock(&g_play_thread_mutex);
+ }
+
+#ifdef BUF_SAVE_MODE
+ __close_buffer_dump_file();
+#endif
+
+ __set_playing_status(false);
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Pause player : uid(%u)", uid);
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return 0;
+}
+
+int ttsd_player_resume(unsigned int uid)
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+ SLOG(LOG_DEBUG, tts_tag(), "[Player] Resume player : uid(%u)", uid);
+
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ /* Check id */
+ player_s* current;
+ current = __player_get_item(uid);
+ if (NULL == current) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ /* check current player */
+ if (NULL != g_playing_info)
+ g_playing_info = NULL;
+
+ current->state = APP_STATE_PLAYING;
+ g_playing_info = current;
+
+ SLOG(LOG_INFO, tts_tag(), "[Player] Resume to run thread");
+ pthread_cond_broadcast(&g_play_thread_cond);
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return 0;
+}
+
+int ttsd_player_all_stop()
+{
+ pthread_mutex_lock(&g_player_control_mutex);
+ if (false == g_player_init) {
+ SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return -1;
+ }
+
+ g_playing_info = NULL;
+
+ GList *iter = NULL;
+ player_s *data = NULL;
+
+ if (0 < g_list_length(g_player_list)) {
+ /* Get a first item */
+ iter = g_list_first(g_player_list);
+
+ while (NULL != iter) {
+ /* Get handle data from list */
+ data = (player_s*)iter->data;
+
+ app_tts_state_e state;
+ if (0 > ttsd_data_get_client_state(data->uid, &state)) {
+ SLOG(LOG_ERROR, tts_tag(), "[player ERROR] uid(%u) is not valid", data->uid);
+ pthread_mutex_unlock(&g_player_control_mutex);
+ ttsd_player_destroy_instance(data->uid);
+ pthread_mutex_lock(&g_player_control_mutex);
+ iter = g_list_next(iter);
+ continue;
+ }
+
+ if (APP_STATE_PLAYING == state || APP_STATE_PAUSED == state) {
+ data->event = TTSE_RESULT_EVENT_FINISH;
+ data->state = APP_STATE_READY;
+
+ if (true == data->is_paused_data) {
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] Clear paused data");
+ ttsd_data_destroy_sound_data(data->paused_data);
+ data->paused_data = NULL;
+ }
+
+ data->is_paused_data = false;
+ data->idx = 0;
+ }
+
+ /* Get next item */
+ iter = g_list_next(iter);
+ }
+ }
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] player all stop!!");
+
+ pthread_mutex_unlock(&g_player_control_mutex);
+ return 0;
+}
+
+int ttsd_player_get_background_volume_ratio(double* ratio)
+{
+ if (NULL == ratio)
+ return -1;
+ else
+ *ratio = g_bg_volume_ratio;
+
+ return TTSD_ERROR_NONE;
+}
+
+static Eina_Bool __modify_background_volume_async(void* data)
+{
+ __recover_background_volume();
+ __change_background_volume(0);
+ SLOG(LOG_INFO, tts_tag(), "[BG] Modify background volume with delay");
+
+ g_modify_background_volume = NULL;
+ return EINA_FALSE;
+}
+
+static void __modify_background_volume(void* data)
+{
+ if (NULL != g_delayed_unset_policy_timer) {
+ SLOG(LOG_INFO, tts_tag(), "[BG] Background volume is going to recover soon. Skip modification");
+ return;
+ }
+
+ if (NULL != g_modify_background_volume) {
+ int result = (intptr_t)ecore_timer_del(g_modify_background_volume);
+ g_modify_background_volume = NULL;
+ SLOG(LOG_ERROR, tts_tag(), "[BG] Remove modify background volume timer (%d)", result);
+ }
+
+ long long int diff = __get_duration_from_last_volume_change();
+ if (diff > SND_MGR_DUCKING_DURATION) {
+ __recover_background_volume();
+ __change_background_volume(0);
+ SLOG(LOG_INFO, tts_tag(), "[BG] Direct modify background volume");
+ } else {
+ double delay = (double)(SND_MGR_DUCKING_DURATION - diff) / 1000.0;
+ g_modify_background_volume = ecore_timer_add(delay, __modify_background_volume_async, (void*)CHECK_TIMER_DELETE);
+ SLOG(LOG_INFO, tts_tag(), "[BG] Delay modifying background volume (%p), delay(%f)", g_modify_background_volume, delay);
+ }
+}
+
+int ttsd_player_set_background_volume_ratio(double ratio)
+{
+ SLOG(LOG_INFO, tts_tag(), "[Player DEBUG] ttsd_player_set_background_volume_ratio : %lf", ratio);
+
+ double prev_ratio = g_bg_volume_ratio;
+ g_bg_volume_ratio = ratio;
+
+ SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Check whether sound is ducked and Change volume. as-is(%lf), to-be(%lf)", prev_ratio, g_bg_volume_ratio);
+ if (prev_ratio == g_bg_volume_ratio) {
+ return TTSD_ERROR_NONE;
+ }
+
+ if (g_is_set_policy) {
+ SLOG(LOG_INFO, tts_tag(), "[BG] Direct modify background volume");
+ ecore_main_loop_thread_safe_call_async(__modify_background_volume, NULL);
+ }
+
+ return TTSD_ERROR_NONE;
+}
+
+int ttsd_player_wait_to_play(unsigned int uid)
+{
+ SLOG(LOG_INFO, tts_tag(), "[Player INFO] wait to play (%u)", uid);
+
+ g_audio_state = AUDIO_STATE_WAIT_FOR_PLAYING;
+
+ return TTSD_ERROR_NONE;
+}