Add a new TTS Interrupt mode 43/167943/1
authorsooyeon.kim <sooyeon.kim@samsung.com>
Fri, 10 Nov 2017 07:09:31 +0000 (16:09 +0900)
committerSuyeon Hwang <stom.hwang@samsung.com>
Tue, 23 Jan 2018 05:31:29 +0000 (05:31 +0000)
Change-Id: I1158619f6c2bc9079bb41c6446795604731aead1
Signed-off-by: sooyeon.kim <sooyeon.kim@samsung.com>
(cherry picked from commit 569aed93a951bb85436090e31e60ec2de42dc8bd)

16 files changed:
CMakeLists.txt
client/tts.c
client/tts_dbus.c
common/tts_defs.h
engine-parser/src/tts-engine-parser.c
include/tts_internal.h
org.tizen.voice.ttsinterruptserver.service [new file with mode: 0644]
org.tizen.voice.ttsinterruptserver.tv.service [new file with mode: 0644]
packaging/tts.spec
server/ttsd_dbus.c
server/ttsd_main.h
server/ttsd_player.c
server/ttsd_player.h
server/ttsd_server.c
server/ttse.c
tts-server.conf

index 8d8c687..f2c5819 100644 (file)
@@ -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.*")
index e6385b4..160b3ab 100644 (file)
@@ -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);
index e7dc689..f922798 100644 (file)
@@ -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);
index c0f57fa..8b11f7c 100644 (file)
@@ -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"
 
index 42414fc..802f6e5 100644 (file)
 #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"
index 29ea810..303b6d3 100644 (file)
@@ -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 (file)
index 0000000..c79f344
--- /dev/null
@@ -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 (file)
index 0000000..f872182
--- /dev/null
@@ -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"
index c7551ea..7d09832 100644 (file)
@@ -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*
index c9015eb..9e0c4f1 100644 (file)
@@ -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));
index 05f4a10..41b7389 100644 (file)
@@ -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 {
index f9d8450..54d1ef6 100644 (file)
@@ -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;
index 430e2c0..ffa0c37 100644 (file)
@@ -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
index 2734b0b..24365e5 100644 (file)
@@ -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);
 
index 5dd4071..bd7ed92 100755 (executable)
@@ -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);
                                }
index 932c226..fa770dd 100644 (file)
     <allow send_destination="org.tizen.voice.ttssrserver"
     send_interface="org.tizen.voice.ttssrserver"/>
   </policy>
+
+
+  <policy user="root">
+    <allow own="org.tizen.voice.ttsinterruptserver"/>
+    <allow send_destination="org.tizen.voice.ttsinterruptserver"/>
+    <allow receive_sender="org.tizen.voice.ttsinterruptserver"/>
+  </policy>
+
+  <policy context="default">
+    <allow send_destination="org.tizen.voice.ttsinterruptserver"
+    send_interface="org.tizen.voice.ttsinterruptserver"/>
+  </policy>
 </busconfig>