From c370c07420eccd878f9ea17b3f59e5fe952a696d Mon Sep 17 00:00:00 2001 From: "sooyeon.kim" Date: Fri, 10 Nov 2017 16:09:31 +0900 Subject: [PATCH] Add a new TTS Interrupt mode Change-Id: I1158619f6c2bc9079bb41c6446795604731aead1 Signed-off-by: sooyeon.kim (cherry picked from commit 569aed93a951bb85436090e31e60ec2de42dc8bd) --- CMakeLists.txt | 1 + client/tts.c | 3 +- client/tts_dbus.c | 12 +- common/tts_defs.h | 22 ++-- engine-parser/src/tts-engine-parser.c | 8 +- include/tts_internal.h | 5 + org.tizen.voice.ttsinterruptserver.service | 4 + org.tizen.voice.ttsinterruptserver.tv.service | 5 + packaging/tts.spec | 2 + server/ttsd_dbus.c | 15 +++ server/ttsd_main.h | 3 +- server/ttsd_player.c | 163 +++++++++++++++++++++++++- server/ttsd_player.h | 2 + server/ttsd_server.c | 13 ++ server/ttse.c | 4 + tts-server.conf | 12 ++ 16 files changed, 254 insertions(+), 20 deletions(-) create mode 100644 org.tizen.voice.ttsinterruptserver.service create mode 100644 org.tizen.voice.ttsinterruptserver.tv.service diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d8c687..f2c5819 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ INSTALL(FILES ${CMAKE_SOURCE_DIR}/tts-server.conf DESTINATION /etc/dbus-1/system INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.voice.ttsserver.service DESTINATION ${TZ_SYS_RO_SHARE}/dbus-1/services) INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.voice.ttsnotiserver.service DESTINATION ${TZ_SYS_RO_SHARE}/dbus-1/services) INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.voice.ttssrserver.service DESTINATION ${TZ_SYS_RO_SHARE}/dbus-1/services) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.voice.ttsinterruptserver.service DESTINATION ${TZ_SYS_RO_SHARE}/dbus-1/services) ## voice_getengine ## IF("${ARCH}" MATCHES "^arm.*") diff --git a/client/tts.c b/client/tts.c index e6385b4..160b3ab 100644 --- a/client/tts.c +++ b/client/tts.c @@ -27,6 +27,7 @@ #include "tts_dbus.h" #include "tts_main.h" +#include "tts_internal.h" static bool g_screen_reader; @@ -391,7 +392,7 @@ int tts_set_mode(tts_h tts, tts_mode_e mode) return TTS_ERROR_INVALID_STATE; } - if (TTS_MODE_DEFAULT <= mode && mode <= TTS_MODE_SCREEN_READER) { + if (TTS_MODE_DEFAULT <= mode && mode <= TTS_MODE_INTERRUPT) { client->mode = mode; } else { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] mode is not valid : %d", mode); diff --git a/client/tts_dbus.c b/client/tts_dbus.c index e7dc689..f922798 100644 --- a/client/tts_dbus.c +++ b/client/tts_dbus.c @@ -21,7 +21,7 @@ #include "tts_dbus.h" #include "tts_defs.h" #include "tts_main.h" - +#include "tts_internal.h" #define HELLO_WAITING_TIME 500 #define WAITING_TIME 5000 @@ -315,6 +315,12 @@ DBusMessage* __tts_dbus_make_message(int uid, const char* method) TTS_SR_SERVER_SERVICE_OBJECT_PATH, TTS_SR_SERVER_SERVICE_INTERFACE, method); + } else if (TTS_MODE_INTERRUPT == client->mode) { + msg = dbus_message_new_method_call( + TTS_INTERRUPT_SERVER_SERVICE_NAME, + TTS_INTERRUPT_SERVER_SERVICE_OBJECT_PATH, + TTS_INTERRUPT_SERVER_SERVICE_INTERFACE, + method); } else { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Input mode is not available"); return NULL; @@ -430,6 +436,8 @@ int tts_dbus_request_initialize(int uid, bool* credential_needed) snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", TTS_NOTI_SERVER_SERVICE_INTERFACE); } else if (TTS_MODE_SCREEN_READER == client->mode) { snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", TTS_SR_SERVER_SERVICE_INTERFACE); + } else if (TTS_MODE_INTERRUPT == client->mode) { + snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", TTS_INTERRUPT_SERVER_SERVICE_INTERFACE); } dbus_bus_add_match(g_conn_listener, rule_err, &err); dbus_connection_flush(g_conn_listener); @@ -474,6 +482,8 @@ int tts_dbus_request_finalize(int uid) snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", TTS_NOTI_SERVER_SERVICE_INTERFACE); } else if (TTS_MODE_SCREEN_READER == client->mode) { snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", TTS_SR_SERVER_SERVICE_INTERFACE); + } else if (TTS_MODE_INTERRUPT == client->mode) { + snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", TTS_INTERRUPT_SERVER_SERVICE_INTERFACE); } dbus_bus_remove_match(g_conn_listener, rule_err, &err); dbus_connection_flush(g_conn_listener); diff --git a/common/tts_defs.h b/common/tts_defs.h index c0f57fa..8b11f7c 100644 --- a/common/tts_defs.h +++ b/common/tts_defs.h @@ -43,6 +43,10 @@ extern "C" { #define TTS_SR_SERVER_SERVICE_OBJECT_PATH "/org/tizen/voice/ttssrserver" #define TTS_SR_SERVER_SERVICE_INTERFACE "org.tizen.voice.ttssrserver" +#define TTS_INTERRUPT_SERVER_SERVICE_NAME "org.tizen.voice.ttsinterruptserver" +#define TTS_INTERRUPT_SERVER_SERVICE_OBJECT_PATH "/org/tizen/voice/ttsinterruptserver" +#define TTS_INTERRUPT_SERVER_SERVICE_INTERFACE "org.tizen.voice.ttsinterruptserver" + /****************************************************************************************** * Message Definition for APIs *******************************************************************************************/ @@ -75,17 +79,17 @@ extern "C" { * Defines for configuration *******************************************************************************************/ -#define TTS_CONFIG_BASE tzplatform_mkpath(TZ_USER_HOME, "/share/.voice") -#define TTS_CONFIG tzplatform_mkpath(TZ_USER_HOME, "/share/.voice/tts-config.xml") -#define TTS_DEFAULT_CONFIG tzplatform_mkpath(TZ_SYS_RO_SHARE, "/voice/tts/1.0/tts-config.xml") +#define TTS_CONFIG_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice") +#define TTS_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/tts-config.xml") +#define TTS_DEFAULT_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "/voice/tts/1.0/tts-config.xml") -#define TTS_DEFAULT_ENGINE tzplatform_mkpath(TZ_SYS_RO_SHARE, "/voice/tts/1.0/engine") -#define TTS_DEFAULT_ENGINE_INFO tzplatform_mkpath(TZ_SYS_RO_SHARE, "/voice/tts/1.0/engine-info") -#define TTS_DEFAULT_ENGINE_SETTING tzplatform_mkpath(TZ_SYS_RO_SHARE, "/voice/tts/1.0/engine-setting") +#define TTS_DEFAULT_ENGINE tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "/voice/tts/1.0/engine") +#define TTS_DEFAULT_ENGINE_INFO tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "/voice/tts/1.0/engine-info") +#define TTS_DEFAULT_ENGINE_SETTING tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "/voice/tts/1.0/engine-setting") -#define TTS_HOME tzplatform_mkpath(TZ_USER_HOME, "/share/.voice/tts") -#define TTS_DOWNLOAD_BASE tzplatform_mkpath(TZ_USER_HOME, "/share/.voice/tts/1.0") -#define TTS_DOWNLOAD_ENGINE_INFO tzplatform_mkpath(TZ_USER_HOME, "share/.voice/tts/1.0/engine-info") +#define TTS_HOME tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/tts") +#define TTS_DOWNLOAD_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/tts/1.0") +#define TTS_DOWNLOAD_ENGINE_INFO tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice/tts/1.0/engine-info") #define TTS_BASE_LANGUAGE "en_US" diff --git a/engine-parser/src/tts-engine-parser.c b/engine-parser/src/tts-engine-parser.c index 42414fc..802f6e5 100644 --- a/engine-parser/src/tts-engine-parser.c +++ b/engine-parser/src/tts-engine-parser.c @@ -54,10 +54,10 @@ #define TTS_TAG_ENGINE_CREDENTIAL "credential" #define TTS_TAG_ENGINE_TEXT_SIZE "text-size" -#define TTS_CONFIG_BASE tzplatform_mkpath(TZ_USER_HOME, "share/.voice") -#define TTS_HOME tzplatform_mkpath(TZ_USER_HOME, "share/.voice/tts") -#define TTS_ENGINE_BASE tzplatform_mkpath(TZ_USER_HOME, "share/.voice/tts/1.0") -#define TTS_ENGINE_INFO tzplatform_mkpath(TZ_USER_SHARE, ".voice/tts/1.0/engine-info") +#define TTS_CONFIG_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice") +#define TTS_HOME tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice/tts") +#define TTS_ENGINE_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice/tts/1.0") +#define TTS_ENGINE_INFO tzplatform_mkpath(tzplatform_getid("TZ_USER_SHARE"), ".voice/tts/1.0/engine-info") #define TTS_GLOBAL_CONFIG_BASE "/etc/skel/share/.voice" #define TTS_GLOBAL_HOME "/etc/skel/share/.voice/tts" diff --git a/include/tts_internal.h b/include/tts_internal.h index 29ea810..303b6d3 100644 --- a/include/tts_internal.h +++ b/include/tts_internal.h @@ -28,6 +28,11 @@ extern "C" #endif /** + * @brief Definition for TTS interrupt mode + */ +#define TTS_MODE_INTERRUPT 3 + +/** * @brief Sets server tts. * @details Using this API, the application can ask server tts with a credential. * The credential is a key to verify the authorization about using the engine based on server, not embeded engine. diff --git a/org.tizen.voice.ttsinterruptserver.service b/org.tizen.voice.ttsinterruptserver.service new file mode 100644 index 0000000..c79f344 --- /dev/null +++ b/org.tizen.voice.ttsinterruptserver.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.tizen.voice.ttsinterruptserver +Exec=/bin/sh -c "voice_getengine get system db/voice/tts/engine/default | awk '{print$5}' | xargs -t -i launch_app {}-interrupt mode interrupt" +#Exec=/bin/sh -c "launch_app org.tizen.tts-engine-default-noti mode noti" diff --git a/org.tizen.voice.ttsinterruptserver.tv.service b/org.tizen.voice.ttsinterruptserver.tv.service new file mode 100644 index 0000000..f872182 --- /dev/null +++ b/org.tizen.voice.ttsinterruptserver.tv.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.tizen.voice.ttsnotiserver +#Exec=/bin/sh -c "buxton2ctl get user db/voice/tts_engine | awk '{print$5}' | xargs -t -i launch_app {}-noti" +#Exec=/bin/sh -c "launch_app org.tizen.tts-engine-default-noti mode noti" +Exec=/bin/sh -c "launch_app org.tizen.tts-engine-vd-interrupt mode interrupt" diff --git a/packaging/tts.spec b/packaging/tts.spec index c7551ea..7d09832 100644 --- a/packaging/tts.spec +++ b/packaging/tts.spec @@ -89,6 +89,7 @@ rm -rf %{buildroot} mv -f org.tizen.voice.ttsserver.tv.service org.tizen.voice.ttsserver.service mv -f org.tizen.voice.ttsnotiserver.tv.service org.tizen.voice.ttsnotiserver.service mv -f org.tizen.voice.ttssrserver.tv.service org.tizen.voice.ttssrserver.service +mv -f org.tizen.voice.ttsinterruptserver.tv.service org.tizen.voice.ttsinterruptserver.service %endif %make_install @@ -112,6 +113,7 @@ mkdir -p %{TZ_SYS_RO_SHARE}/voice/test %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice.ttsserver.service %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice.ttsnotiserver.service %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice.ttssrserver.service +%{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice.ttsinterruptserver.service #%{TZ_SYS_RO_SHARE}/voice/test/tts-test %{_bindir}/voice_getengine %{TZ_SYS_RO_ETC}/package-manager/parserlib/metadata/libtts-engine-parser.so* diff --git a/server/ttsd_dbus.c b/server/ttsd_dbus.c index c9015eb..9e0c4f1 100644 --- a/server/ttsd_dbus.c +++ b/server/ttsd_dbus.c @@ -391,6 +391,21 @@ int ttsd_dbus_open_connection() snprintf(g_service_name, strlen(TTS_NOTI_SERVER_SERVICE_NAME) + 1, "%s", TTS_NOTI_SERVER_SERVICE_NAME); snprintf(g_service_object, strlen(TTS_NOTI_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", TTS_NOTI_SERVER_SERVICE_OBJECT_PATH); snprintf(g_service_interface, strlen(TTS_NOTI_SERVER_SERVICE_INTERFACE) + 1, "%s", TTS_NOTI_SERVER_SERVICE_INTERFACE); + } else if (TTSD_MODE_INTERRUPT == ttsd_get_mode()) { + g_service_name = (char*)calloc(strlen(TTS_INTERRUPT_SERVER_SERVICE_NAME) + 1, sizeof(char)); + g_service_object = (char*)calloc(strlen(TTS_INTERRUPT_SERVER_SERVICE_OBJECT_PATH) + 1, sizeof(char)); + g_service_interface = (char*)calloc(strlen(TTS_INTERRUPT_SERVER_SERVICE_INTERFACE) + 1, sizeof(char)); + + if (NULL == g_service_name || NULL == g_service_object || NULL == g_service_interface) { + SLOG(LOG_ERROR, tts_tag(), "[ERROR] Fail to allocate memory"); + __ttsd_dbus_service_free(); + __ttsd_dbus_connection_free(); + return -1; + } + + snprintf(g_service_name, strlen(TTS_INTERRUPT_SERVER_SERVICE_NAME) + 1, "%s", TTS_INTERRUPT_SERVER_SERVICE_NAME); + snprintf(g_service_object, strlen(TTS_INTERRUPT_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", TTS_INTERRUPT_SERVER_SERVICE_OBJECT_PATH); + snprintf(g_service_interface, strlen(TTS_INTERRUPT_SERVER_SERVICE_INTERFACE) + 1, "%s", TTS_INTERRUPT_SERVER_SERVICE_INTERFACE); } else { g_service_name = (char*)calloc(strlen(TTS_SERVER_SERVICE_NAME) + 1, sizeof(char)); g_service_object = (char*)calloc(strlen(TTS_SERVER_SERVICE_OBJECT_PATH) + 1, sizeof(char)); diff --git a/server/ttsd_main.h b/server/ttsd_main.h index 05f4a10..41b7389 100644 --- a/server/ttsd_main.h +++ b/server/ttsd_main.h @@ -57,7 +57,8 @@ typedef enum { typedef enum { TTSD_MODE_DEFAULT = 0, /**< Default mode for normal application */ TTSD_MODE_NOTIFICATION, /**< Notification mode */ - TTSD_MODE_SCREEN_READER /**< Screen reader mode */ + TTSD_MODE_SCREEN_READER, /**< Screen reader mode */ + TTSD_MODE_INTERRUPT /**< Interrupt mode */ } ttsd_mode_e; typedef enum { diff --git a/server/ttsd_player.c b/server/ttsd_player.c index f9d8450..54d1ef6 100644 --- a/server/ttsd_player.c +++ b/server/ttsd_player.c @@ -21,6 +21,9 @@ #include "ttsd_data.h" #include "ttsd_dbus.h" +#include "tts_internal.h" +#include "ttsd_server.h" + /* * Internal data structure */ @@ -66,6 +69,7 @@ static audio_out_h g_audio_h; static sound_stream_info_h g_stream_info_h; +static int g_focus_watch_id; /* * Internal Interfaces */ @@ -104,7 +108,7 @@ void __player_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Invalid stream info handle"); return; } - SLOG(LOG_WARN, tts_tag(), "[Player] focus state changed to (%d) with reason(%d)", (int)focus_state, (int)reason_for_change); + 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 (AUDIO_STATE_PLAY == g_audio_state && focus_mask == SOUND_STREAM_FOCUS_FOR_PLAYBACK && SOUND_STREAM_FOCUS_STATE_RELEASED == focus_state) { if (TTSD_MODE_DEFAULT == ttsd_get_mode()) { @@ -133,11 +137,88 @@ void __player_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus } } +/* if (AUDIO_STATE_READY == g_audio_state && focus_mask == SOUND_STREAM_FOCUS_FOR_PLAYBACK && SOUND_STREAM_FOCUS_STATE_ACQUIRED == focus_state) { + if (TTSD_MODE_DEFAULT == ttsd_get_mode()) { + g_audio_state = AUDIO_STATE_PLAY; + + if (NULL == g_playing_info) { + SLOG(LOG_WARN, tts_tag(), "[Player WARNING] No current player"); + return; + } + + if (APP_STATE_PAUSED == g_playing_info->state) { + int uid = g_playing_info->uid; + + g_audio_state = AUDIO_STATE_PLAY; + if (0 != ttsd_player_resume(uid)) { + SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to resume the player"); + g_audio_state = AUDIO_STATE_READY; + return; + } + + ttsd_data_set_client_state(uid, APP_STATE_PLAYING); + int pid = ttsd_data_get_pid(uid); + ttsdc_send_set_state_message(pid, uid, APP_STATE_PLAYING); + } + + } else { + SLOG(LOG_DEBUG, tts_tag(), "[Player] Ignore focus state cb - mode(%d)", ttsd_get_mode()); + } + } +*/ SLOG(LOG_DEBUG, tts_tag(), "@@@"); return; } +void __player_focus_state_watch_cb(int id, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state, sound_stream_focus_change_reason_e reason, + const char *extra_info, void *user_data) +{ + SLOG(LOG_DEBUG, tts_tag(), "@@@ Focus state watch cb"); + + ttsd_mode_e mode = ttsd_get_mode(); + + if (TTSD_MODE_SCREEN_READER != mode && TTSD_MODE_NOTIFICATION != mode) { + SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] This is not screen-reader mode and notification mode."); + return; + } + + if (AUDIO_STATE_PLAY == g_audio_state && SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION == reason && + NULL != extra_info && 0 == strncmp(extra_info, "TTSD_MODE_INTERRUPT", strlen(extra_info))) { + /* If the focus is changed by "Interrupt" mode and current players of "SR" and "Noti" modes are on going, please stop the current players. */ + g_audio_state = AUDIO_STATE_READY; + + if (NULL == g_playing_info) { + SLOG(LOG_WARN, tts_tag(), "[Player WARNING] No current player"); + return; + } + + if (APP_STATE_PLAYING == g_playing_info->state) { + int uid = g_playing_info->uid; + + if (0 != ttsd_server_stop(uid)) { + SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to stop TTS server"); + return; + } + if (0 != ttsd_player_stop(uid)) { + SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to stop the player"); + return; + } + + ttsd_data_set_client_state(uid, APP_STATE_READY); + int pid = ttsd_data_get_pid(uid); + /* send message to client about changing state */ + ttsdc_send_set_state_message(pid, uid, APP_STATE_READY); + } else { + SLOG(LOG_DEBUG, tts_tag(), "[Player] Not playing state"); + } + } else { + SLOG(LOG_DEBUG, tts_tag(), "[Player] This is not Interrupt mode or not playing state."); + } + + return; +} + static int __create_audio_out(ttse_audio_type_e type, int rate) { int ret = -1; @@ -201,25 +282,39 @@ static void __set_policy_for_playing(int volume) { /* Set stream info */ int ret; - if (TTSD_MODE_DEFAULT == ttsd_get_mode()) { + ttsd_mode_e mode = ttsd_get_mode(); + if (TTSD_MODE_DEFAULT == mode) { ret = sound_manager_acquire_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 acquire focus"); + } else { + SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Success to acquire focus (default mode)"); + } + } else if (TTSD_MODE_INTERRUPT == mode) { + ret = sound_manager_acquire_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, "TTSD_MODE_INTERRUPT"); + 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 (interrupt mode)"); } } + 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"); } + SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] set policy for playing"); + return; } static void __unset_policy_for_playing() { int ret; + ttsd_mode_e mode = ttsd_get_mode(); /* Unset stream info */ - if (TTSD_MODE_DEFAULT == ttsd_get_mode()) { + if (TTSD_MODE_DEFAULT == mode || TTSD_MODE_INTERRUPT == mode) { sound_stream_focus_state_e state_for_playing = SOUND_STREAM_FOCUS_STATE_ACQUIRED; ret = sound_manager_get_focus_state(g_stream_info_h, &state_for_playing, NULL); if (SOUND_MANAGER_ERROR_NONE != ret) { @@ -227,16 +322,58 @@ static void __unset_policy_for_playing() } if (SOUND_STREAM_FOCUS_STATE_ACQUIRED == state_for_playing) { - ret = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL); + if (TTSD_MODE_DEFAULT == mode || TTSD_MODE_INTERRUPT == mode) { + ret = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL); + SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] release focus (mode: %d)", mode); + } + if (SOUND_MANAGER_ERROR_NONE != ret) { SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to release focus"); } } } + SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] unset policy for playing"); + return; } +int ttsd_player_check_current_playback_focus(bool *is_current_interrupt) +{ + int ret; + ttsd_mode_e mode = ttsd_get_mode(); + + if (TTSD_MODE_INTERRUPT != mode) { + /* check the current playback focus */ + sound_stream_focus_change_reason_e reason; + int sound_behavior = 0; + char *extra_info = NULL; + + ret = sound_manager_get_current_playback_focus(&reason, &sound_behavior, &extra_info); + + if (SOUND_MANAGER_ERROR_NONE == ret && NULL != extra_info) { + if (SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION == reason && 0 == strncmp(extra_info, "TTSD_MODE_INTERRUPT", strlen(extra_info))) { + SLOG(LOG_DEBUG, tts_tag(), "[Player] The current focus in Interrupt. Cannot play the requested sound data"); + *is_current_interrupt = true; + + free(extra_info); + extra_info = NULL; + + return TTSD_ERROR_NONE; + } + } + + if (NULL != extra_info) { + free(extra_info); + extra_info = NULL; + } + } + + *is_current_interrupt = false; + + return TTSD_ERROR_NONE; +} + static void __play_thread(void *data, Ecore_Thread *thread) { SLOG(LOG_DEBUG, tts_tag(), "@@@ Start thread"); @@ -413,6 +550,7 @@ static void __play_thread(void *data, Ecore_Thread *thread) return; } + __set_policy_for_playing(40); } @@ -625,6 +763,15 @@ int ttsd_player_init() SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Create stream info"); } + /* add sound focus state watch callback */ + ret = sound_manager_add_focus_state_watch_cb(SOUND_STREAM_FOCUS_FOR_PLAYBACK, __player_focus_state_watch_cb, NULL, &g_focus_watch_id); + if (SOUND_MANAGER_ERROR_NONE != ret) { + SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to add sound focus watch callback"); + return -1; + } else { + SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Add sound focus watch callback"); + } + ecore_thread_max_set(1); ret = __create_audio_out(TTSE_AUDIO_TYPE_RAW_S16, 16000); @@ -677,6 +824,14 @@ int ttsd_player_release(void) SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Destroy stream info"); } + /* remove focus state watch callback */ + ret = sound_manager_remove_focus_state_watch_cb(g_focus_watch_id); + if (SOUND_MANAGER_ERROR_NONE != ret) { + SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to remove the focus state watch cb"); + } else { + SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] Remove the focus state watch cb"); + } + /* clear g_player_list */ g_playing_info = NULL; g_player_init = false; diff --git a/server/ttsd_player.h b/server/ttsd_player.h index 430e2c0..ffa0c37 100644 --- a/server/ttsd_player.h +++ b/server/ttsd_player.h @@ -57,6 +57,8 @@ int ttsd_player_all_stop(); int ttsd_player_play_pcm(int uid); +int ttsd_player_check_current_playback_focus(bool *is_current_interrupt); + #ifdef __cplusplus } #endif diff --git a/server/ttsd_server.c b/server/ttsd_server.c index 2734b0b..24365e5 100644 --- a/server/ttsd_server.c +++ b/server/ttsd_server.c @@ -851,6 +851,19 @@ int ttsd_server_play(int uid, const char* credential) } } + /* check the current playback focus */ + if (TTSD_MODE_INTERRUPT != ttsd_get_mode()) { + bool is_current_interrupt = false; + if (0 != ttsd_player_check_current_playback_focus(&is_current_interrupt)) { + SLOG(LOG_ERROR, tts_tag(), "[Server ERROR] Fail to check the current playback focus"); + } else { + if (true == is_current_interrupt) { + SLOG(LOG_WARN, tts_tag(), "[Server WARNING] Current playback focus is set on Interrupt mode. Cannot play default, screen reader, and noti modes."); + return TTSD_ERROR_AUDIO_POLICY_BLOCKED; + } + } + } + int current_uid = ttsd_data_get_current_playing(); SLOG(LOG_INFO, tts_tag(), "[Server] playing uid (%d)", current_uid); diff --git a/server/ttse.c b/server/ttse.c index 5dd4071..bd7ed92 100755 --- a/server/ttse.c +++ b/server/ttse.c @@ -32,6 +32,8 @@ const char* tts_tag() return "ttsdnoti"; } else if (TTSD_MODE_SCREEN_READER == g_tts_mode) { return "ttsdsr"; + } else if (TTSD_MODE_INTERRUPT == g_tts_mode) { + return "ttsdinterrupt"; } else { return "ttsd"; } @@ -63,6 +65,8 @@ int ttse_main(int argc, char** argv, ttse_request_callback_s *callback) mode = TTSD_MODE_NOTIFICATION; } else if (!strcmp("sr", val)) { mode = TTSD_MODE_SCREEN_READER; + } else if (!strcmp("interrupt", val)) { + mode = TTSD_MODE_INTERRUPT; } else { SLOG(LOG_WARN, tts_tag(), "[WARNING] mode (%s)", val); } diff --git a/tts-server.conf b/tts-server.conf index 932c226..fa770dd 100644 --- a/tts-server.conf +++ b/tts-server.conf @@ -50,4 +50,16 @@ + + + + + + + + + + + -- 2.7.4