policy: Add stream-manager.c and communicater.c 81/41281/4
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 12 Jun 2015 06:54:56 +0000 (15:54 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 24 Jun 2015 07:44:16 +0000 (16:44 +0900)
Add stream-map parsing logic to stream-manager.c
Add initial codes for matching up each sink-input/source-output and it's clients to stream-manager.c
Support dbus methods for getting stream list and stream information per type to stream-manager.c
Manage streams made by pa_scache, virtual-stream from sound-manager

[Version] 0.5.1
[Profile] Common
[Issue Type] Add feature

Change-Id: Ia66f42960c3f260e046f211cef097d026cf67694

packaging/pulseaudio.spec
src/Makefile.am
src/modules/communicator.c [new file with mode: 0644]
src/modules/communicator.h [new file with mode: 0644]
src/modules/module-policy.c
src/modules/stream-manager.c [new file with mode: 0644]
src/modules/stream-manager.h [new file with mode: 0644]
src/modules/tizen-audio.h
src/pulse/proplist.h

index 1f7c126..43e0997 100644 (file)
@@ -11,7 +11,7 @@
 Name:             pulseaudio
 Summary:          Improved Linux sound server
 Version:          5.0
-Release:          0
+Release:          1
 Group:            Multimedia/Audio
 License:          GPL-2.0+ and LGPL-2.1+
 URL:              http://pulseaudio.org
index a6808c5..bc80a45 100755 (executable)
@@ -2296,10 +2296,10 @@ module_rygel_media_server_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libprotocol-
 module_rygel_media_server_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
 
 if USE_SAMSUNG_POLICY
-module_policy_la_SOURCES = modules/module-policy.c
+module_policy_la_SOURCES = modules/module-policy.c modules/communicator.c modules/communicator.h modules/stream-manager.c modules/stream-manager.h
 module_policy_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_policy_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(ASOUNDLIB_LIBS) libprotocol-native.la libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
-module_policy_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(ASOUNDLIB_CFLAGS)
+module_policy_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) $(ASOUNDLIB_LIBS) libprotocol-native.la libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
+module_policy_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(LIBJSON_CFLAGS) $(ASOUNDLIB_CFLAGS)
 endif
 
 ###################################
diff --git a/src/modules/communicator.c b/src/modules/communicator.c
new file mode 100644 (file)
index 0000000..cd5d2f9
--- /dev/null
@@ -0,0 +1,89 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2015 Sangchul Lee <sc11.lee@samsung.com>
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "communicator.h"
+
+struct _pa_communicator {
+    PA_REFCNT_DECLARE;
+
+    pa_core *core;
+    pa_hook hooks[PA_COMMUNICATOR_HOOK_MAX];
+};
+
+pa_communicator* pa_communicator_get(pa_core *core) {
+    pa_communicator *c;
+    unsigned i;
+
+    pa_assert(core);
+
+    if ((c = pa_shared_get(core, "communicator")))
+        return pa_communicator_ref(c);
+
+    c = pa_xnew0(pa_communicator, 1);
+    PA_REFCNT_INIT(c);
+    c->core = core;
+
+    for (i = 0; i < PA_COMMUNICATOR_HOOK_MAX; i++)
+        pa_hook_init(&c->hooks[i], c);
+
+    pa_shared_set(core, "communicator", c);
+
+    return c;
+}
+
+pa_communicator* pa_communicator_ref(pa_communicator *c) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) > 0);
+
+    PA_REFCNT_INC(c);
+
+    return c;
+}
+
+void pa_communicator_unref(pa_communicator *c) {
+    unsigned i;
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) > 0);
+
+    if (PA_REFCNT_DEC(c) > 0)
+        return;
+
+    for (i = 0; i < PA_COMMUNICATOR_HOOK_MAX; i++)
+        pa_hook_done(&c->hooks[i]);
+
+    if (c->core)
+        pa_shared_remove(c->core, "communicator");
+
+    pa_xfree(c);
+}
+
+pa_hook* pa_communicator_hook(pa_communicator *c, pa_communicator_hook_t hook) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) > 0);
+
+    return &c->hooks[hook];
+}
+
diff --git a/src/modules/communicator.h b/src/modules/communicator.h
new file mode 100644 (file)
index 0000000..70cda4e
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef foocommunicatorfoo
+#define foocommunicatorfoo
+#include <pulsecore/core.h>
+
+typedef enum pa_communicator_hook {
+    PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE,
+    PA_COMMUNICATOR_HOOK_CHANGE_ROUTE,
+    PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTION,
+    PA_COMMUNICATOR_HOOK_MAX
+} pa_communicator_hook_t;
+
+typedef struct _pa_communicator pa_communicator;
+
+pa_communicator* pa_communicator_get(pa_core *c);
+pa_communicator* pa_communicator_ref(pa_communicator *c);
+void pa_communicator_unref(pa_communicator *c);
+pa_hook* pa_communicator_hook(pa_communicator *c, pa_communicator_hook_t hook);
+
+#endif
index c6f13b6..6867b32 100644 (file)
@@ -39,6 +39,8 @@
 
 #include "module-policy-symdef.h"
 #include "tizen-audio.h"
+#include "communicator.h"
+#include "stream-manager.h"
 
 #define VCONFKEY_SOUND_HDMI_SUPPORT "memory/private/sound/hdmisupport"
 #ifdef PRIMARY_VOLUME
@@ -256,7 +258,7 @@ struct userdata {
         void *dl_handle;
         void *data;
         audio_interface_t intf;
-    } audio_mgr;
+    } hal_manager;
 
     struct  { // for burst-shot
         pa_bool_t is_running;
@@ -269,6 +271,15 @@ struct userdata {
         pa_usec_t time_interval;
         pa_usec_t factor; /* timer boosting */
     } audio_sample_userdata;
+
+    struct {
+        pa_communicator *comm;
+        pa_hook_slot *comm_hook_select_proper_sink_or_source_slot;
+        pa_hook_slot *comm_hook_change_route_slot;
+        pa_hook_slot *comm_hook_update_route_option_slot;
+    } communicator;
+
+    pa_stream_manager *stream_manager;
 };
 
 enum {
@@ -1814,7 +1825,7 @@ static audio_return_t policy_play_sample_continuously(struct userdata *u, pa_nat
     /* FIXME : Add gain_type parameter to API like volume_type */
     audio_info.stream.gain_type = gain_type;
 
-    if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_volume_value(u->audio_mgr.data, &audio_info, volume_type, volume_level, &volume_linear)))) {
+    if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_volume_value(u->hal_manager.data, &audio_info, volume_type, volume_level, &volume_linear)))) {
         pa_log_warn("get_volume_value returns error:0x%x", audio_ret);
         goto exit;
     }
@@ -1958,7 +1969,7 @@ static audio_return_t policy_play_sample(struct userdata *u, pa_native_connectio
     /* FIXME : Add gain_type parameter to API like volume_type */
     audio_info.stream.gain_type = gain_type;
 
-    if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_volume_value(u->audio_mgr.data, &audio_info, volume_type, volume_level, &volume_linear)))) {
+    if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_volume_value(u->hal_manager.data, &audio_info, volume_type, volume_level, &volume_linear)))) {
         pa_log_warn("get_volume_value returns error:0x%x", audio_ret);
         goto exit;
     }
@@ -2004,9 +2015,10 @@ static audio_return_t policy_reset(struct userdata *u)
 
     pa_log_debug("reset");
     __load_dump_config(u);
-    if (u->audio_mgr.intf.reset) {
-        if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.reset(&u->audio_mgr.data)))) {
-            pa_log_error("audio_mgr reset failed");
+
+    if (u->hal_manager.intf.reset) {
+        if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.reset(&u->hal_manager.data)))) {
+            pa_log_error("hal_manager reset failed");
             return audio_ret;
         }
     }
@@ -2035,12 +2047,12 @@ static audio_return_t policy_set_session(struct userdata *u, uint32_t session, u
         } else {
             u->subsession = AUDIO_SUBSESSION_NONE;
         }
-        if (u->audio_mgr.intf.set_session) {
-            u->audio_mgr.intf.set_session(u->audio_mgr.data, session, u->subsession, AUDIO_SESSION_CMD_START);
+        if (u->hal_manager.intf.set_session) {
+            u->hal_manager.intf.set_session(u->hal_manager.data, session, u->subsession, AUDIO_SESSION_CMD_START);
         }
     } else {
-        if (u->audio_mgr.intf.set_session) {
-            u->audio_mgr.intf.set_session(u->audio_mgr.data, session, u->subsession, AUDIO_SESSION_CMD_END);
+        if (u->hal_manager.intf.set_session) {
+            u->hal_manager.intf.set_session(u->hal_manager.data, session, u->subsession, AUDIO_SESSION_CMD_END);
         }
         u->session = AUDIO_SESSION_MEDIA;
         u->subsession = AUDIO_SUBSESSION_NONE;
@@ -2060,8 +2072,8 @@ static audio_return_t policy_set_session(struct userdata *u, uint32_t session, u
     if (need_route) {
         uint32_t route_flag = __get_route_flag(u);
 
-        if (u->audio_mgr.intf.set_route) {
-            u->audio_mgr.intf.set_route(u->audio_mgr.data, u->session, u->subsession, u->active_device_in, u->active_device_out, route_flag);
+        if (u->hal_manager.intf.set_route) {
+            u->hal_manager.intf.set_route(u->hal_manager.data, u->session, u->subsession, u->active_device_in, u->active_device_out, route_flag);
         }
         u->active_route_flag = route_flag;
     } else {
@@ -2095,8 +2107,8 @@ static audio_return_t policy_set_subsession(struct userdata *u, uint32_t subsess
     u->subsession_opt = subsession_opt;
 #endif
 
-    if (u->audio_mgr.intf.set_session) {
-        u->audio_mgr.intf.set_session(u->audio_mgr.data, u->session, u->subsession, AUDIO_SESSION_CMD_SUBSESSION);
+    if (u->hal_manager.intf.set_session) {
+        u->hal_manager.intf.set_session(u->hal_manager.data, u->session, u->subsession, AUDIO_SESSION_CMD_SUBSESSION);
     }
 
     if (prev_subsession!= subsession) {
@@ -2114,8 +2126,8 @@ static audio_return_t policy_set_subsession(struct userdata *u, uint32_t subsess
     if (need_route) {
         uint32_t route_flag = __get_route_flag(u);
 
-        if (u->audio_mgr.intf.set_route) {
-            u->audio_mgr.intf.set_route(u->audio_mgr.data, u->session, u->subsession, u->active_device_in, u->active_device_out, route_flag);
+        if (u->hal_manager.intf.set_route) {
+            u->hal_manager.intf.set_route(u->hal_manager.data, u->session, u->subsession, u->active_device_in, u->active_device_out, route_flag);
         }
         u->active_route_flag = route_flag;
     } else {
@@ -2161,8 +2173,8 @@ static audio_return_t policy_set_active_device(struct userdata *u, uint32_t devi
     }
 
 #ifdef TIZEN_MICRO
-    if (u->audio_mgr.intf.set_route) {
-        u->audio_mgr.intf.set_route(u->audio_mgr.data, u->session, u->subsession, device_in, device_out, route_flag);
+    if (u->hal_manager.intf.set_route) {
+        u->hal_manager.intf.set_route(u->hal_manager.data, u->session, u->subsession, device_in, device_out, route_flag);
     }
 #else
 
@@ -2170,7 +2182,7 @@ static audio_return_t policy_set_active_device(struct userdata *u, uint32_t devi
     if(u->active_device_out == device_out) {
         *need_update = false;
     }
-    if (u->audio_mgr.intf.set_route) {
+    if (u->hal_manager.intf.set_route) {
         audio_return_t audio_ret = AUDIO_RET_OK;
         const char *device_switching_str;
         uint32_t device_switching = 0;
@@ -2200,7 +2212,7 @@ static audio_return_t policy_set_active_device(struct userdata *u, uint32_t devi
         }
 #endif
 
-        u->audio_mgr.intf.set_route(u->audio_mgr.data, u->session, u->subsession, device_in, device_out, route_flag);
+        u->hal_manager.intf.set_route(u->hal_manager.data, u->session, u->subsession, device_in, device_out, route_flag);
         /* Unmute sink inputs which are muted due to device switching */
         PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
             if ((device_switching_str = pa_proplist_gets(si->proplist, "module-policy.device_switching"))) {
@@ -2253,8 +2265,8 @@ static audio_return_t policy_get_volume_level_max(struct userdata *u, uint32_t v
     audio_return_t audio_ret = AUDIO_RET_OK;
 
     /* Call HAL function if exists */
-    if (u->audio_mgr.intf.get_volume_level_max) {
-        if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_volume_level_max(u->audio_mgr.data, volume_type, volume_level)))) {
+    if (u->hal_manager.intf.get_volume_level_max) {
+        if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_volume_level_max(u->hal_manager.data, volume_type, volume_level)))) {
             pa_log_error("get_volume_level_max returns error:0x%x", audio_ret);
             return audio_ret;
         }
@@ -2289,8 +2301,8 @@ static audio_return_t __update_volume(struct userdata *u, uint32_t stream_idx, u
     }
 
     /* Call HAL function if exists */
-    if (u->audio_mgr.intf.set_volume_level && (stream_idx == PA_INVALID_INDEX)) {
-        if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.set_volume_level(u->audio_mgr.data, NULL, volume_type, volume_level)))) {
+    if (u->hal_manager.intf.set_volume_level && (stream_idx == PA_INVALID_INDEX)) {
+        if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.set_volume_level(u->hal_manager.data, NULL, volume_type, volume_level)))) {
             pa_log_error("set_volume_level returns error:0x%x", audio_ret);
             return audio_ret;
         }
@@ -2309,8 +2321,8 @@ static audio_return_t __update_volume(struct userdata *u, uint32_t stream_idx, u
             pa_cvolume cv;
 
             /* Call HAL function if exists */
-            if (u->audio_mgr.intf.set_volume_level) {
-                if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.set_volume_level(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, volume_level)))) {
+            if (u->hal_manager.intf.set_volume_level) {
+                if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.set_volume_level(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, volume_level)))) {
                     pa_log_error("set_volume_level for sink-input[%d] returns error:0x%x", idx, audio_ret);
                     __free_audio_info(&audio_info);
                     return audio_ret;
@@ -2318,8 +2330,8 @@ static audio_return_t __update_volume(struct userdata *u, uint32_t stream_idx, u
             }
 
             /* Get volume value by type & level */
-            if (u->audio_mgr.intf.get_volume_value && (audio_ret != AUDIO_RET_USE_HW_CONTROL)) {
-                if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_volume_value(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, volume_level, &volume_linear)))) {
+            if (u->hal_manager.intf.get_volume_value && (audio_ret != AUDIO_RET_USE_HW_CONTROL)) {
+                if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_volume_value(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, volume_level, &volume_linear)))) {
                     pa_log_warn("get_volume_value for sink-input[%d] returns error:0x%x", idx, audio_ret);
                     __free_audio_info(&audio_info);
                     return audio_ret;
@@ -2362,8 +2374,8 @@ static audio_return_t __update_volume_by_value(struct userdata *u, uint32_t stre
             pa_cvolume cv;
 
             // 1. get gain first
-            if (u->audio_mgr.intf.get_gain_value) {
-                if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_gain_value(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, &gain)))) {
+            if (u->hal_manager.intf.get_gain_value) {
+                if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_gain_value(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, &gain)))) {
                     pa_log_warn("get_gain_value for sink-input[%d] volume_type(%d), returns error:0x%x", idx, audio_info.stream.volume_type, audio_ret);
                     __free_audio_info(&audio_info);
                     return audio_ret;
@@ -2374,8 +2386,8 @@ static audio_return_t __update_volume_by_value(struct userdata *u, uint32_t stre
             volume *= gain;
 
             /* 3. adjust hw volume(LPA), Call HAL function if exists */
-            if (u->audio_mgr.intf.set_volume_value) {
-                if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.set_volume_value(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, &volume)))) {
+            if (u->hal_manager.intf.set_volume_value) {
+                if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.set_volume_value(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, &volume)))) {
                     pa_log_error("set_volume_level for sink-input[%d] returns error:0x%x", idx, audio_ret);
                     __free_audio_info(&audio_info);
                     return audio_ret;
@@ -2516,8 +2528,8 @@ static audio_return_t policy_get_volume_level(struct userdata *u, uint32_t strea
         pa_log_warn("volume_type (%d) invalid", *volume_type);
         return AUDIO_ERR_PARAMETER;
     }
-    if (u->audio_mgr.intf.get_volume_level) {
-        u->audio_mgr.intf.get_volume_level(u->audio_mgr.data, *volume_type, volume_level);
+    if (u->hal_manager.intf.get_volume_level) {
+        u->hal_manager.intf.get_volume_level(u->hal_manager.data, *volume_type, volume_level);
     }
 
     pa_log_info("get_volume_level stream_idx:%d type:%d level:%d", stream_idx, *volume_type, *volume_level);
@@ -2538,8 +2550,8 @@ static audio_return_t policy_get_volume_value(struct userdata *u, uint32_t strea
             return AUDIO_ERR_UNDEFINED;
         }
 
-        if(u->audio_mgr.intf.get_volume_value) {
-            if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_volume_value(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, *volume_level, volume_linear)))) {
+        if(u->hal_manager.intf.get_volume_value) {
+            if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_volume_value(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, *volume_level, volume_linear)))) {
                 pa_log_warn("get_volume_value for stream_idx[%d] returns error:0x%x", stream_idx, audio_ret);
                 return audio_ret;
             }
@@ -2555,8 +2567,8 @@ static audio_return_t policy_set_volume_level(struct userdata *u, uint32_t strea
 
     /* Store volume level of type */
     if (volume_type != (uint32_t)-1) {
-        if (u->audio_mgr.intf.set_volume_level) {
-            u->audio_mgr.intf.set_volume_level(u->audio_mgr.data, NULL, volume_type, volume_level);
+        if (u->hal_manager.intf.set_volume_level) {
+            u->hal_manager.intf.set_volume_level(u->hal_manager.data, NULL, volume_type, volume_level);
         }
     }
 
@@ -2577,8 +2589,8 @@ static audio_return_t policy_update_volume(struct userdata *u) {
     pa_log_info("update_volume");
 
     for (volume_type = 0; volume_type < AUDIO_VOLUME_TYPE_MAX; volume_type++) {
-        if (u->audio_mgr.intf.get_volume_level) {
-            u->audio_mgr.intf.get_volume_level(u->audio_mgr.data, volume_type, &volume_level);
+        if (u->hal_manager.intf.get_volume_level) {
+            u->hal_manager.intf.get_volume_level(u->hal_manager.data, volume_type, &volume_level);
         }
         __update_volume(u, (uint32_t)-1, volume_type, volume_level);
 #ifdef WEARABLE_FIX // commit : update call mute status after changing audio pathupdate call mute status after changing audio path
@@ -2586,10 +2598,10 @@ static audio_return_t policy_update_volume(struct userdata *u) {
         if (u->session == AUDIO_SESSION_VOICECALL) {
             uint32_t call_muted = 0;
 
-            if (u->audio_mgr.intf.get_mute) {
-                u->audio_mgr.intf.get_mute(u->audio_mgr.data, NULL, AUDIO_VOLUME_TYPE_CALL, AUDIO_DIRECTION_IN, &call_muted);
-                if (u->call_muted != (int)call_muted && u->audio_mgr.intf.set_mute) {
-                    u->audio_mgr.intf.set_mute(u->audio_mgr.data, NULL, AUDIO_VOLUME_TYPE_CALL, AUDIO_DIRECTION_IN, u->call_muted);
+            if (u->hal_manager.intf.get_mute) {
+                u->hal_manager.intf.get_mute(u->hal_manager.data, NULL, AUDIO_VOLUME_TYPE_CALL, AUDIO_DIRECTION_IN, &call_muted);
+                if (u->call_muted != (int)call_muted && u->hal_manager.intf.set_mute) {
+                    u->hal_manager.intf.set_mute(u->hal_manager.data, NULL, AUDIO_VOLUME_TYPE_CALL, AUDIO_DIRECTION_IN, u->call_muted);
                 }
             }
         }
@@ -2605,8 +2617,8 @@ static audio_return_t policy_get_mute(struct userdata *u, uint32_t stream_idx, u
     uint32_t idx;
     audio_info_t audio_info;
 
-    if (u->audio_mgr.intf.get_mute && (stream_idx == PA_INVALID_INDEX)) {
-        audio_ret = u->audio_mgr.intf.get_mute(u->audio_mgr.data, NULL, volume_type, direction, mute);
+    if (u->hal_manager.intf.get_mute && (stream_idx == PA_INVALID_INDEX)) {
+        audio_ret = u->hal_manager.intf.get_mute(u->hal_manager.data, NULL, volume_type, direction, mute);
         if (audio_ret == AUDIO_RET_USE_HW_CONTROL) {
             return audio_ret;
         } else {
@@ -2626,8 +2638,8 @@ static audio_return_t policy_get_mute(struct userdata *u, uint32_t stream_idx, u
             if ((stream_idx == idx) || ((stream_idx == PA_INVALID_INDEX) && (audio_info.stream.volume_type == volume_type))) {
 
                 /* Call HAL function if exists */
-                if (u->audio_mgr.intf.get_mute) {
-                    audio_ret = u->audio_mgr.intf.get_mute(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, direction, mute);
+                if (u->hal_manager.intf.get_mute) {
+                    audio_ret = u->hal_manager.intf.get_mute(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, direction, mute);
                     if (audio_ret == AUDIO_RET_USE_HW_CONTROL) {
                         return audio_ret;
                     } else if (AUDIO_IS_ERROR(audio_ret)) {
@@ -2681,8 +2693,8 @@ static audio_return_t policy_set_mute(struct userdata *u, uint32_t stream_idx, u
     }
 
     /* Call HAL function if exists */
-    if (u->audio_mgr.intf.set_mute && (stream_idx == PA_INVALID_INDEX)) {
-        audio_ret = u->audio_mgr.intf.set_mute(u->audio_mgr.data, NULL, volume_type, direction, mute);
+    if (u->hal_manager.intf.set_mute && (stream_idx == PA_INVALID_INDEX)) {
+        audio_ret = u->hal_manager.intf.set_mute(u->hal_manager.data, NULL, volume_type, direction, mute);
         if (audio_ret == AUDIO_RET_USE_HW_CONTROL) {
             pa_log_info("set_mute(call) returns error:0x%x mute:%d", audio_ret, mute);
             return audio_ret;
@@ -2703,8 +2715,8 @@ static audio_return_t policy_set_mute(struct userdata *u, uint32_t stream_idx, u
             if ((stream_idx == idx) || ((stream_idx == PA_INVALID_INDEX) && (audio_info.stream.volume_type == volume_type))) {
 
                 /* Call HAL function if exists */
-                if (u->audio_mgr.intf.set_mute) {
-                    audio_ret = u->audio_mgr.intf.set_mute(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, direction, mute);
+                if (u->hal_manager.intf.set_mute) {
+                    audio_ret = u->hal_manager.intf.set_mute(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, direction, mute);
                     if (AUDIO_IS_ERROR(audio_ret)) {
                         pa_log_error("set_mute for sink-input[%d] returns error:0x%x", idx, audio_ret);
                         return audio_ret;
@@ -2758,9 +2770,9 @@ static void policy_get_buffer_attr(struct userdata       *u,
     assert(minreq);
     assert(fragsize);
 
-    pa_log_debug("hal-latency : u->intf.audio_mgr.get_buffer_attr(%p)", u->audio_mgr.intf.get_buffer_attr);
-    if (u->audio_mgr.intf.get_buffer_attr != NULL) {
-        audio_return_t ret = u->audio_mgr.intf.get_buffer_attr(u->audio_mgr.data, latency, samplerate, format, channels, maxlength, tlength, prebuf, minreq, fragsize);
+    pa_log_debug("hal-latency : u->intf.hal_manager.get_buffer_attr(%p)", u->hal_manager.intf.get_buffer_attr);
+    if (u->hal_manager.intf.get_buffer_attr != NULL) {
+        audio_return_t ret = u->hal_manager.intf.get_buffer_attr(u->hal_manager.data, latency, samplerate, format, channels, maxlength, tlength, prebuf, minreq, fragsize);
         if (ret != AUDIO_RET_OK) {
             pa_log_error("Failed get_buffer_attr() - ret:%d", ret);
         }
@@ -2978,7 +2990,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
             u->muteall = enable;
 
 /* Use mute instead of volume for muteall */
-#if 1
+#if 1 /* volume feature will be moved to stream-manager */
 #ifdef TIZEM_MICRO
             /* Special case. Set mute for call volume type in B3. */
             policy_set_mute(u, (-1), AUDIO_VOLUME_TYPE_CALL, AUDIO_DIRECTION_OUT, u->muteall);
@@ -3245,7 +3257,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
         pa_log_debug(" New stream lacks property data.");
         return PA_HOOK_OK;
     }
-
+#if 1
     /* If no policy exists, skip */
     if (!(policy = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_POLICY))) {
         pa_log_debug("Not setting device for stream [%s], because it lacks policy.",
@@ -3292,7 +3304,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
     if(new_sink != new_data->sink)
         pa_sink_input_new_data_set_sink(new_data, new_sink, false);
     }
-
+#endif
     s = pa_strbuf_new();
     master_name = pa_proplist_gets(new_data->sink->proplist, PA_PROP_DEVICE_MASTER_DEVICE);
     if (master_name)
@@ -3308,8 +3320,8 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
         // set role type
         __set_sink_input_role_type(new_data->proplist, audio_info.stream.gain_type);
 
-        if (u->audio_mgr.intf.get_volume_level) {
-            u->audio_mgr.intf.get_volume_level(u->audio_mgr.data, audio_info.stream.volume_type, &volume_level);
+        if (u->hal_manager.intf.get_volume_level) {
+            u->hal_manager.intf.get_volume_level(u->hal_manager.data, audio_info.stream.volume_type, &volume_level);
         }
 
         pa_strbuf_printf(s, "[%s] policy[%s] ch[%d] rate[%d] volume&gain[%d,%d] level[%d]",
@@ -3324,16 +3336,16 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
         pa_strbuf_printf(s, " sink[%s]", (new_data->sink)? new_data->sink->name : "null");
 
         /* Call HAL function if exists */
-        if (u->audio_mgr.intf.set_volume_level) {
-            if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.set_volume_level(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, volume_level)))) {
+        if (u->hal_manager.intf.set_volume_level) {
+            if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.set_volume_level(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, volume_level)))) {
                 pa_log_warn("set_volume_level for new sink-input returns error:0x%x", audio_ret);
                 goto exit;
             }
         }
 
         /* Get volume value by type & level */
-        if (u->audio_mgr.intf.get_volume_value && (audio_ret != AUDIO_RET_USE_HW_CONTROL)) {
-            if (AUDIO_IS_ERROR((audio_ret = u->audio_mgr.intf.get_volume_value(u->audio_mgr.data, &audio_info, audio_info.stream.volume_type, volume_level, &volume_linear)))) {
+        if (u->hal_manager.intf.get_volume_value && (audio_ret != AUDIO_RET_USE_HW_CONTROL)) {
+            if (AUDIO_IS_ERROR((audio_ret = u->hal_manager.intf.get_volume_value(u->hal_manager.data, &audio_info, audio_info.stream.volume_type, volume_level, &volume_linear)))) {
                 pa_log_warn("get_volume_value for new sink-input returns error:0x%x", audio_ret);
                 goto exit;
             }
@@ -3350,10 +3362,6 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
         __free_audio_info(&audio_info);
     }
 
-    /* get buffer_attr by audio latency */
-    pa_log_info("hal-latency - get buffer attr by audio latency");
-    __add_hal_buffer_attr_by_latency(u, new_data->proplist, new_data->sample_spec);
-
 exit:
     if (s) {
         s_info = pa_strbuf_tostring_free(s);
@@ -3393,6 +3401,9 @@ static pa_hook_result_t sink_input_put_callback(pa_core *core, pa_sink_input *i,
     pa_sink_input_assert_ref(i);
     pa_assert(u);
 
+    /* get buffer_attr by audio latency */
+    pa_log_info("hal-latency - get buffer attr by audio latency");
+    __add_hal_buffer_attr_by_latency(u, i->proplist, i->sample_spec);
 #ifdef PRIMARY_VOLUME
     if ((si_volume_type_str = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)) &&
         pa_sink_input_get_state(i) != PA_SINK_INPUT_CORKED /* if sink-input is created by pulsesink, sink-input init state is cork.*/) {
@@ -3411,8 +3422,10 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct
     uint32_t idx;
     char *args = NULL;
 
-    bool is_bt;
-    bool is_usb_alsa;
+    pa_bool_t is_bt;
+    pa_bool_t is_usb_alsa;
+    pa_bool_t is_need_to_move = true;
+       uint32_t device_out = AUDIO_DEVICE_OUT_BT_A2DP;
 
     pa_assert(c);
     pa_assert(sink);
@@ -3433,10 +3446,23 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct
     }
 
     if (is_bt) {
-        /* Load mono_bt sink */
-        args = pa_sprintf_malloc("sink_name=%s master=%s channels=1", SINK_MONO_BT, sink->name);
-        u->module_mono_bt = pa_module_load(u->module->core, "module-remap-sink", args);
-        pa_xfree(args);
+/*
+        pa_log_info("new bluetooth sink(card) is detected. volume level and route will be changed by sound_server a2dp_on function");
+        is_need_to_move = false;
+        */
+    }
+
+    if (is_need_to_move) {
+        int ret = 0;
+        uint32_t route_flag = 0;
+
+        /* Set active device out */
+        if (u->active_device_out != device_out) {
+            route_flag = __get_route_flag(u);
+            if (u->hal_manager.intf.set_route) {
+                ret = u->hal_manager.intf.set_route(u->hal_manager.data, u->session, u->subsession, u->active_device_in, device_out, route_flag);
+            }
+        }
 
         /* load combine sink */
         args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", SINK_COMBINED, sink->name, SINK_ALSA);
@@ -4040,6 +4066,65 @@ static pa_hook_result_t source_output_unlink_post_hook_callback(pa_core *c, pa_s
     return PA_HOOK_OK;
 }
 
+static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_select *data, struct userdata *u) {
+    pa_log("select_proper_sink_or_source_hook_cb is called. (%p), stream_type(%d), stream_role(%s), route_type(%d)", data, data->stream_type, data->stream_role, data->route_type);
+    int i = 0;
+    for (i = 0; i < data->device_list_len; i++)
+        pa_log(" - device : type[%s], direction[%d], id[%d]", data->device_list[i].type, data->device_list[i].direction, data->device_list[i].id);
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_route *data, struct userdata *u) {
+    pa_log("route_change_hook_cb is called. (%p), stream_type(%d), stream_role(%s), route_type(%d)", data, data->stream_type, data->stream_role, data->route_type);
+    int i = 0;
+    for (i = 0; i < data->device_list_len; i++)
+        pa_log(" - device : type[%s], direction[%d], id[%d]", data->device_list[i].type, data->device_list[i].direction, data->device_list[i].id);
+#if 0
+    /* from stream manager */
+    typedef struct _device {
+        int device_type;
+        int direction;
+        int id;
+    } device;
+    typedef struct _hook_call_data_for_route {
+        stream_type stream_type;
+        char *stream_role;
+        device *device_list;
+        int device_list_len;
+        pa_sample_spec sample_spec;
+    } pa_stream_manager_hook_data_for_route;
+    typedef struct device_info {
+        int32_t type;
+        int32_t direction;
+        int32_t id;
+    } device_info_t;
+
+    /* to hal manager */
+    typedef struct audio_route_info {
+        char *role;
+        device_info_t *device_infos;
+        int32_t num_of_devices;
+    } audio_route_info_t;
+#endif
+    audio_route_info_t route_info;
+    route_info.role = data->stream_role;
+    if (u->hal_manager.intf.do_route) {
+        if (u->hal_manager.intf.do_route(&u->hal_manager.data, &route_info) != AUDIO_RET_OK) {
+            pa_log_error("do_route() failed");
+        }
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t route_option_update_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_option *data, struct userdata *u) {
+    pa_log("route_option_update_hook_cb is called. (%p), stream_role(%d), option_list_len(%d)", data, data->stream_role, data->option_list_len);
+    int i = 0;
+    for (i = 0; i < data->option_list_len; i++)
+        pa_log(" - idx[%d] : option(%s)", data->option_list[i]);
+    return PA_HOOK_OK;
+}
+
 int pa__init(pa_module *m)
 {
     pa_modargs *ma = NULL;
@@ -4127,44 +4212,46 @@ int pa__init(pa_module *m)
 #ifdef PRIMARY_VOLUME
     vconf_set_int (VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, -1);
 #endif
-    /* Get mono key value for init */
-    vconf_get_bool(MONO_KEY, &u->is_mono);
-    /* Load library & init audio mgr */
-    u->audio_mgr.dl_handle = dlopen(LIB_TIZEN_AUDIO, RTLD_NOW);
-    if (u->audio_mgr.dl_handle) {
-        u->audio_mgr.intf.init = dlsym(u->audio_mgr.dl_handle, "audio_init");
-        u->audio_mgr.intf.deinit = dlsym(u->audio_mgr.dl_handle, "audio_deinit");
-        u->audio_mgr.intf.reset = dlsym(u->audio_mgr.dl_handle, "audio_reset");
-        u->audio_mgr.intf.set_callback = dlsym(u->audio_mgr.dl_handle, "audio_set_callback");
-        u->audio_mgr.intf.get_volume_level_max = dlsym(u->audio_mgr.dl_handle, "audio_get_volume_level_max");
-        u->audio_mgr.intf.get_volume_level = dlsym(u->audio_mgr.dl_handle, "audio_get_volume_level");
-        u->audio_mgr.intf.get_volume_value = dlsym(u->audio_mgr.dl_handle, "audio_get_volume_value");
-        u->audio_mgr.intf.set_volume_level = dlsym(u->audio_mgr.dl_handle, "audio_set_volume_level");
-        u->audio_mgr.intf.set_volume_value = dlsym(u->audio_mgr.dl_handle, "audio_set_volume_value");
-        u->audio_mgr.intf.get_gain_value = dlsym(u->audio_mgr.dl_handle, "audio_get_gain_value");
-        u->audio_mgr.intf.get_mute = dlsym(u->audio_mgr.dl_handle, "audio_get_mute");
-        u->audio_mgr.intf.set_mute = dlsym(u->audio_mgr.dl_handle, "audio_set_mute");
-        u->audio_mgr.intf.alsa_pcm_open = dlsym(u->audio_mgr.dl_handle, "audio_alsa_pcm_open");
-        u->audio_mgr.intf.alsa_pcm_close = dlsym(u->audio_mgr.dl_handle, "audio_alsa_pcm_close");
-        u->audio_mgr.intf.pcm_open = dlsym(u->audio_mgr.dl_handle, "audio_pcm_open");
-        u->audio_mgr.intf.pcm_close = dlsym(u->audio_mgr.dl_handle, "audio_pcm_close");
-        u->audio_mgr.intf.pcm_avail = dlsym(u->audio_mgr.dl_handle, "audio_pcm_avail");
-        u->audio_mgr.intf.pcm_write = dlsym(u->audio_mgr.dl_handle, "audio_pcm_write");
-        u->audio_mgr.intf.set_session = dlsym(u->audio_mgr.dl_handle, "audio_set_session");
-        u->audio_mgr.intf.set_route = dlsym(u->audio_mgr.dl_handle, "audio_set_route");
-        u->audio_mgr.intf.set_mixer_value_string = dlsym(u->audio_mgr.dl_handle, "audio_set_mixer_value_string");
-
-        u->audio_mgr.intf.get_buffer_attr = dlsym(u->audio_mgr.dl_handle, "audio_get_buffer_attr");
-        if (u->audio_mgr.intf.init) {
-            if (u->audio_mgr.intf.init(&u->audio_mgr.data, (void *)u) != AUDIO_RET_OK) {
-                pa_log_error("audio_mgr init failed");
+    /* Load library & init HAL manager */
+    u->hal_manager.dl_handle = dlopen(LIB_TIZEN_AUDIO, RTLD_NOW);
+    if (u->hal_manager.dl_handle) {
+        u->hal_manager.intf.init = dlsym(u->hal_manager.dl_handle, "audio_init");
+        u->hal_manager.intf.deinit = dlsym(u->hal_manager.dl_handle, "audio_deinit");
+        u->hal_manager.intf.reset = dlsym(u->hal_manager.dl_handle, "audio_reset");
+        u->hal_manager.intf.set_callback = dlsym(u->hal_manager.dl_handle, "audio_set_callback");
+        u->hal_manager.intf.get_volume_level_max = dlsym(u->hal_manager.dl_handle, "audio_get_volume_level_max");
+        u->hal_manager.intf.get_volume_level = dlsym(u->hal_manager.dl_handle, "audio_get_volume_level");
+        u->hal_manager.intf.get_volume_value = dlsym(u->hal_manager.dl_handle, "audio_get_volume_value");
+        u->hal_manager.intf.set_volume_level = dlsym(u->hal_manager.dl_handle, "audio_set_volume_level");
+        u->hal_manager.intf.set_volume_value = dlsym(u->hal_manager.dl_handle, "audio_set_volume_value");
+        u->hal_manager.intf.get_gain_value = dlsym(u->hal_manager.dl_handle, "audio_get_gain_value");
+        u->hal_manager.intf.get_mute = dlsym(u->hal_manager.dl_handle, "audio_get_mute");
+        u->hal_manager.intf.set_mute = dlsym(u->hal_manager.dl_handle, "audio_set_mute");
+        u->hal_manager.intf.alsa_pcm_open = dlsym(u->hal_manager.dl_handle, "audio_alsa_pcm_open");
+        u->hal_manager.intf.alsa_pcm_close = dlsym(u->hal_manager.dl_handle, "audio_alsa_pcm_close");
+        u->hal_manager.intf.pcm_open = dlsym(u->hal_manager.dl_handle, "audio_pcm_open");
+        u->hal_manager.intf.pcm_close = dlsym(u->hal_manager.dl_handle, "audio_pcm_close");
+        u->hal_manager.intf.pcm_avail = dlsym(u->hal_manager.dl_handle, "audio_pcm_avail");
+        u->hal_manager.intf.pcm_write = dlsym(u->hal_manager.dl_handle, "audio_pcm_write");
+        u->hal_manager.intf.set_session = dlsym(u->hal_manager.dl_handle, "audio_set_session");
+        u->hal_manager.intf.set_route = dlsym(u->hal_manager.dl_handle, "audio_set_route");
+        u->hal_manager.intf.set_mixer_value_string = dlsym(u->hal_manager.dl_handle, "audio_set_mixer_value_string");
+#ifdef ENABLE_NEW_ROUTE
+        u->hal_manager.intf.do_route = dlsym(u->hal_manager.dl_handle, "audio_do_route");
+        u->hal_manager.intf.update_route_option = dlsym(u->hal_manager.dl_handle, "audio_update_route_option");
+#endif
+
+        u->hal_manager.intf.get_buffer_attr = dlsym(u->hal_manager.dl_handle, "audio_get_buffer_attr");
+        if (u->hal_manager.intf.init) {
+            if (u->hal_manager.intf.init(&u->hal_manager.data, (void *)u) != AUDIO_RET_OK) {
+                pa_log_error("hal_manager init failed");
             }
         }
 
-        pa_shared_set(u->core, "tizen-audio-data", u->audio_mgr.data);
-        pa_shared_set(u->core, "tizen-audio-interface", &u->audio_mgr.intf);
+        pa_shared_set(u->core, "tizen-audio-data", u->hal_manager.data);
+        pa_shared_set(u->core, "tizen-audio-interface", &u->hal_manager.intf);
 
-        if (u->audio_mgr.intf.set_callback) {
+        if (u->hal_manager.intf.set_callback) {
             audio_cb_interface_t cb_interface;
 
             cb_interface.load_device = __load_device_callback;
@@ -4172,12 +4259,27 @@ int pa__init(pa_module *m)
             cb_interface.close_all_devices = __close_all_devices_callback;
             cb_interface.close_device = __close_device_callback;
             cb_interface.unload_device = __unload_device_callback;
-            u->audio_mgr.intf.set_callback(u->audio_mgr.data, &cb_interface);
+            u->hal_manager.intf.set_callback(u->hal_manager.data, &cb_interface);
         }
 
     } else {
-        pa_log_error("open audio_mgr failed :%s", dlerror());
+        pa_log_error("open hal_manager failed :%s", dlerror());
+    }
+
+    u->communicator.comm = pa_communicator_get(u->core);
+    if (u->communicator.comm) {
+        u->communicator.comm_hook_select_proper_sink_or_source_slot = pa_hook_connect(pa_communicator_hook(u->communicator.comm,PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE),
+                    PA_HOOK_EARLY, (pa_hook_cb_t) select_proper_sink_or_source_hook_cb, u);
+        u->communicator.comm_hook_change_route_slot = pa_hook_connect(pa_communicator_hook(u->communicator.comm,PA_COMMUNICATOR_HOOK_CHANGE_ROUTE),
+                    PA_HOOK_EARLY, (pa_hook_cb_t) route_change_hook_cb, u);
+        u->communicator.comm_hook_update_route_option_slot = pa_hook_connect(pa_communicator_hook(u->communicator.comm,PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTION),
+                    PA_HOOK_EARLY, (pa_hook_cb_t) route_option_update_hook_cb, u);
     }
+    u->stream_manager = pa_stream_manager_init(u->core);
+#if 0
+    u->device_manager = pa_device_manager_init(u->core);
+#endif
+
     __load_dump_config(u);
     pa_log_info("policy module is loaded\n");
 
@@ -4227,14 +4329,30 @@ void pa__done(pa_module *m)
     if (u->source_output_new_hook_slot)
         pa_hook_slot_free(u->source_output_new_hook_slot);
 
-    /* Deinit audio mgr & unload library */
-    if (u->audio_mgr.intf.deinit) {
-        if (u->audio_mgr.intf.deinit(&u->audio_mgr.data) != AUDIO_RET_OK) {
-            pa_log_error("audio_mgr deinit failed");
+    /* Deinit HAL manager & unload library */
+    if (u->hal_manager.intf.deinit) {
+        if (u->hal_manager.intf.deinit(&u->hal_manager.data) != AUDIO_RET_OK) {
+            pa_log_error("hal_manager deinit failed");
         }
     }
-    if (u->audio_mgr.dl_handle) {
-        dlclose(u->audio_mgr.dl_handle);
+    if (u->hal_manager.dl_handle) {
+        dlclose(u->hal_manager.dl_handle);
+    }
+
+    if (u->stream_manager) {
+        pa_stream_manager_done(u->stream_manager);
+    }
+#if 0
+    if (u->device_manager) {
+        pa_device_manager_done(u->device_manager);
+    }
+#endif
+    if (u->communicator.comm) {
+        if (u->communicator.comm_hook_change_route_slot)
+            pa_hook_slot_free(u->communicator.comm_hook_change_route_slot);
+        if (u->communicator.comm_hook_change_route_slot)
+            pa_hook_slot_free(u->communicator.comm_hook_update_route_option_slot);
+        pa_communicator_unref(u->communicator.comm);
     }
 
     pa_xfree(u);
diff --git a/src/modules/stream-manager.c b/src/modules/stream-manager.c
new file mode 100644 (file)
index 0000000..197747b
--- /dev/null
@@ -0,0 +1,1447 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2015 Sangchul Lee <sc11.lee@samsung.com>
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/proplist.h>
+
+#include <pulsecore/module.h>
+#include <pulsecore/log.h>
+#include <pulsecore/namereg.h>
+#include <pulsecore/sink.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#ifdef HAVE_DBUS
+#include <pulsecore/dbus-shared.h>
+#include <pulsecore/protocol-dbus.h>
+#include <pulsecore/dbus-util.h>
+#endif
+
+#include <json.h>
+#include "tizen-audio.h"
+#include "stream-manager.h"
+#include "communicator.h"
+
+#ifdef HAVE_DBUS
+#define ARR_ARG_MAX  32
+#define STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/Ext/StreamManager"
+#define STREAM_MANAGER_INTERFACE   "org.pulseaudio.Ext.StreamManager"
+#define STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO    "GetStreamInfo"
+#define STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST    "GetStreamList"
+
+static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata);
+static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
+
+enum method_handler_index {
+    METHOD_HANDLER_GET_STREAM_INFO,
+    METHOD_HANDLER_GET_STREAM_LIST,
+    METHOD_HANDLER_MAX
+};
+
+static pa_dbus_arg_info sample_method_args[]    = { { "uri", "s", "in" },
+                                                 { "conf", "i", "in" } };
+static pa_dbus_arg_info get_stream_info_args[]  = { { "stream_type", "s", "in" },
+                                                      { "priority", "i", "out" },
+                                                    { "route_type", "i", "out" },
+                                           { "avail_in_devices", "a(s)", "out" },
+                                          { "avail_out_devices", "a(s)", "out" },
+                                          { "avail_frameworks", "a(s)", "out"} };
+static pa_dbus_arg_info get_stream_list_args[]  = { { "stream_type", "a(s)", "out" },
+                                                     { "priority", "a(i)", "out" } };
+static char* signature_args_for_in[] = { "s","" };
+
+static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
+    [METHOD_HANDLER_GET_STREAM_INFO] = {
+        .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
+        .arguments = get_stream_info_args,
+        .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
+        .receive_cb = handle_get_stream_info },
+    [METHOD_HANDLER_GET_STREAM_LIST] = {
+        .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
+        .arguments = get_stream_list_args,
+        .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
+        .receive_cb = handle_get_stream_list }
+};
+
+#ifdef USE_DBUS_PROTOCOL
+
+static pa_dbus_interface_info stream_manager_interface_info = {
+    .name = STREAM_MANAGER_INTERFACE,
+    .method_handlers = method_handlers,
+    .n_method_handlers = METHOD_HANDLER_MAX,
+    .property_handlers = ,
+    .n_property_handlers = ,
+    .get_all_properties_cb =,
+    .signals =,
+    .n_signals =
+};
+
+#else
+
+#define STREAM_MGR_INTROSPECT_XML                                       \
+    DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                           \
+    "<node>"                                                            \
+    " <interface name=\"STREAM_MANAGER_INTERFACE\">"                    \
+    "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO\">"    \
+    "   <arg name=\"stream_type\" direction=\"in\" type=\"s\"/>"        \
+    "   <arg name=\"priority\" direction=\"out\" type=\"i\"/>"          \
+    "   <arg name=\"route_type\" direction=\"out\" type=\"i\"/>"        \
+    "   <arg name=\"avail_in_devices\" direction=\"out\" type=\"a(s)\"/>" \
+    "   <arg name=\"avail_out_devices\" direction=\"out\" type=\"a(s)\"/>"\
+    "   <arg name=\"avail_frameworks\" direction=\"out\" type=\"a(s)\"/>" \
+    "  </method>"                                                       \
+    "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST\">"    \
+    "   <arg name=\"stream_type\" direction=\"in\" type=\"a(s)\"/>"     \
+    "   <arg name=\"priority\" direction=\"in\" type=\"a(i)\"/>"        \
+    "  </method>"                                                       \
+    " </interface>"                                                     \
+    " <interface name=\"org.freedesktop.DBus.Introspectable\">"         \
+    "  <method name=\"Introspect\">"                                    \
+    "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"              \
+    "  </method>"                                                       \
+    " </interface>"                                                     \
+    "</node>"
+#endif
+
+#endif
+
+#define STREAM_MANAGER_CLIENT_NAME "SOUND_MANAGER_STREAM_INFO"
+#define STREAM_PROCESSED_USING_PUT_UNLINK_1 "VIRTUAL_STREAM"
+#define STREAM_PROCESSED_USING_PUT_UNLINK_2 "SIMPLE_PLAY"
+
+typedef enum pa_process_stream_result {
+    PA_PROCESS_STREAM_OK,
+    PA_PROCESS_STREAM_STOP,
+    PA_PROCESS_STREAM_SKIP,
+} pa_process_stream_result_t;
+
+typedef enum _process_command_type {
+    PROCESS_COMMAND_PREPARE,
+    PROCESS_COMMAND_START,
+    PROCESS_COMMAND_END,
+} process_command_type;
+
+typedef enum _notify_command_type {
+    NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
+    NOTIFY_COMMAND_CHANGE_ROUTE,
+    NOTIFY_COMMAND_UPDATE_ROUTE_OPTION,
+} notify_command_type;
+
+typedef struct _prior_max_priority_stream {
+    pa_sink_input *sink_input;
+    pa_source_output *source_output;
+} cur_max_priority_stream;
+
+struct _stream_manager {
+    pa_core *core;
+    pa_hashmap *stream_map;
+    cur_max_priority_stream cur_highest_priority;
+    void *new_starting_stream;
+    pa_hook_slot
+        *sink_input_new_slot,
+        *sink_input_put_slot,
+        *sink_input_unlink_slot,
+        *sink_input_state_changed_slot,
+        *source_output_new_slot,
+        *source_output_put_slot,
+        *source_output_unlink_slot,
+        *source_output_state_changed_slot;
+#ifdef HAVE_DBUS
+#ifdef USE_DBUS_PROTOCOL
+    pa_dbus_protocol *dbus_protocol;
+#else
+    pa_dbus_connection *dbus_conn;
+#endif
+#endif
+    pa_subscription *subscription;
+    pa_communicator *comm;
+    pa_idxset *clients;
+};
+
+#define STREAM_MAP_FILE "/etc/pulse/stream-map.json"
+#define STREAM_MAP_STREAMS "streams"
+#define STREAM_MAP_STREAM_ROLE "role"
+#define STREAM_MAP_STREAM_PRIORITY "priority"
+#define STREAM_MAP_STREAM_ROUTE_TYPE "route-type"
+#define STREAM_MAP_STREAM_DIRECTIONS "directions"
+#define STREAM_MAP_STREAM_VOLUME_TYPES "volume-types"
+#define STREAM_MAP_STREAM_VOLUME_TYPE_IN "in"
+#define STREAM_MAP_STREAM_VOLUME_TYPE_OUT "out"
+#define STREAM_MAP_STREAM_CAPTURE_VOLUME_TYPE "capture-volume-type"
+#define STREAM_MAP_STREAM_PLAYBACK_VOLUME_TYPE "playback-volume-type"
+#define STREAM_MAP_STREAM_AVAIL_IN_DEVICES "avail-in-devices"
+#define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices"
+#define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks"
+
+enum stream_direction {
+    STREAM_DIRECTION_IN,
+    STREAM_DIRECTION_OUT,
+    STREAM_DIRECTION_MAX,
+};
+
+typedef struct _stream_info {
+    char *role;
+    int32_t priority;
+    char *volume_types[STREAM_DIRECTION_MAX];
+    stream_route_type route_type;
+    pa_hashmap *avail_in_devices;
+    pa_hashmap *avail_out_devices;
+    pa_hashmap *avail_frameworks;
+} stream_info;
+
+typedef struct _stream_parent {
+    uint32_t idx;
+    pa_idxset *idx_sink_inputs;
+    pa_idxset *idx_source_outputs;
+} stream_parent;
+
+#define AVAIL_DEVICES_MAX 16
+#define AVAIL_FRAMEWORKS_MAX 16
+#define AVAIL_STREAMS_MAX 32
+typedef struct _stream_info_per_type {
+    int32_t priority;
+    int32_t route_type;
+    int32_t num_of_in_devices;
+    int32_t num_of_out_devices;
+    int32_t num_of_frameworks;
+    char *avail_in_devices[AVAIL_DEVICES_MAX];
+    char *avail_out_devices[AVAIL_DEVICES_MAX];
+    char *avail_frameworks[AVAIL_FRAMEWORKS_MAX];
+} stream_info_per_type;
+typedef struct _stream_list {
+    int32_t num_of_streams;
+    char* types[AVAIL_STREAMS_MAX];
+    int32_t priorities[AVAIL_STREAMS_MAX];
+} stream_list;
+
+static int get_available_streams_from_map(pa_stream_manager *m, stream_list *list) {
+    void *state;
+    stream_info *s;
+    int i = 0;
+    pa_log_info("get_available_streams_from_map");
+    if (m->stream_map) {
+        PA_HASHMAP_FOREACH(s, m->stream_map, state) {
+            if (i < AVAIL_STREAMS_MAX) {
+                list->priorities[i] = s->priority;
+                list->types[i++] = s->role;
+                pa_log_debug("  [%d] stream_type[%s], priority[%d]", i-1, s->role, s->priority);
+            } else {
+                pa_log_error("  out of range, [%d]", i);
+                break;
+            }
+        }
+        list->num_of_streams = i;
+        pa_log_debug("  num_of_streams[%d]",i);
+    } else {
+        pa_log_error("stream_map is not initialized..");
+        return -1;
+    }
+    return 0;
+}
+
+static int get_stream_info_from_map(pa_stream_manager *m, const char *stream_role, stream_info_per_type *info) {
+    void *state;
+    void *_state;
+    char *name;
+    stream_info *s;
+    int i = 0;
+    int j = 0;
+    int k = 0;
+    pa_log_info("get_stream_info_from_map : role[%s]", stream_role);
+    if (m->stream_map) {
+        PA_HASHMAP_FOREACH(s, m->stream_map, state) {
+            if (pa_streq(stream_role, s->role)) {
+                info->priority = s->priority;
+                info->route_type = s->route_type;
+                PA_HASHMAP_FOREACH(name, s->avail_in_devices, _state) {
+                    pa_log_debug("  avail-in-device[%d] name  : %s", i, name);
+                    if (i < AVAIL_DEVICES_MAX)
+                        info->avail_in_devices[i++] = name;
+                    else
+                        pa_log_error("  avail-in-devices, out of range, [%d]", i);
+                }
+                info->num_of_in_devices = i;
+                PA_HASHMAP_FOREACH(name, s->avail_out_devices, _state) {
+                    pa_log_debug("  avail-out-device[%d] name  : %s", j, name);
+                    if (j < AVAIL_DEVICES_MAX)
+                        info->avail_out_devices[j++] = name;
+                    else
+                        pa_log_error("  avail-out-devices, out of range, [%d]", j);
+                }
+                info->num_of_out_devices = j;
+                PA_HASHMAP_FOREACH(name, s->avail_frameworks, _state) {
+                    pa_log_debug("  avail-framework-name[%d] name  : %s", k, name);
+                    if (j < AVAIL_FRAMEWORKS_MAX)
+                        info->avail_frameworks[k++] = name;
+                    else
+                        pa_log_error("  avail-frameworks, out of range, [%d]", k);
+                }
+                info->num_of_frameworks = k;
+                break;
+            }
+        }
+    } else {
+        pa_log_error("stream_map is not initialized..");
+        return -1;
+    }
+    return 0;
+}
+
+#ifdef HAVE_DBUS
+static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    const char *xml = STREAM_MGR_INTROSPECT_XML;
+    DBusMessage *r = NULL;
+
+    pa_assert(conn);
+    pa_assert(msg);
+    pa_assert(userdata);
+
+    pa_assert_se(r = dbus_message_new_method_return(msg));
+    pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
+
+    if (r) {
+        pa_assert_se(dbus_connection_send((conn), r, NULL));
+        dbus_message_unref(r);
+    }
+
+    return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    stream_list list;
+    pa_stream_manager *m = (pa_stream_manager*)userdata;
+    pa_assert(conn);
+    pa_assert(msg);
+    pa_assert(m);
+
+    pa_assert_se(dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_INVALID));
+    pa_log_info("handle_get_stream_list() dbus method is called");
+
+    memset(&list, 0, sizeof(stream_list));
+    if(!get_available_streams_from_map(m, &list)) {
+        DBusMessage *reply = NULL;
+        DBusMessageIter msg_iter;
+        DBusMessageIter variant_iter;
+        pa_assert_se((reply = dbus_message_new_method_return(msg)));
+        dbus_message_iter_init_append(reply, &msg_iter);
+        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
+        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
+        pa_assert_se(dbus_connection_send(conn, reply, NULL));
+        dbus_message_unref(reply);
+    }
+}
+
+static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    char *type;
+    stream_info_per_type info;
+    pa_stream_manager *m = (pa_stream_manager*)userdata;
+    pa_assert(conn);
+    pa_assert(msg);
+    pa_assert(m);
+
+    pa_assert_se(dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_STRING, &type,
+                                       DBUS_TYPE_INVALID));
+    pa_log_info("handle_get_stream_info(), type[%s]", type);
+    memset(&info, 0, sizeof(stream_info_per_type));
+    if(!get_stream_info_from_map(m, type, &info)) {
+        DBusMessage *reply = NULL;
+        DBusMessageIter msg_iter;
+        pa_assert_se((reply = dbus_message_new_method_return(msg)));
+        dbus_message_iter_init_append(reply, &msg_iter);
+        pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
+        pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
+        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
+        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
+        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
+        pa_assert_se(dbus_connection_send(conn, reply, NULL));
+        dbus_message_unref(reply);
+    }
+}
+
+static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+       int idx = 0;
+    pa_stream_manager *m = (pa_stream_manager*)userdata;
+
+    pa_assert(conn);
+    pa_assert(msg);
+    pa_assert(m);
+
+    for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
+        if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name )) {
+            if (pa_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
+                method_handlers[idx].receive_cb(conn, msg, userdata);
+                return DBUS_HANDLER_RESULT_HANDLED;
+            } else {
+                pa_log_warn("Wrong Argument Signature");
+                pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE,  "Wrong Signature, Expected %s", signature_args_for_in[idx]);
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+            }
+        }
+    }
+
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
+    pa_stream_manager *u = (pa_stream_manager*)userdata;
+    const char *path, *interface, *member;
+
+    pa_assert(c);
+    pa_assert(m);
+    pa_assert(u);
+
+    path = dbus_message_get_path(m);
+    interface = dbus_message_get_interface(m);
+    member = dbus_message_get_member(m);
+
+    pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
+
+    if (!pa_streq(path, STREAM_MANAGER_OBJECT_PATH))
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+        return handle_introspect(c, m, u);
+    } else {
+        return handle_methods(c, m, u);
+    }
+
+    return DBUS_HANDLER_RESULT_HANDLED;
+}
+#endif
+
+static int convert_route_type(stream_route_type *route_type, const char *route_type_string) {
+    int ret = 0;
+    pa_assert(route_type);
+    pa_assert(route_type_string);
+
+    if (pa_streq("auto", route_type_string))
+        *route_type = STREAM_ROUTE_TYPE_AUTO;
+    else if (pa_streq("auto-all", route_type_string))
+        *route_type = STREAM_ROUTE_TYPE_AUTO_ALL;
+    else if (pa_streq("manual", route_type_string))
+        *route_type = STREAM_ROUTE_TYPE_MANUAL;
+    else {
+        ret = -1;
+        pa_log_error("Not supported route_type(%s)", route_type_string);
+    }
+
+    return ret;
+}
+static int init_stream_map (pa_stream_manager *m) {
+    stream_info *s;
+    json_object *o;
+    json_object *stream_array_o;
+    json_object *role_o;
+    json_object *priority_o;
+    json_object *route_type_o;
+    json_object *volume_types_o;
+    json_object *avail_in_devices_o;
+    json_object *avail_out_devices_o;
+    json_object *avail_frameworks_o;
+    int num_of_stream_types = 0;
+    int i = 0;
+    pa_assert(m);
+
+    o = json_object_from_file(STREAM_MAP_FILE);
+    if(is_error(o)) {
+        pa_log_error("Read stream-map file(%s) failed", STREAM_MAP_FILE);
+        return -1;
+    }
+    m->stream_map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
+    if((stream_array_o = json_object_object_get(o, STREAM_MAP_STREAMS)) && json_object_is_type(stream_array_o, json_type_array)){
+        num_of_stream_types = json_object_array_length(stream_array_o);
+        for (i = 0; i < num_of_stream_types; i++) {
+            json_object *stream_o;
+            if((stream_o = json_object_array_get_idx(stream_array_o, i)) && json_object_is_type(stream_o, json_type_object)) {
+                char *string;
+                s = pa_xmalloc0(sizeof(stream_info));
+                pa_log_debug("stream found [%d]", i);
+                if((role_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_ROLE)) && json_object_is_type(role_o, json_type_string)) {
+                    s->role = json_object_get_string(role_o);
+                    pa_log_debug(" - role : %s", s->role);
+                } else {
+                    pa_log_error("Get stream role failed");
+                    goto failed;
+                }
+                if((priority_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_PRIORITY)) && json_object_is_type(priority_o, json_type_int)) {
+                    s->priority = json_object_get_int(priority_o);
+                    pa_log_debug(" - priority : %d", s->priority);
+                } else {
+                    pa_log_error("Get stream priority failed");
+                    goto failed;
+                }
+                if((route_type_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_ROUTE_TYPE)) && json_object_is_type(route_type_o, json_type_string)) {
+                    if (convert_route_type(&(s->route_type), json_object_get_string(route_type_o))) {
+                        pa_log_error("convert stream route-type failed");
+                        goto failed;
+                    }
+                    pa_log_debug(" - route-type : %d", s->route_type);
+                } else {
+                    pa_log_error("Get stream route-type failed");
+                    goto failed;
+                }
+                if((volume_types_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_VOLUME_TYPES)) && json_object_is_type(volume_types_o, json_type_object)) {
+                    json_object *volume_type_in_o;
+                    json_object *volume_type_out_o;
+                    if((volume_type_in_o = json_object_object_get(volume_types_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN)) && json_object_is_type(volume_type_in_o, json_type_string)) {
+                        s->volume_types[STREAM_DIRECTION_IN] = json_object_get_string(volume_type_in_o);
+                    } else {
+                        pa_log_error("Get stream volume-type-in failed");
+                        goto failed;
+                    }
+                    if((volume_type_out_o = json_object_object_get(volume_types_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT)) && json_object_is_type(volume_type_out_o, json_type_string)) {
+                        s->volume_types[STREAM_DIRECTION_OUT] = json_object_get_string(volume_type_out_o);
+                    } else {
+                        pa_log_error("Get stream volume-type-out failed");
+                        goto failed;
+                    }
+                    pa_log_debug(" - volume-types : in[%s], out[%s]", s->volume_types[STREAM_DIRECTION_IN], s->volume_types[STREAM_DIRECTION_OUT]);
+                } else {
+                    pa_log_error("Get stream volume-types failed");
+                    goto failed;
+                }
+                if((avail_in_devices_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_IN_DEVICES)) && json_object_is_type(avail_in_devices_o, json_type_array)) {
+                    int j = 0;
+                    json_object *in_device_o;
+                    s->avail_in_devices = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+                    int num_of_avail_in_devices = json_object_array_length(avail_in_devices_o);
+                    pa_log_debug(" - avail-in-devices");
+                    for (j = 0; j < num_of_avail_in_devices; j++) {
+                        if((in_device_o = json_object_array_get_idx(avail_in_devices_o, j)) && json_object_is_type(in_device_o, json_type_string)) {
+                            pa_hashmap_put(s->avail_in_devices, PA_INT_TO_PTR(j), json_object_get_string(in_device_o));
+                            pa_log_debug("      device[%d] : %s", j, json_object_get_string(in_device_o));
+                           }
+                       }
+                } else {
+                    pa_log_error("Get stream avail-in-devices failed");
+                    goto failed;
+                }
+                if((avail_out_devices_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_OUT_DEVICES)) && json_object_is_type(avail_out_devices_o, json_type_array)) {
+                    int j = 0;
+                    json_object *out_device_o;
+                    s->avail_out_devices = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+                    int num_of_avail_out_devices = json_object_array_length(avail_out_devices_o);
+                    pa_log_debug(" - avail-out-devices");
+                    for (j = 0; j < num_of_avail_out_devices; j++) {
+                        if((out_device_o = json_object_array_get_idx(avail_out_devices_o, j)) && json_object_is_type(out_device_o, json_type_string)) {
+                            pa_hashmap_put(s->avail_out_devices, PA_INT_TO_PTR(j), json_object_get_string(out_device_o));
+                            pa_log_debug("      device[%d] : %s", j, json_object_get_string(out_device_o));
+                           }
+                       }
+                } else {
+                    pa_log_error("Get stream avail-out-devices failed");
+                    goto failed;
+                }
+                if((avail_frameworks_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_FRAMEWORKS)) && json_object_is_type(avail_frameworks_o, json_type_array)) {
+                    int j = 0;
+                    json_object *framework_o;
+                    s->avail_frameworks = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+                    int num_of_avail_frameworks = json_object_array_length(avail_frameworks_o);
+                    pa_log_debug(" - avail-frameworks");
+                    for (j = 0; j < num_of_avail_frameworks; j++) {
+                        if((framework_o = json_object_array_get_idx(avail_frameworks_o, j)) && json_object_is_type(framework_o, json_type_string)) {
+                            pa_hashmap_put(s->avail_frameworks, PA_INT_TO_PTR(j), json_object_get_string(framework_o));
+                            pa_log_debug("      framework[%d] : %s", j, json_object_get_string(framework_o));
+                           }
+                       }
+                } else {
+                    pa_log_error("Get stream avail-frameworks failed");
+                    goto failed;
+                }
+                pa_hashmap_put(m->stream_map, s->role, s);
+            }
+        }
+    } else {
+        pa_log_error("Get streams object failed");
+        goto failed;
+    }
+    return 0;
+failed:
+    if (m->stream_map) {
+        if (s->avail_in_devices)
+            pa_hashmap_free(s->avail_in_devices);
+        if (s->avail_out_devices)
+            pa_hashmap_free(s->avail_out_devices);
+        if (s->avail_frameworks)
+            pa_hashmap_free(s->avail_frameworks);
+        pa_hashmap_free(m->stream_map);
+    }
+    return -1;
+}
+
+static void deinit_stream_map (pa_stream_manager *m) {
+    pa_assert(m);
+    if (m->stream_map) {
+        stream_info *s;
+        void *state;
+        PA_HASHMAP_FOREACH(s, m->stream_map, state) {
+            if (s->avail_in_devices)
+                pa_hashmap_free(s->avail_in_devices);
+            if (s->avail_out_devices)
+                pa_hashmap_free(s->avail_out_devices);
+            if (s->avail_frameworks)
+                pa_hashmap_free(s->avail_frameworks);
+            pa_xfree(s);
+        }
+        pa_hashmap_free(m->stream_map);
+    }
+    return;
+}
+
+static void dump_stream_map (pa_stream_manager *m) {
+    pa_assert(m);
+    pa_log_debug("==========[START stream-map dump]==========");
+    if (m->stream_map) {
+        stream_info *s;
+        char *name;
+        void *state;
+        void *_state;
+        PA_HASHMAP_FOREACH(s, m->stream_map, state) {
+            pa_log_debug("[role : %s]", s->role);
+            pa_log_debug("  - prirority  : %d", s->priority);
+            pa_log_debug("  - route-type : %d (0:auto,1:auto-all,2:manual,3:manual-all)", s->route_type);
+            pa_log_debug("  - volume-types : in[%s], out[%s]", s->volume_types[STREAM_DIRECTION_IN], s->volume_types[STREAM_DIRECTION_OUT]);
+            pa_log_debug("  - avail-in-devices");
+            PA_HASHMAP_FOREACH(name, s->avail_in_devices, _state) {
+                pa_log_debug("      name  : %s", name);
+            }
+            pa_log_debug("  - avail-out-devices");
+            PA_HASHMAP_FOREACH(name, s->avail_out_devices, _state) {
+                pa_log_debug("      name  : %s", name);
+            }
+            pa_log_debug("  - avail-frameworks");
+            PA_HASHMAP_FOREACH(name, s->avail_frameworks, _state) {
+                pa_log_debug("      name  : %s", name);
+            }
+        }
+    }
+    pa_log_debug("===========[END stream-map dump]===========");
+    return;
+}
+
+static pa_bool_t check_role_to_skip(const char *role, pa_stream_manager *m) {
+    pa_bool_t ret = TRUE;
+    pa_assert(role);
+    pa_assert(m);
+
+    if (m->stream_map) {
+        void *state;
+        stream_info *s;
+        PA_HASHMAP_FOREACH(s, m->stream_map, state) {
+            if (pa_streq(role, s->role)) {
+                ret = FALSE;
+                break;
+            }
+        }
+    }
+
+    pa_log_info("role is %s, skip(%d)", role, ret);
+
+    return ret;
+}
+
+static pa_bool_t update_priority_of_stream(stream_type type, void *stream, const char *role, pa_stream_manager *m, int32_t *priority) {
+    pa_assert(role);
+    pa_assert(m);
+
+    if (m->stream_map) {
+        stream_info *s;
+        s = pa_hashmap_get(m->stream_map, role);
+        *priority = s->priority;
+    }
+
+    pa_proplist_setf(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY, "%d", *priority);
+
+    return TRUE;
+}
+
+static pa_bool_t update_routing_type_of_stream(stream_type type, void *stream, const char *role, pa_stream_manager *m) {
+    stream_route_type route_type = STREAM_ROUTE_TYPE_AUTO;
+    pa_assert(role);
+    pa_assert(m);
+
+    if (m->stream_map) {
+        stream_info *s = pa_hashmap_get(m->stream_map, role);
+        route_type = s->route_type;
+    }
+
+    pa_proplist_setf(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE_ROUTE_TYPE, "%d", route_type);
+
+    return TRUE;
+}
+
+static pa_bool_t update_stream_parent_info(process_command_type command, stream_type type, void *stream, pa_stream_manager *m) {
+    char *p_idx;
+    uint32_t idx;
+
+    pa_assert(stream);
+    pa_assert(m);
+
+    p_idx = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_PARENT_ID);
+    if (p_idx && !pa_atou(p_idx, &idx)) {
+        pa_log_debug("***p_idx(%s), idx(%u)", p_idx, idx);
+        stream_parent *sp = NULL;
+        void *state = NULL;
+        while ((sp = pa_idxset_iterate(m->clients, &state, NULL))) {
+            if (sp->idx == idx) {
+                uint32_t *idx_addr = (type==STREAM_SINK_INPUT)?&((pa_sink_input*)stream)->index:&((pa_source_output*)stream)->index;
+                if (command == PROCESS_COMMAND_START) {
+                    /* append this stream to the parent stream info. */
+                    pa_log_debug(" - append this idx_addr(%p),idx(%u) to the list, sp(%p), stream_type(%d)", idx_addr, *idx_addr, sp, type);
+                    pa_idxset_put(type==STREAM_SINK_INPUT?(sp->idx_sink_inputs):(sp->idx_source_outputs), idx_addr, NULL);
+                    return TRUE;
+                } else if (command == PROCESS_COMMAND_END) {
+                    /* remove this stream from the parent stream info. */
+                    pa_log_debug(" - remove this idx_addr(%p),idx(%u) from the list, sp(%p), stream_type(%d)", idx_addr, *idx_addr, sp, type);
+                    pa_idxset_remove_by_data(type==STREAM_SINK_INPUT?(sp->idx_sink_inputs):(sp->idx_source_outputs), idx_addr, NULL);
+                    return TRUE;
+                } else {
+                    pa_log_error("invalid command(%d)", command);
+                    return FALSE;
+                }
+            }
+        }
+        if (sp == NULL) {
+            pa_log_error("could not find matching client for this parent_id(%u)", idx);
+            return FALSE;
+        }
+    } else {
+        pa_log_error("p_idx(%s) or idx(%u) is not valid", p_idx, idx);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static pa_bool_t update_the_highest_priority_stream(stream_type type, void *mine, const char *role, int32_t priority, pa_stream_manager *m, pa_bool_t *need_to_update) {
+    uint32_t idx = 0;
+    int32_t p_max;
+    void *cur_max_stream = NULL;
+    char *cur_max_priority = NULL;
+    char *cur_max_role = NULL;
+    *need_to_update = FALSE;
+
+    pa_assert(mine);
+    pa_assert(m);
+    if (!role) {
+        pa_log_error("invalid input, role(%s)", role);
+        return FALSE;
+    }
+
+    if (type == STREAM_SINK_INPUT) {
+        cur_max_stream = m->cur_highest_priority.sink_input;
+    } else if (type == STREAM_SOURCE_OUTPUT) {
+        cur_max_stream = m->cur_highest_priority.source_output;
+    }
+
+    pa_log_error("stream : type(%d), role(%s), priority(%d) ", type, role, priority);
+    if (priority != -1) {
+        if (cur_max_stream == NULL) {
+            *need_to_update = TRUE;
+            pa_log_debug("set cur_highest to mine");
+            if (type == STREAM_SINK_INPUT) {
+                m->cur_highest_priority.sink_input = mine;
+            } else if (type == STREAM_SOURCE_OUTPUT) {
+                m->cur_highest_priority.source_output = mine;
+            }
+        } else {
+            /* TODO : need to check if this stream should be played to external devices */
+            cur_max_priority = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)cur_max_stream)->proplist:((pa_source_output*)cur_max_stream)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY);
+            cur_max_role = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)cur_max_stream)->proplist:((pa_source_output*)cur_max_stream)->proplist, PA_PROP_MEDIA_ROLE);
+            if (!cur_max_priority || !cur_max_role) {
+                pa_log_error("Failed to pa_proplist_gets() for getting current max priority(%s) and it's role(%s)", cur_max_priority, cur_max_role);
+                return FALSE;
+            } else {
+                if (pa_atoi(cur_max_priority, &p_max)) {
+                    pa_log_error("Failed to pa_atoi(), cur_max_priority(%s)", cur_max_priority);
+                    return FALSE;
+                }
+                if (priority < p_max) {
+                    /* no need to trigger */
+                    return TRUE;
+                } else {
+                    *need_to_update = TRUE;
+                    pa_log_debug("update cur_highest to mine(%s)", role);
+                    if (type == STREAM_SINK_INPUT) {
+                        m->cur_highest_priority.sink_input = mine;
+                    } else if (type == STREAM_SOURCE_OUTPUT) {
+                        m->cur_highest_priority.source_output = mine;
+                    }
+                }
+            }
+        }
+    } else {
+        void *cur_max_stream_tmp = NULL;
+        void *i = NULL;
+        char *role = NULL;
+        char *priority = NULL;
+        int32_t p;
+        pa_idxset *streams = NULL;
+        if (cur_max_stream == mine) {
+            if (type == STREAM_SINK_INPUT) {
+                streams = ((pa_sink_input*)mine)->sink->inputs;
+            } else if (type == STREAM_SOURCE_OUTPUT) {
+                streams = ((pa_source_output*)mine)->source->outputs;
+            }
+            /* find the next highest priority input */
+            //PA_IDXSET_FOREACH(i, m->core->sinks, idx) { /* need to check a sink which this stream belongs to */
+            PA_IDXSET_FOREACH(i, streams, idx) {
+                if (!(role = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)i)->proplist:((pa_source_output*)i)->proplist, PA_PROP_MEDIA_ROLE))){
+                    pa_log_error("Failed to pa_proplist_gets() for role");
+                    continue;
+                }
+                if (!(priority = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)i)->proplist:((pa_source_output*)i)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY))){
+                    pa_log_error("Failed to pa_proplist_gets() for priority");
+                    continue;
+                }
+                pa_log_debug("role(%s)/priority(%s)/stream(%p)", role, priority, i);
+                if (cur_max_priority == NULL) {
+                    cur_max_priority = priority;
+                    cur_max_stream_tmp = i;
+                }
+                if (pa_atoi(cur_max_priority, &p_max)) {
+                    pa_log_error("Failed to pa_atoi(), cur_max_priority(%s)", cur_max_priority);
+                    continue;
+                }
+                if (pa_atoi(priority, &p)) {
+                    pa_log_error("Failed to pa_atoi(), priority(%s)", priority);
+                    continue;
+                }
+                if (p_max <= p) {
+                    cur_max_priority = priority;
+                    cur_max_stream_tmp = i;
+                    p_max = p;
+                }
+            }
+            pa_log_debug("updated max priority(%s)/stream(%p)", cur_max_priority, cur_max_stream_tmp);
+            if ((p_max > -1) && cur_max_stream_tmp) {
+                if (type == STREAM_SINK_INPUT) {
+                    m->cur_highest_priority.sink_input = cur_max_stream_tmp;
+                } else if (type == STREAM_SOURCE_OUTPUT) {
+                    m->cur_highest_priority.source_output = cur_max_stream_tmp;
+                }
+            } else {
+                if (type == STREAM_SINK_INPUT) {
+                    m->cur_highest_priority.sink_input = NULL;
+                } else if (type == STREAM_SOURCE_OUTPUT) {
+                    m->cur_highest_priority.source_output = NULL;
+                }
+            }
+            *need_to_update = TRUE;
+            pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p/source_output=%p)",
+                        type, (void*)m->cur_highest_priority.sink_input, (void*)m->cur_highest_priority.sink_input);
+        } else {
+            /* no need to trigger */
+            return TRUE;
+        }
+    }
+    return TRUE;
+}
+
+static void fill_device_info_to_hook_data(void *hook_data, notify_command_type command, stream_type type, pa_stream_manager *m) {
+    int i = 0;
+    pa_assert(hook_data);
+    pa_assert(m);
+    switch (command) {
+    case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
+        pa_stream_manager_hook_data_for_select *data = (pa_stream_manager_hook_data_for_select*)hook_data;
+        stream_info *si = pa_hashmap_get(m->stream_map, data->stream_role);
+        data->route_type = si->route_type;
+        if (si->route_type == STREAM_ROUTE_TYPE_AUTO || si->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
+            pa_hashmap *avail_devices = (type==STREAM_SINK_INPUT)?si->avail_out_devices:si->avail_in_devices;
+            int list_len = pa_hashmap_size(avail_devices);
+            char *device_name = pa_hashmap_get(avail_devices, 0);
+            if (list_len == 1 && pa_streq(device_name, "none")) {
+                /* no available devices for this role */
+            } else {
+                data->device_list = (device*)pa_xmalloc0(sizeof(device)*list_len);
+                for (i = 0; i < list_len; i++) {
+                    data->device_list[i].type = pa_hashmap_get(avail_devices, i);
+                    data->device_list[i].direction = !(int)type;
+                }
+                data->device_list_len = list_len;
+            }
+        } else if (si->route_type == STREAM_ROUTE_TYPE_MANUAL) {
+            /* TODO : need to check device for explicit routing */
+            /* find parent idx and it's device info. */
+        }
+        break;
+    }
+    case NOTIFY_COMMAND_CHANGE_ROUTE: {
+        pa_stream_manager_hook_data_for_route *data = (pa_stream_manager_hook_data_for_route*)hook_data;
+        stream_info *si = pa_hashmap_get(m->stream_map, data->stream_role);
+        data->route_type = si->route_type;
+        if (si->route_type == STREAM_ROUTE_TYPE_AUTO || si->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
+            pa_hashmap *avail_devices = (type==STREAM_SINK_INPUT)?si->avail_out_devices:si->avail_in_devices;
+            int list_len = pa_hashmap_size(avail_devices);
+            char *device_name = pa_hashmap_get(avail_devices, 0);
+            if (list_len == 1 && pa_streq(device_name, "none")) {
+                /* no available devices for this role */
+            } else {
+                data->device_list = (device*)pa_xmalloc0(sizeof(device)*list_len);
+                for (i = 0; i < list_len; i++) {
+                    data->device_list[i].type = pa_hashmap_get(avail_devices, i);
+                    data->device_list[i].direction = !(int)type;
+                }
+                data->device_list_len = list_len;
+            }
+        } else if (si->route_type == STREAM_ROUTE_TYPE_MANUAL) {
+            /* TODO : need to check device for explicit routing */
+#if 0
+            char *p_idx;
+            uint32_t idx;
+            p_idx = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_PARENT_ID);
+            if (p_idx && !pa_atou(p_idx, &idx)) {
+            /* find parent idx, it's device info. and it's children idxs */
+            }
+#endif
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    return;
+}
+
+static void do_notify(notify_command_type command, stream_type type, pa_stream_manager *m) {
+    char *priority = NULL;
+    char *role = NULL;
+
+    pa_assert(m);
+    pa_log_debug("do_notify() : command(%d), type(%d)", command, type);
+    switch (command) {
+    case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
+        pa_stream_manager_hook_data_for_select hook_call_data;
+        memset(&hook_call_data, 0, sizeof(pa_stream_manager_hook_data_for_select));
+        device* device_list = NULL;
+        void *s = m->new_starting_stream;
+        hook_call_data.stream_type = type;
+        hook_call_data.stream_role = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input_new_data*)s)->proplist:((pa_source_output_new_data*)s)->proplist, PA_PROP_MEDIA_ROLE);
+        fill_device_info_to_hook_data(&hook_call_data, command, type, m);
+        hook_call_data.sample_spec.format = (type==STREAM_SINK_INPUT?((pa_sink_input_new_data*)s)->sample_spec.format:((pa_source_output_new_data*)s)->sample_spec.format);
+        hook_call_data.sample_spec.rate = (type==STREAM_SINK_INPUT?((pa_sink_input_new_data*)s)->sample_spec.rate:((pa_source_output_new_data*)s)->sample_spec.rate);
+        if (type == STREAM_SINK_INPUT)
+            hook_call_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
+        else if (type == STREAM_SOURCE_OUTPUT)
+            hook_call_data.proper_source = &(((pa_source_output_new_data*)s)->source);
+
+        pa_hook_fire(pa_communicator_hook(m->comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_data);
+        if (hook_call_data.device_list)
+            pa_xfree(hook_call_data.device_list);
+#if 0
+        {
+            /* TODO : need to notify to change route if needed                               */
+            /* check if 1. this new role is needed to change route before opening the device */
+            /*          2. if yes, do others exist? if no, do below                          */
+            pa_stream_manager_hook_data_for_route hook_call_data;
+            pa_hook_fire(pa_communicator_hook(m->comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_data);
+        }
+#endif
+        break;
+    }
+    case NOTIFY_COMMAND_CHANGE_ROUTE: {
+        pa_stream_manager_hook_data_for_route hook_call_data;
+        memset(&hook_call_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
+        device* device_list = NULL;
+        void *s = (type==STREAM_SINK_INPUT)?m->cur_highest_priority.sink_input:m->cur_highest_priority.source_output;
+        if (s) {
+            priority = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)s)->proplist:((pa_source_output*)s)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY);
+            role = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)s)->proplist:((pa_source_output*)s)->proplist, PA_PROP_MEDIA_ROLE);
+            hook_call_data.stream_type = type;
+            hook_call_data.stream_role = role;
+            hook_call_data.sample_spec.format = (type==STREAM_SINK_INPUT?((pa_sink_input*)s)->sample_spec.format:((pa_source_output*)s)->sample_spec.format);
+            hook_call_data.sample_spec.rate = (type==STREAM_SINK_INPUT?((pa_sink_input*)s)->sample_spec.rate:((pa_source_output*)s)->sample_spec.rate);
+            fill_device_info_to_hook_data(&hook_call_data, command, type, m);
+        } else {
+            pa_log_info("no stream for this type(%d), need to unset route", type);
+            hook_call_data.stream_type = type;
+            hook_call_data.stream_role = "reset";
+        }
+        pa_hook_fire(pa_communicator_hook(m->comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_data);
+        if (hook_call_data.device_list)
+            pa_xfree(hook_call_data.device_list);
+        break;
+    }
+    case NOTIFY_COMMAND_UPDATE_ROUTE_OPTION: {
+        pa_stream_manager_hook_data_for_option hook_call_data;
+        memset(&hook_call_data, 0, sizeof(pa_stream_manager_hook_data_for_option));
+        int test_option_list_len = 2;
+        char* test_option_list[2] = {"test_option1","test_option2"};
+        pa_hook_fire(pa_communicator_hook(m->comm, PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTION), &hook_call_data);
+        break;
+    }
+    }
+
+    return;
+}
+
+static pa_process_stream_result_t process_stream(stream_type type, void *stream, process_command_type command, pa_stream_manager *m) {
+    const char *role;
+    pa_bool_t ret = TRUE;
+    pa_bool_t need_update = FALSE;
+
+    pa_log_info("START process_stream(): stream_type(%d), stream(%p), m(%p), command(%d)", type, stream, m, command);
+    pa_assert(stream);
+    pa_assert(m);
+
+    if (command == PROCESS_COMMAND_PREPARE) {
+        role = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input_new_data*)stream)->proplist:((pa_source_output_new_data*)stream)->proplist, PA_PROP_MEDIA_ROLE);
+        if (!role) {
+            /* set default value for role and priority */
+            #define DEFAULT_ROLE "media"
+            pa_proplist_sets(type==STREAM_SINK_INPUT?((pa_sink_input_new_data *)stream)->proplist:((pa_source_output_new_data *)stream)->proplist, PA_PROP_MEDIA_ROLE, DEFAULT_ROLE);
+            pa_log_error("role is null, set default to (%s)", DEFAULT_ROLE);
+        } else {
+            /* skip roles */
+            if (check_role_to_skip(role, m))
+                return PA_PROCESS_STREAM_SKIP;
+        }
+        m->new_starting_stream = stream;
+
+        /* notify to update */
+        do_notify(NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, m);
+
+    } else {
+        role = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE);
+        if (command == PROCESS_COMMAND_START) {
+            pa_log_debug("stream(%s) is about to be started", role);
+            int32_t priority = 0;
+            pa_log_error("role is (%s)", role);
+
+            /* skip roles */
+            if (check_role_to_skip(role, m))
+                return PA_PROCESS_STREAM_SKIP;
+
+            /* update the priority of this stream */
+            ret = update_priority_of_stream(type, stream, role, m, &priority);
+            if (ret == FALSE) {
+                pa_log_error("could not update the priority of '%s' role.", role);
+                return PA_PROCESS_STREAM_STOP;
+            }
+            /* update the routing type of this stream */
+            ret = update_routing_type_of_stream(type, stream, role, m);
+            if (ret == FALSE) {
+                pa_log_error("could not update the route type of '%s' role.", role);
+                return PA_PROCESS_STREAM_STOP;
+            }
+            /* update the highest priority */
+            ret = update_the_highest_priority_stream(type, stream, role, priority, m, &need_update);
+            if (ret == FALSE) {
+                pa_log_error("could not update the highest priority stream");
+                return PA_PROCESS_STREAM_STOP;
+            }
+            /* update parent stream info. */
+            ret = update_stream_parent_info(command, type, stream, m);
+            if (ret == FALSE) {
+                pa_log_error("could not update the parent information of this stream");
+                return PA_PROCESS_STREAM_STOP;
+            }
+            /* need to skip if this stream does not belong to internal device */
+            /* if needed, notify to update */
+            if (need_update)
+                do_notify(NOTIFY_COMMAND_CHANGE_ROUTE, type, m);
+
+        } else if (command == PROCESS_COMMAND_END) {
+            pa_log_debug("stream(%s) is about to be ended", role);
+            if (role) {
+                /* skip roles */
+                if (check_role_to_skip(role, m))
+                    return PA_PROCESS_STREAM_SKIP;
+                /* mark the priority of this stream to -1 */
+                pa_proplist_setf(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY, "%d", -1);
+                ret = update_the_highest_priority_stream(type, stream, role, -1, m, &need_update);
+                if (ret == FALSE) {
+                    pa_log_error("could not update the highest priority stream");
+                    return PA_PROCESS_STREAM_STOP;
+                }
+                /* update parent stream info. */
+                ret = update_stream_parent_info(command, type, stream, m);
+                if (ret == FALSE) {
+                    pa_log_error("could not update the parent information of this stream");
+                    return PA_PROCESS_STREAM_STOP;
+                }
+                /* need to skip if this stream does not belong to internal device */
+                /* if needed, notify to update */
+                if (need_update)
+                    do_notify(NOTIFY_COMMAND_CHANGE_ROUTE, type, m);
+            } else {
+                pa_log_error("role is null, skip it");
+            }
+        }
+    }
+    pa_log_info("END process_stream()");
+    return PA_PROCESS_STREAM_OK;
+}
+
+static pa_bool_t is_good_to_process(stream_type type, void *stream) {
+    /* Normally, routing process is on input/output state changed cb.      */
+    /* but if a stream named as below, routing process is on put/unlink cb.*/
+    /* Later on it could be changed if it is possible to get notified via  */
+    /* input/output state change cb.                                       */
+    const char *name = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_NAME);
+    if (strncmp (name, STREAM_PROCESSED_USING_PUT_UNLINK_1, strlen(STREAM_PROCESSED_USING_PUT_UNLINK_1)) ||
+        strncmp (name, STREAM_PROCESSED_USING_PUT_UNLINK_2, strlen(STREAM_PROCESSED_USING_PUT_UNLINK_2)) ) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, pa_stream_manager *m) {
+    pa_log_info("start sink_input_new_cb");
+    pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+    pa_core_assert_ref(core);
+
+    process_result = process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_PREPARE, m);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+    pa_log_info("start sink_input_put_cb, i(%p, index:%u)", i, i->index);
+    pa_bool_t ret = FALSE;
+    pa_core_assert_ref(core);
+    pa_sink_input_assert_ref(i);
+
+    ret = is_good_to_process(STREAM_SINK_INPUT, i);
+    if (ret) {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_START, m);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+    pa_log_info("start sink_input_unlink_cb, i(%p, index:%u)", i, i->index);
+    pa_bool_t ret = FALSE;
+    pa_core_assert_ref(core);
+    pa_sink_input_assert_ref(i);
+
+    ret = is_good_to_process(STREAM_SINK_INPUT, i);
+    if (ret) {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_END, m);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+    pa_sink_input_state_t state;
+
+    pa_assert(i);
+    pa_assert(m);
+
+    state = pa_sink_input_get_state(i);
+    pa_log_debug("start sink_input_state_changed_hook_cb(), sink-input(%p), state(%d)", i, state);
+
+    switch(state) {
+    case PA_SINK_INPUT_CORKED: {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_END, m);
+        break;
+    }
+    case PA_SINK_INPUT_DRAINED:
+    case PA_SINK_INPUT_RUNNING: {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_START, m);
+        break;
+    }
+    default:
+        break;
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new_data *new_data, pa_stream_manager *m) {
+    pa_log_info("start source_output_new_new_cb");
+    pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+    pa_core_assert_ref(core);
+
+    process_result = process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_PREPARE, m);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
+    pa_log_info("start source_output_put_cb, o(%p, index:%u)", o, o->index);
+    pa_bool_t ret = FALSE;
+    pa_core_assert_ref(core);
+    pa_source_output_assert_ref(o);
+
+    ret = is_good_to_process(STREAM_SOURCE_OUTPUT, o);
+    if (ret) {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_START, m);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
+    pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
+    pa_bool_t ret = FALSE;
+    pa_core_assert_ref(core);
+    pa_source_output_assert_ref(o);
+
+    ret = is_good_to_process(STREAM_SOURCE_OUTPUT, o);
+    if (ret) {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_END, m);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_state_changed_hook_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
+    pa_source_output_state_t state;
+
+    pa_assert(o);
+    pa_assert(m);
+
+    state = pa_source_output_get_state(o);
+    pa_log_debug("start source_output_state_changed_hook_cb(), source-output(%p), state(%d)", o, state);
+
+    switch(state) {
+    case PA_SINK_INPUT_CORKED: {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_END, m);
+        break;
+    }
+    case PA_SINK_INPUT_DRAINED:
+    case PA_SINK_INPUT_RUNNING: {
+        pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
+        process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_START, m);
+        break;
+    }
+    default:
+        break;
+    }
+
+    return PA_HOOK_OK;
+}
+
+static void subscribe_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, pa_stream_manager *m) {
+    pa_core_assert_ref(core);
+    pa_assert(m);
+    pa_client *client = NULL;
+    const char *name = NULL;
+    pa_log_info("subscribe_cb() is called, t(%x), idx(%u)", t, idx);
+
+    if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE)) {
+        client = pa_idxset_get_by_index(core->clients, idx);
+        if (client == NULL) {
+            pa_log_error(" - could not find any client that has idx(%u)", idx);
+            return;
+        }
+        name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
+        if (strncmp (name, STREAM_MANAGER_CLIENT_NAME, strlen(STREAM_MANAGER_CLIENT_NAME))) {
+            pa_log_warn(" - this is not a client(%s) that we should take care of, skip it", name);
+            return;
+        }
+        /* add a stream parent */
+        uint32_t p_idx = 0;
+        stream_parent *sp = pa_xmalloc0(sizeof(stream_parent));
+        sp->idx = idx;
+        sp->idx_sink_inputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+        sp->idx_source_outputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+        pa_idxset_put(m->clients, sp, NULL);
+        pa_log_debug(" - add sp(%p), idx(%u)", sp, idx);
+     } else if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE)) {
+        /* remove the stream parent */
+        stream_parent *sp = NULL;
+        void *state = NULL;
+        while ((sp = pa_idxset_iterate(m->clients, &state, NULL))) {
+            if (sp->idx == idx) {
+                pa_log_debug(" - remove sp(%p), idx(%u)", sp, idx);
+                pa_idxset_remove_by_data(m->clients, sp, NULL);
+                pa_idxset_free(sp->idx_sink_inputs, NULL);
+                pa_idxset_free(sp->idx_source_outputs, NULL);
+                pa_xfree(sp);
+                break;
+            }
+        }
+    }
+}
+
+static int init_ipc (pa_stream_manager *m) {
+
+    pa_assert(m);
+
+    pa_log_info("Initialization for IPC");
+
+#ifdef HAVE_DBUS
+#ifdef USE_DBUS_PROTOCOL
+    m->dbus_protocol = pa_dbus_protocol_get(m->core);
+    pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
+    pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
+#else
+    DBusError err;
+    pa_dbus_connection *conn = NULL;
+    static const DBusObjectPathVTable vtable = {
+        .message_function = method_handler_for_vt,
+    };
+    dbus_error_init(&err);
+
+    if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
+        if (conn) {
+            pa_dbus_connection_unref(conn);
+        }
+        pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
+        goto fail;
+    } else {
+        pa_log_notice("Got dbus connection");
+    }
+    m->dbus_conn = conn;
+    pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
+#endif
+#else
+    pa_log_error("DBUS is not supported\n");
+    goto fail;
+#endif
+
+    return 0;
+fail:
+    return -1;
+}
+
+static void deinit_ipc (pa_stream_manager *m) {
+
+    pa_assert(m);
+
+#ifdef HAVE_DBUS
+#ifdef USE_DBUS_PROTOCOL
+    if (m->dbus_protocol) {
+        pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
+        pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
+        pa_dbus_protocol_unref(m->dbus_protocol);
+        m->dbus_protocol = NULL;
+    }
+#else
+    if (m->dbus_conn) {
+        if(!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
+            pa_log_error("Failed to unregister object path");
+        m->dbus_conn = NULL;
+    }
+#endif
+#endif
+    return;
+}
+
+pa_stream_manager* pa_stream_manager_init(pa_core *c) {
+    pa_stream_manager *m;
+    const char *ipc_type = NULL;
+
+    pa_assert(c);
+
+    m = pa_xnew0(pa_stream_manager, 1);
+    m->core = c;
+
+#ifdef HAVE_DBUS
+#ifdef USE_DBUS_PROTOCOL
+    m->dbus_protocol = NULL;
+#else
+    m->dbus_conn = NULL;
+#endif
+#endif
+    if (init_ipc(m))
+        goto fail;
+#if 1
+    if (init_stream_map(m))
+        goto fail;
+#endif
+
+    dump_stream_map(m);
+
+    m->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_cb, m);
+    m->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_put_cb, m);
+    m->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_unlink_cb, m);
+    m->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_state_changed_hook_cb, m);
+    m->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_cb, m);
+    m->source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_put_cb, m);
+    m->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_cb, m);
+    m->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_state_changed_hook_cb, m);
+
+    m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, subscribe_cb, m);
+
+    m->comm = pa_communicator_get(c);
+
+    m->clients = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+
+    return m;
+
+fail:
+    deinit_stream_map(m);
+    deinit_ipc(m);
+    pa_xfree(m);
+    return 0;
+}
+
+void pa_stream_manager_done(pa_stream_manager *m) {
+    pa_assert(m);
+
+    if (m->clients)
+        pa_idxset_free(m->clients, NULL);
+
+    if (m->comm)
+        pa_communicator_unref(m->comm);
+
+    if (m->subscription)
+        pa_subscription_free(m->subscription);
+
+    if (m->sink_input_new_slot)
+        pa_hook_slot_free(m->sink_input_new_slot);
+    if (m->sink_input_put_slot)
+        pa_hook_slot_free(m->sink_input_put_slot);
+    if (m->sink_input_unlink_slot)
+        pa_hook_slot_free(m->sink_input_unlink_slot);
+    if (m->source_output_new_slot)
+        pa_hook_slot_free(m->source_output_new_slot);
+    if (m->source_output_put_slot)
+        pa_hook_slot_free(m->source_output_put_slot);
+    if (m->source_output_unlink_slot)
+        pa_hook_slot_free(m->source_output_unlink_slot);
+
+    deinit_stream_map(m);
+
+    deinit_ipc(m);
+
+    pa_xfree(m);
+}
diff --git a/src/modules/stream-manager.h b/src/modules/stream-manager.h
new file mode 100644 (file)
index 0000000..affb439
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef foostreammanagerfoo
+#define foostreammanagerfoo
+#include <pulsecore/core.h>
+
+typedef struct _stream_manager pa_stream_manager;
+
+typedef enum _stream_type {
+    STREAM_SINK_INPUT,
+    STREAM_SOURCE_OUTPUT,
+} stream_type;
+
+typedef enum stream_route_type {
+    STREAM_ROUTE_TYPE_AUTO,     /* the policy of decision device(s) is automatic and it's routing path is particular to one device */
+    STREAM_ROUTE_TYPE_AUTO_ALL, /* the policy of decision device(s) is automatic and it's routing path can be several devices */
+    STREAM_ROUTE_TYPE_MANUAL,   /* the policy of decision device(s) is manual */
+} stream_route_type;
+
+typedef struct _device {
+    char *type;
+    int direction;
+    int id;
+} device;
+
+typedef struct _hook_call_data_for_select {
+    stream_type stream_type;
+    char *stream_role;
+    stream_route_type route_type;
+    device *device_list;
+    int device_list_len;
+    pa_sink **proper_sink;
+    pa_source **proper_source;
+    pa_sample_spec sample_spec;
+} pa_stream_manager_hook_data_for_select;
+
+typedef struct _hook_call_data_for_route {
+    stream_type stream_type;
+    char *stream_role;
+    stream_route_type route_type;
+    device *device_list;
+    int device_list_len;
+    pa_sample_spec sample_spec;
+} pa_stream_manager_hook_data_for_route;
+
+typedef struct _hook_call_data_for_option {
+    char *stream_role;
+    char **option_list;
+    int option_list_len;
+} pa_stream_manager_hook_data_for_option;
+
+pa_stream_manager* pa_stream_manager_init(pa_core *c);
+void pa_stream_manager_done(pa_stream_manager* m);
+
+#endif
index d045cad..d52ef17 100755 (executable)
@@ -148,6 +148,23 @@ typedef enum audio_device_param {
     AUDIO_DEVICE_PARAM_MAX,
 } audio_device_param_t;
 
+enum audio_device_type {
+    AUDIO_DEVICE_NONE,
+    AUDIO_DEVICE_BUILTIN_SPEAKER,
+    AUDIO_DEVICE_BUILTIN_RECEIVER,
+    AUDIO_DEVICE_BUILTIN_MIC,
+    AUDIO_DEVICE_AUDIO_JACK,
+    AUDIO_DEVICE_BT,
+    AUDIO_DEVICE_HDMI,
+    AUDIO_DEVICE_AUX,
+    AUDIO_DEVICE_MAX
+};
+
+enum audio_device_direction_type{
+    AUDIO_DEVICE_DIRECTION_IN,
+    AUDIO_DEVICE_DIRECTION_OUT
+};
+
 typedef struct audio_device_param_info {
     audio_device_param_t param;
     union {
@@ -180,6 +197,23 @@ typedef struct audio_device_info {
     };
 } audio_device_info_t;
 
+typedef struct device_info {
+    int32_t type;
+    int32_t direction;
+    int32_t id;
+} device_info_t;
+
+typedef struct audio_route_info {
+    char *role;
+    device_info_t *device_infos;
+    int32_t num_of_devices;
+} audio_route_info_t;
+
+typedef struct audio_route_option {
+    char *role;
+    char **options;
+    int32_t num_of_options;
+} audio_route_option_t;
 
 /* Stream */
 
@@ -297,6 +331,8 @@ typedef struct audio_interface {
     audio_return_t (*set_mute)(void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t mute);
     audio_return_t (*set_session)(void *userdata, uint32_t session, uint32_t subsession, uint32_t cmd);
     audio_return_t (*set_route)(void *userdata, uint32_t session, uint32_t subsession, uint32_t device_in, uint32_t device_out, uint32_t route_flag);
+    audio_return_t (*do_route)(void *userdata, audio_route_info_t *info);
+    audio_return_t (*update_route_option)(void *userdata, audio_route_option_t *option);
     audio_return_t (*alsa_pcm_open)(void *userdata, void **pcm_handle, char *device_name, uint32_t direction, int mode);
     audio_return_t (*alsa_pcm_close)(void *userdata, void *pcm_handle);
     audio_return_t (*pcm_open)(void *userdata, void **pcm_handle, void *sample_spec, uint32_t direction);
@@ -321,6 +357,8 @@ audio_return_t audio_get_gain_value (void *userdata, audio_info_t *info, uint32_
 audio_return_t audio_get_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t *mute);
 audio_return_t audio_set_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t mute);
 audio_return_t audio_set_session (void *userdata, uint32_t session, uint32_t subsession, uint32_t cmd);
+audio_return_t audio_do_route (void *userdata, audio_route_info_t *info);
+audio_return_t audio_update_route_option (void *userdata, audio_route_option_t *option);
 audio_return_t audio_alsa_pcm_open (void *userdata, void **pcm_handle, char *device_name, uint32_t direction, int mode);
 audio_return_t audio_alsa_pcm_close (void *userdata, void *pcm_handle);
 audio_return_t audio_pcm_open(void *userdata, void **pcm_handle, void *sample_spec, uint32_t direction);
index 44e03f6..0425f3c 100755 (executable)
 
 PA_C_DECL_BEGIN
 
-#ifdef __TIZEN__
-#define PA_PROP_MEDIA_TIZEN_VOLUME_TYPE        "media.tizen_volume_type"
-#define PA_PROP_MEDIA_TIZEN_GAIN_TYPE          "media.tizen_gain_type"
-#define PA_PROP_MEDIA_TIZEN_FADE_STATUS        "media.tizen_fade_status"
-#define PA_PROP_MEDIA_TIZEN_FADE_RETURN_VOLUME "media.tizen_fade_return_volume"
-/** For streams: the policy to ignore the preset sink rather use a sink picked by module-policy. One of the strings "yes", "no" */
-#define PA_PROP_MEDIA_POLICY_IGNORE_PRESET_SINK  "media.policy.ignore_preset_sink"
-#define PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY      "media.tizen_audio_latency"
-/** For streams: logic role of this media. One of the strings "auto", "phone" */
-#define PA_PROP_MEDIA_POLICY                "media.policy"
-#endif
-
 /** For streams: localized media name, formatted as UTF-8. E.g. "Guns'N'Roses: Civil War".*/
 #define PA_PROP_MEDIA_NAME                     "media.name"
 
@@ -86,6 +74,23 @@ PA_C_DECL_BEGIN
 /** For streams: the name of a filter that should specifically suppressed (i.e.\ overrides PA_PROP_FILTER_WANT). Useful for the times that PA_PROP_FILTER_WANT is automatically added (e.g. echo-cancellation for phone streams when $VOIP_APP does it's own, internal AEC) \since 1.0 */
 #define PA_PROP_FILTER_SUPPRESS                "filter.suppress"
 
+#ifdef __TIZEN__
+/** For streams: logic role of this media. One of the strings "auto", "phone" */
+#define PA_PROP_MEDIA_POLICY                "media.policy"
+
+/** For streams: the policy to ignore the preset sink rather use a sink picked by module-policy. One of the strings "yes", "no" */
+#define PA_PROP_MEDIA_POLICY_IGNORE_PRESET_SINK  "media.policy.ignore_preset_sink"
+
+#define PA_PROP_MEDIA_ROLE_PRIORITY            "media.role.priority"
+#define PA_PROP_MEDIA_ROLE_ROUTE_TYPE          "media.role.route_type"
+#define PA_PROP_MEDIA_PARENT_ID                "media.parent_id"
+#define PA_PROP_MEDIA_TIZEN_VOLUME_TYPE        "media.tizen_volume_type"
+#define PA_PROP_MEDIA_TIZEN_GAIN_TYPE          "media.tizen_gain_type"
+#define PA_PROP_MEDIA_TIZEN_FADE_STATUS        "media.tizen_fade_status"
+#define PA_PROP_MEDIA_TIZEN_FADE_RETURN_VOLUME "media.tizen_fade_return_volume"
+#define PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY      "media.tizen_audio_latency"
+#endif
+
 /** For event sound streams: XDG event sound name. e.g.\ "message-new-email" (Event sound streams are those with media.role set to "event") */
 #define PA_PROP_EVENT_ID                       "event.id"