device manager refactoring and enhancement 64/85964/9
authorMok Jeongho <jho.mok@samsung.com>
Thu, 11 Aug 2016 08:35:38 +0000 (17:35 +0900)
committerMok Jeongho <jho.mok@samsung.com>
Thu, 8 Sep 2016 05:09:37 +0000 (14:09 +0900)
device manager refactoring
- divide pa_tz_device and it's interfaces to tizen-device
- adopt new_data concept for pa_tz_device
- divide some definitions and static property of device-types to tizen-device-def
bt enhancement
- support multi-device per profile
- deal with call/media option on/off
- sco control(open/close/etc) on pa_tz_device(type=bt)

[Version] 5.0.71
[Profile] Common
[Issue Type] Refactoring

Change-Id: I06c07eaf67e0662b97a26dd9fa874d83c37f5ba2

12 files changed:
Makefile.am
packaging/pulseaudio-modules-tizen.spec
src/device-manager.c
src/device-manager.h
src/module-tizenaudio-policy.c
src/stream-manager.c
src/subscribe-observer.c
src/subscribe-observer.h
src/tizen-device-def.c [new file with mode: 0644]
src/tizen-device-def.h [new file with mode: 0644]
src/tizen-device.c [new file with mode: 0644]
src/tizen-device.h [new file with mode: 0644]

index 157bfac..7421ffb 100644 (file)
@@ -92,7 +92,7 @@ module_tizenaudio_policy_la_SOURCES = \
           src/stream-manager.c   src/stream-manager.h   src/stream-manager-priv.h   \
           src/stream-manager-volume.c   src/stream-manager-volume.h   src/stream-manager-volume-priv.h   \
           src/stream-manager-restriction.c   src/stream-manager-restriction-priv.h   \
-          src/device-manager.c   src/device-manager.h \
+          src/device-manager.c   src/device-manager.h   src/tizen-device.c   src/tizen-device.h   src/tizen-device-def.c  src/tizen-device-def.h  \
           src/subscribe-observer.c   src/subscribe-observer.h
 module_tizenaudio_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -L$(pulsemodlibexecdir)
 module_tizenaudio_policy_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) libhal-interface.la
index df84175..54d30b1 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          5.0.70
+Version:          5.0.71
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 3ca5831..4cd9abb 100644 (file)
@@ -37,6 +37,8 @@
 #include <pulsecore/modargs.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/shared.h>
+#include <pulsecore/dynarray.h>
+#include <pulsecore/hashmap.h>
 
 #include <vconf.h>
 #include <vconf-keys.h>
@@ -60,6 +62,9 @@
 #define DEVICE_AVAIL_COND_STR_MAX           6
 #define DEVICE_FILE_PER_TYPE_MAX            4
 #define DEVICE_FILE_STRING_MAX              4
+#define DEVICE_TYPE_STR_MAX                 20
+#define DEVICE_PROFILE_STR_MAX              5
+#define DEVICE_ROLE_STR_MAX                 15
 
 #define DEVICE_TYPE_OBJECT                  "device-types"
 #define DEVICE_FILE_OBJECT                  "device-files"
 
 #define DEVICE_TYPE_STR_MAX                 20
 
-#define DEVICE_DIRECTION_STR_NONE           "none"
-#define DEVICE_DIRECTION_STR_OUT            "out"
-#define DEVICE_DIRECTION_STR_IN             "in"
-#define DEVICE_DIRECTION_STR_BOTH           "both"
-
 /* Properties of sink/sources */
 #define DEVICE_API_BLUEZ                    "bluez"
 #define DEVICE_API_ALSA                     "alsa"
@@ -209,23 +209,10 @@ static const char* const valid_alsa_device_modargs[] = {
     NULL
 };
 
-
-
 /* A macro to ease iteration through all entries */
 #define PA_HASHMAP_FOREACH_KEY(e, h, state, key) \
     for ((state) = NULL, (e) = pa_hashmap_iterate((h), &(state), (const void**)&(key)); (e); (e) = pa_hashmap_iterate((h), &(state), (const void**)&(key)))
 
-#define PA_DEVICE(pulse_device, pdt) \
-    pdt == PA_DEVICE_TYPE_SINK ? ((pa_sink *) pulse_device) : ((pa_source *) pulse_device)
-
-#define PA_DEVICES(core, pdt) \
-    pdt == PA_DEVICE_TYPE_SINK ? (((pa_core *) core)->sinks) : (((pa_core *) core)->sources)
-
-#define MAKE_SINK(s) ((pa_sink*) (s))
-#define MAKE_SOURCE(s) ((pa_source*) (s))
-
-#define COMPOUND_STATE(d) (((dm_device_profile*)d)->playback_state | ((dm_device_profile*)d)->capture_state)
-
 #define BT_CVSD_CODEC_ID 1 // narrow-band
 #define BT_MSBC_CODEC_ID 2 // wide-band
 /*
@@ -261,17 +248,14 @@ typedef enum external_value_hdmi_type {
     device_detected_type_t is needed to distinguish detected device-types ( ex. earjack which can be out or both way)
     So If you just want to know whether detected or not, can device_detected_t as mask.
 */
-typedef enum device_detected {
-    DEVICE_NOT_DETECTED = 0x00,
-    DEVICE_DETECTED = 0x01,
-} device_detected_t;
 
 typedef enum device_detected_type {
-    DEVICE_DETECTED_BT_SCO = DEVICE_DETECTED,
-    DEVICE_DETECTED_FORWARDING = DEVICE_DETECTED,
-    DEVICE_DETECTED_HDMI = DEVICE_DETECTED,
-    DEVICE_DETECTED_AUDIO_JACK_BOTH_DIREC = DEVICE_DETECTED | 0x2,
-    DEVICE_DETECTED_AUDIO_JACK_OUT_DIREC = DEVICE_DETECTED | 0x4,
+    DEVICE_DISCONNECTED = 0x0,
+    DEVICE_CONNECTED = 0x1,
+    DEVICE_CONNECTED_AUDIO_JACK_4P = DEVICE_CONNECTED | 0x2,
+    DEVICE_CONNECTED_AUDIO_JACK_3P = DEVICE_CONNECTED | 0x4,
+    DEVICE_CONNECTED_SCO = DEVICE_CONNECTED | 0x8,
+    DEVICE_OPENED_SCO = DEVICE_CONNECTED | 0xF,
 } device_detected_type_t;
 
 typedef enum dm_device_class_type {
@@ -302,56 +286,6 @@ typedef enum {
 } device_flags_type_t;
 
 
-/************* structures for represent device items can be connected/disconnected */
-/*
-    Before beginning, There are two structure(dm_device, dm_device_profile)
-    for represent device by following reasons.
-    When bt-a2dp and bt-sco are on physically same device ,it is of course same device.
-    So those physically same device item are represended by dm_device,
-    and each profile is represented by dm_device_profile.
-*/
-
-
-/*
-    Structure to represent physicall device.
-    This is profile known data-structure, which means it can have multiple profiles ( ex. bt-a2dp and sco)
-*/
-struct dm_device {
-    uint32_t id;
-    char *type;
-    char *name;
-    const char *identifier;
-
-    /* Indicate currently activated profile */
-    uint32_t active_profile;
-    /* include profile_items(dm_device_profile) , currently has only one item except bt case*/
-    pa_idxset *profiles;
-
-    pa_device_manager *dm;
-};
-
-/*
-    Structure to represent each device profile (subtype).
-    Even if both-way device(earjack, sco..) , one device_profile.
-*/
-typedef struct dm_device_profile {
-    char *profile;
-    dm_device_direction_t direction;
-    dm_device_state_t playback_state;
-    dm_device_state_t capture_state;
-
-    /* Can get proper sink/source in hashmaps with key(=device_role) */
-    pa_hashmap *playback_devices;
-    pa_hashmap *capture_devices;
-
-    /* device belongs to */
-    dm_device *device_item;
-
-    /* creation time */
-    pa_usec_t creation_time;
-
-} dm_device_profile;
-
 /*
     Structure to save parsed information about device-file.
 */
@@ -361,33 +295,6 @@ struct device_file_map {
     pa_idxset *capture;
 };
 
-struct pa_device_manager {
-    PA_REFCNT_DECLARE;
-
-    pa_core *core;
-    pa_hook_slot *sink_put_hook_slot, *sink_state_changed_slot, *sink_unlink_hook_slot;
-    pa_hook_slot *source_put_hook_slot, *source_state_changed_slot, *source_unlink_hook_slot;
-    pa_communicator *comm;
-
-    /*
-       Idxset for save parsed information about device-type.
-       { device_type_info }
-    */
-    pa_idxset *type_infos;
-    /* For save Parsed information about device-file */
-    struct device_file_map *file_map;
-
-    /* device list */
-    pa_idxset *device_list;
-    /*
-       Hashmap for save statuses got through dbus.
-       { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
-    */
-    pa_idxset *device_status;
-    pa_dbus_connection *dbus_conn;
-    dm_device_bt_sco_status_t bt_sco_status;
-};
-
 /***************** structures for static information get from json *********/
 
 /*
@@ -425,12 +332,12 @@ struct device_type_info {
 };
 
 struct device_status_info {
-    const char *type;
-    const char *profile;
+    char *type;
+    char *profile;
+    char *name;
     /* Identify devices among same device-types (for multi-device), currently not works*/
-    const char *identifier;
-    device_detected_t detected;
-    device_detected_type_t detected_type;
+    char *system_id;
+    device_detected_type_t detected;
 };
 
 struct pulse_device_prop {
@@ -440,9 +347,39 @@ struct pulse_device_prop {
     int status;
 };
 /******************************************************************************/
+struct pa_device_manager {
+    PA_REFCNT_DECLARE;
+
+    pa_core *core;
+    pa_hook_slot *sink_put_hook_slot, *sink_state_changed_slot, *sink_unlink_hook_slot;
+    pa_hook_slot *source_put_hook_slot, *source_state_changed_slot, *source_unlink_hook_slot;
+    pa_hook_slot *comm_hook_device_connection_changed_slot, *comm_hook_device_info_changed_slot;
+    pa_communicator *comm;
+
+    /*
+       Idxset for save parsed information about device-type.
+       { device_type_info }
+    */
+    pa_idxset *type_infos;
+    /* For save Parsed information about device-file */
+    struct device_file_map *file_map;
+
+    /* device list */
+    pa_idxset *device_list;
+    /*
+       Hashmap for save statuses got through dbus.
+       { key:device_type -> value:(audio_detected_type_t or device_detected_t) }
+    */
+    pa_idxset *device_status;
+    pa_dbus_connection *dbus_conn;
+};
 
-int device_id_max_g = 1;
-uint32_t event_id_max_g = 1;
+
+struct composite_type {
+    const char *type;
+    const char *profile;
+    const char *role;
+};
 
 #ifdef HAVE_DBUS
 
@@ -453,11 +390,6 @@ static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, vo
 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
 
-static void notify_device_connection_changed(dm_device *device_item, bool connected, pa_device_manager *dm);
-static void notify_device_info_changed(dm_device *device_item, dm_device_changed_info_t changed_type, pa_device_manager *dm);
-
-static int method_call_bt_sco(DBusConnection *conn, bool onoff);
-static int method_call_bt_sco_get_property(DBusConnection *conn, bool *is_wide_band, bool *nrec);
 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
 
 enum method_handler_index {
@@ -493,130 +425,6 @@ enum signal_index {
 
 #endif
 
-static uint32_t _new_event_id() {
-    return event_id_max_g++;
-}
-
-static bool device_type_is_builtin(const char *device_type) {
-    if (!device_type)
-        return false;
-    else if (pa_streq(device_type, DEVICE_TYPE_SPEAKER))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_MIC))
-        return true;
-    else
-        return false;
-}
-
-static bool device_type_is_valid(const char *device_type) {
-    if (!device_type)
-        return false;
-    else if (pa_streq(device_type, DEVICE_TYPE_SPEAKER))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_MIC))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_AUDIO_JACK))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_BT))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_HDMI))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_FORWARDING))
-        return true;
-    else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO))
-        return true;
-    else
-        return false;
-}
-
-/* Check whether 'direction' is valid for 'device_type'
- * This is static device-type availability, not for runtime checking */
-static bool device_type_is_valid_direction(const char *device_type, const char *device_profile, dm_device_direction_t direction) {
-    if (!device_type || direction == DM_DEVICE_DIRECTION_NONE)
-        return false;
-
-    if (pa_streq(device_type, DEVICE_TYPE_SPEAKER))
-        return direction == DM_DEVICE_DIRECTION_OUT;
-    else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER))
-        return direction == DM_DEVICE_DIRECTION_OUT;
-    else if (pa_streq(device_type, DEVICE_TYPE_MIC))
-        return direction == DM_DEVICE_DIRECTION_IN;
-    else if (pa_streq(device_type, DEVICE_TYPE_AUDIO_JACK))
-        return direction == DM_DEVICE_DIRECTION_OUT || direction == DM_DEVICE_DIRECTION_BOTH;
-    else if (pa_streq(device_type, DEVICE_TYPE_BT) && pa_streq(device_profile, DEVICE_PROFILE_BT_SCO))
-        return direction == DM_DEVICE_DIRECTION_BOTH;
-    else if (pa_streq(device_type, DEVICE_TYPE_BT) && pa_streq(device_profile, DEVICE_PROFILE_BT_A2DP))
-        return direction == DM_DEVICE_DIRECTION_OUT || direction == DM_DEVICE_DIRECTION_IN;
-    else if (pa_streq(device_type, DEVICE_TYPE_HDMI))
-        return direction == DM_DEVICE_DIRECTION_OUT;
-    else if (pa_streq(device_type, DEVICE_TYPE_FORWARDING))
-        return direction == DM_DEVICE_DIRECTION_BOTH;
-    else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO))
-        return direction == DM_DEVICE_DIRECTION_BOTH || direction == DM_DEVICE_DIRECTION_OUT || direction == DM_DEVICE_DIRECTION_IN;
-    else
-        return false;
-}
-
-static const char* device_direction_to_string(dm_device_direction_t direction) {
-    if (direction <= DM_DEVICE_DIRECTION_NONE || direction > DM_DEVICE_DIRECTION_BOTH) {
-        return NULL;
-    }
-
-    if (direction == DM_DEVICE_DIRECTION_NONE)
-        return DEVICE_DIRECTION_STR_NONE;
-    else if (direction == DM_DEVICE_DIRECTION_OUT)
-        return DEVICE_DIRECTION_STR_OUT;
-    else if (direction == DM_DEVICE_DIRECTION_IN)
-        return DEVICE_DIRECTION_STR_IN;
-    else if (direction == DM_DEVICE_DIRECTION_BOTH)
-        return DEVICE_DIRECTION_STR_BOTH;
-    else
-        return NULL;
-}
-
-static bool device_role_is_valid(const char *device_role) {
-    if (!device_role)
-        return false;
-    else if (pa_streq(device_role, DEVICE_ROLE_NORMAL))
-        return true;
-    else if (pa_streq(device_role, DEVICE_ROLE_CALL_VOICE))
-        return true;
-    else if (pa_streq(device_role, DEVICE_ROLE_CALL_VIDEO))
-        return true;
-    else if (pa_streq(device_role, DEVICE_ROLE_VOIP))
-        return true;
-    else if (pa_streq(device_role, DEVICE_ROLE_LOW_LATENCY))
-        return true;
-    else if (pa_streq(device_role, DEVICE_ROLE_HIGH_LATENCY))
-        return true;
-    else if (pa_streq(device_role, DEVICE_ROLE_UHQA))
-        return true;
-    else
-        return false;
-}
-
-static dm_device_direction_t device_direction_to_int(const char *device_direction) {
-    if (!device_direction) {
-        return -1;
-    }
-
-    if (pa_streq(device_direction, DEVICE_DIRECTION_STR_NONE)) {
-        return DM_DEVICE_DIRECTION_NONE;
-    } else if (pa_streq(device_direction, DEVICE_DIRECTION_STR_OUT)) {
-        return DM_DEVICE_DIRECTION_OUT;
-    } else if (pa_streq(device_direction, DEVICE_DIRECTION_STR_IN)) {
-        return DM_DEVICE_DIRECTION_IN;
-    } else if (pa_streq(device_direction, DEVICE_DIRECTION_STR_BOTH)) {
-        return DM_DEVICE_DIRECTION_BOTH;
-    } else {
-        return -1;
-    }
-}
-
 static void type_info_free_func(struct device_type_info *type_info) {
     if (!type_info)
         return;
@@ -636,74 +444,56 @@ static void file_info_free_func(struct device_file_info *file_info) {
         pa_hashmap_free(file_info->roles);
 }
 
-static void profile_item_free_func(dm_device_profile *profile_item) {
-    if (!profile_item)
-        return;
-
-    if (profile_item->profile) {
-        pa_xfree(profile_item->profile);
+static dm_device_class_t device_string_get_class(const char *device_string) {
+    if (!device_string) {
+        return DM_DEVICE_CLASS_NONE;
     }
 
-    if (profile_item->playback_devices) {
-        pa_hashmap_free(profile_item->playback_devices);
-    }
-    if (profile_item->capture_devices) {
-        pa_hashmap_free(profile_item->capture_devices);
+    if (device_string == strstr(device_string, "alsa")) {
+        return DM_DEVICE_CLASS_ALSA;
+    } else if (device_string == strstr(device_string, "null")) {
+        return DM_DEVICE_CLASS_NULL;
+    } else if (device_string == strstr(device_string, "tizen")) {
+        return DM_DEVICE_CLASS_TIZEN;
+    } else {
+        return DM_DEVICE_CLASS_NONE;
     }
-
-    profile_item->device_item = NULL;
-
-    pa_xfree(profile_item);
 }
 
-static void device_item_free_func(dm_device *device_item) {
-    if (!device_item)
-        return;
-
-    if (device_item->type)
-        pa_xfree(device_item->type);
-    if (device_item->name)
-        pa_xfree(device_item->name);
-    if (device_item->profiles)
-        pa_idxset_free(device_item->profiles, (pa_free_cb_t)profile_item_free_func);
-
-    pa_xfree(device_item);
-}
+static const char* device_string_get_value(const char *device_string) {
+    int len;
+    const char *end_p, *value_p;
 
-static pa_proplist* pulse_device_get_proplist(void *pulse_device, pa_device_type_t pdt) {
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        return MAKE_SINK(pulse_device)->proplist;
-    else
-        return MAKE_SOURCE(pulse_device)->proplist;
-}
+    if (!device_string) {
+        return NULL;
+    }
 
-static pa_core* pulse_device_get_core(void *pulse_device, pa_device_type_t pdt) {
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        return MAKE_SINK(pulse_device)->core;
-    else
-        return MAKE_SOURCE(pulse_device)->core;
-}
+    len = strlen(device_string);
+    end_p = device_string + len -1;
 
-static char* pulse_device_get_name(void *pulse_device, pa_device_type_t pdt) {
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        return MAKE_SINK(pulse_device)->name;
-    else
-        return MAKE_SOURCE(pulse_device)->name;
+    if (!(value_p = strchr(device_string, ':'))) {
+        return NULL;
+    }
+    if (value_p < end_p) {
+        return value_p + 1;
+    } else {
+        return NULL;
+    }
 }
 
-static pa_idxset* pulse_core_get_device_list(pa_core *core, pa_device_type_t pdt) {
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        return core->sinks;
+static pa_proplist* pulse_device_get_proplist(pa_object *pdevice) {
+    if (pa_sink_isinstance(pdevice))
+        return PA_SINK(pdevice)->proplist;
     else
-        return core->sources;
+        return PA_SOURCE(pdevice)->proplist;
 }
 
-static bool pulse_device_is_alsa(pa_proplist *prop) {
+static bool pulse_device_is_alsa(pa_object *pdevice) {
     const char *api_name = NULL;
+    pa_proplist *prop;
 
-    if (!prop) {
+    if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
         return false;
-    }
 
     if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
         if (pa_streq(api_name, DEVICE_API_ALSA)) {
@@ -717,12 +507,12 @@ static bool pulse_device_is_alsa(pa_proplist *prop) {
 }
 
 
-static bool pulse_device_is_bluez(pa_proplist *prop) {
+static bool pulse_device_is_bluez(pa_object *pdevice) {
     const char *api_name = NULL;
+    pa_proplist *prop;
 
-    if (!prop) {
+    if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
         return false;
-    }
 
     if ((api_name = pa_proplist_gets(prop, PA_PROP_DEVICE_API))) {
         if (pa_streq(api_name, DEVICE_API_BLUEZ)) {
@@ -735,23 +525,25 @@ static bool pulse_device_is_bluez(pa_proplist *prop) {
     }
 }
 
-static bool pulse_device_is_tizenaudio(void *pulse_device, pa_device_type_t pdt) {
-    pa_sink *sink;
-
-    if (!pulse_device) {
+static bool pulse_device_is_tizenaudio(pa_object *pdevice) {
+    if (!pdevice)
         return false;
-    }
 
-    if (pdt == PA_DEVICE_TYPE_SOURCE) {
-        return false;
+    if (pa_sink_isinstance(pdevice)) {
+        pa_sink *sink = PA_SINK(pdevice);
+        return pa_streq(sink->module->name, "module-tizenaudio-sink");
+    } else {
+        pa_source *source = PA_SOURCE(pdevice);
+        return pa_streq(source->module->name, "module-tizenaudio-source");
     }
-
-    sink = (pa_sink *) pulse_device;
-    return pa_streq(sink->module->name, "module-tizenaudio-sink");
 }
 
-static bool pulse_device_is_usb(pa_proplist *prop) {
+static bool pulse_device_is_usb(pa_object *pdevice) {
     const char *bus_name = NULL;
+    pa_proplist *prop;
+
+    if ((prop = pulse_device_get_proplist(pdevice)) == NULL)
+        return false;
 
     if ((bus_name = pa_proplist_gets(prop, PA_PROP_DEVICE_BUS))) {
         if (pa_streq(bus_name, DEVICE_BUS_USB)) {
@@ -765,147 +557,165 @@ static bool pulse_device_is_usb(pa_proplist *prop) {
     }
 }
 
-static bool pulse_device_is_null(void *pulse_device, pa_device_type_t pdt) {
+static bool pulse_device_is_null(pa_object *pdevice) {
     pa_sink *sink;
     pa_source *source;
 
-    if (!pulse_device)
+    if (!pdevice)
         return false;
 
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        sink = (pa_sink *) pulse_device;
+    if (pa_sink_isinstance(pdevice)) {
+        sink = PA_SINK(pdevice);
         return pa_streq(sink->module->name, "module-null-sink");
     } else {
-        source = (pa_source *) pulse_device;
-
+        source = PA_SOURCE(pdevice);
         return pa_streq(source->module->name, "module-null-source");
     }
 }
 
-static const char* device_class_to_string(dm_device_class_t device_class) {
-    if (device_class == DM_DEVICE_CLASS_ALSA) {
-        return "alsa";
-    } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
-        return "tizen";
-    } else if (device_class == DM_DEVICE_CLASS_BT) {
-        return "bt";
-    } else if (device_class == DM_DEVICE_CLASS_NULL) {
-        return "null";
-    } else if (device_class == DM_DEVICE_CLASS_NONE) {
-        return "none";
-    } else {
-        return NULL;
-    }
-}
-
-static dm_device_class_t device_string_get_class(const char *device_string) {
-    if (!device_string) {
-        return DM_DEVICE_CLASS_NONE;
-    }
+static const char* pulse_device_get_device_string_removed_argument(pa_object *pdevice) {
+    static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
+    char *device_string_p = NULL;
+    char *next_p = NULL;
+    const char *params_p, *params;
+    char *end_p = NULL;
+    int len = 0, prev_len = 0;
+    pa_sink *sink;
+    pa_source *source;
 
-    if (device_string == strstr(device_string, "alsa")) {
-        return DM_DEVICE_CLASS_ALSA;
-    } else if (device_string == strstr(device_string, "null")) {
-        return DM_DEVICE_CLASS_NULL;
-    } else if (device_string == strstr(device_string, "tizen")) {
-        return DM_DEVICE_CLASS_TIZEN;
+    if (pa_sink_isinstance(pdevice)) {
+        sink = PA_SINK(pdevice);
+        params = sink->module->argument;
     } else {
-        return DM_DEVICE_CLASS_NONE;
+        source = PA_SOURCE(pdevice);
+        params = source->module->argument;
     }
-}
 
-static const char* device_string_get_value(const char *device_string) {
-    int len;
-    const char *end_p, *value_p;
+    params_p = params;
 
-    if (!device_string) {
+    if (!params) {
         return NULL;
     }
+    if (!(device_string_p = strstr(params, "device="))) {
+        return params;
+    }
 
-    len = strlen(device_string);
-    end_p = device_string + len -1;
-
-    if (!(value_p = strchr(device_string, ':'))) {
-        return NULL;
+    next_p = device_string_p;
+    while (!isblank(*next_p)) {
+        next_p++;
     }
-    if (value_p < end_p) {
-        return value_p + 1;
-    } else {
-        return NULL;
+    while (isblank(*next_p)) {
+        next_p++;
+    }
+
+    strncpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
+
+    if (device_string_p > params_p) {
+        prev_len = device_string_p - params_p;
+        len = strlen(removed_param);
+        end_p = removed_param + len;
+        *end_p = ' ';
+        end_p++;
+        strncpy(end_p, params_p, prev_len);
     }
+
+    return removed_param;
 }
 
-static dm_device_class_t pulse_device_get_class(void *pulse_device, pa_device_type_t pdt) {
-    pa_sink *sink = NULL;
-    pa_source *source = NULL;
+static dm_device_class_t pulse_device_get_class(pa_object *pdevice) {
 
-    if (!pulse_device) {
-        pa_log_error("pulse_device null");
+    if (!pdevice) {
+        pa_log_error("pdevice null");
         return DM_DEVICE_CLASS_NONE;
     }
 
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        sink = (pa_sink *) pulse_device;
-    else
-        source = (pa_source *) pulse_device;
-
-    if (pulse_device_is_null(pulse_device, pdt)) {
+    if (pulse_device_is_null(pdevice)) {
         return DM_DEVICE_CLASS_NULL;
-    } else if (pulse_device_is_alsa(pdt == PA_DEVICE_TYPE_SINK ? sink->proplist : source->proplist)) {
+    } else if (pulse_device_is_alsa(pdevice)) {
         return DM_DEVICE_CLASS_ALSA;
-    } else if (pulse_device_is_tizenaudio(pulse_device, pdt)) {
+    } else if (pulse_device_is_tizenaudio(pdevice)) {
         return DM_DEVICE_CLASS_TIZEN;
-    } else if (pulse_device_is_bluez(pdt == PA_DEVICE_TYPE_SINK ? sink->proplist : source->proplist)) {
+    } else if (pulse_device_is_bluez(pdevice)) {
         return DM_DEVICE_CLASS_BT;
     } else {
         return DM_DEVICE_CLASS_NONE;
     }
 }
 
-static const char* device_class_get_module_name(dm_device_class_t device_class, pa_device_type_t pdt) {
-    if (device_class == DM_DEVICE_CLASS_NONE) {
-        return NULL;
-    } else if (device_class == DM_DEVICE_CLASS_ALSA) {
-        return pdt == PA_DEVICE_TYPE_SINK ? "module-alsa-sink" : "module-alsa-source";
-    } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
-        return pdt == PA_DEVICE_TYPE_SINK ? "module-tizenaudio-sink" : NULL;
-    } else if (device_class == DM_DEVICE_CLASS_BT) {
-        return pdt == PA_DEVICE_TYPE_SINK ? "module-bluez5-device" : NULL;
-    } else if (device_class == DM_DEVICE_CLASS_NULL) {
-        return pdt == PA_DEVICE_TYPE_SINK ? "module-null-sink" : "module-null-source";
-    } else {
-        return NULL;
-    }
+static dm_device_direction_t pulse_device_get_direction(pa_object *pdevice) {
+    if (pa_sink_isinstance(pdevice))
+        return DM_DEVICE_DIRECTION_OUT;
+    else
+        return DM_DEVICE_DIRECTION_IN;
 }
 
-static int compare_device_profile(const char *device_profile1, const char *device_profile2) {
-    if (!device_profile1 && !device_profile2) {
-        return 0;
-    } else if (!device_profile1 || !device_profile2) {
-        return 1;
-    } else if (pa_streq(device_profile1, device_profile2)) {
-        return 0;
+static bool pulse_device_is_monitor(pa_object *pdevice) {
+    const char *device_class = NULL;
+    pa_proplist *prop;
+
+    prop = pulse_device_get_proplist(pdevice);
+
+    if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
+        if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
+            return true;
+        } else {
+            return false;
+        }
     } else {
-        return 1;
+        return false;
     }
 }
 
-static int compare_device_type(const char *device_type1, const char *device_profile1, const char *device_type2, const char *device_profile2) {
-    if (!device_type1 || !device_type2) {
+static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
+    const char *device_string_prop = NULL;
+    char *device_string_tmp;
+
+    if (!prop || !device_string) {
+        pa_log_error("Invalid Parameter");
+        return -1;
+    }
+
+    if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
+        pa_log_error("failed to get property 'device.string'");
+        return -1;
+    }
+    if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
+        pa_log_error("failed to parse device string");
+        return -1;
+    }
+
+    if (((device_string_tmp + 1) == '\0')) {
+        pa_log_error("no device string value");
         return -1;
     }
-    if (pa_streq(device_type1, device_type2)) {
-        return compare_device_profile(device_profile1, device_profile2);
+
+    *device_string = device_string_tmp + 1;
+
+    return 0;
+}
+
+static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) {
+    if (device_class == DM_DEVICE_CLASS_NONE) {
+        return NULL;
+    } else if (device_class == DM_DEVICE_CLASS_ALSA) {
+        return is_sink ? "module-alsa-sink" : "module-alsa-source";
+    } else if (device_class == DM_DEVICE_CLASS_TIZEN) {
+        return is_sink ? "module-tizenaudio-sink" : NULL;
+    } else if (device_class == DM_DEVICE_CLASS_BT) {
+        return is_sink ? "module-bluez5-device" : NULL;
+    } else if (device_class == DM_DEVICE_CLASS_NULL) {
+        return is_sink ? "module-null-sink" : "module-null-source";
+    } else {
+        return NULL;
     }
-    return 1;
 }
 
-static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *device_type, const char *device_profile) {
+static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type, const char *device_profile) {
     struct device_type_info *type_info;
     uint32_t type_idx;
 
     PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
-        if (!compare_device_type(type_info->type, type_info->profile, device_type, device_profile)) {
+        if (device_type_is_equal(type_info->type, type_info->profile, type, device_profile)) {
             return type_info;
         }
     }
@@ -913,32 +723,11 @@ static struct device_type_info* _device_manager_get_type_info(pa_idxset *type_in
     return NULL;
 }
 
-static struct device_status_info* _device_manager_get_status_info(pa_idxset *status_infos, const char *device_type, const char *device_profile, const char *identifier) {
-    struct device_status_info *status_info;
-    uint32_t status_idx;
-
-    PA_IDXSET_FOREACH(status_info, status_infos, status_idx) {
-        if (!compare_device_type(status_info->type, status_info->profile, device_type, device_profile)) {
-            if (!status_info->identifier && !identifier) {
-                return status_info;
-            } else if (!status_info->identifier || !identifier) {
-                continue;
-            } else if (pa_streq(status_info->identifier, identifier)) {
-                return status_info;
-            } else {
-                continue;
-            }
-        }
-    }
-
-    return NULL;
-}
-
 static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_infos, const char *device_string) {
     struct device_file_info *file_info;
     uint32_t file_idx;
-    if (!file_infos)
-        return NULL;
+
+    pa_assert(file_infos);
 
     PA_IDXSET_FOREACH(file_info, file_infos, file_idx) {
         if (file_info->device_string) {
@@ -951,251 +740,218 @@ static struct device_file_info* _device_manager_get_file_info(pa_idxset *file_in
     return NULL;
 }
 
-static dm_device* _device_manager_get_device(pa_idxset *device_list, const char *device_type) {
-    dm_device *device_item;
-    uint32_t device_idx;
-
-    if (!device_list || !device_type)
-        return NULL;
+static struct device_status_info* _device_status_new(const char *type, const char *profile,
+        const char *name, const char *system_id) {
+    struct device_status_info *status_info;
 
-    PA_IDXSET_FOREACH(device_item, device_list, device_idx) {
-        if (pa_streq(device_item->type, device_type)) {
-            return device_item;
-        }
-    }
+    status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
+    status_info->type = pa_xstrdup(type);
+    status_info->profile = pa_xstrdup(profile);
+    status_info->name = pa_xstrdup(name);
+    status_info->system_id = pa_xstrdup(system_id);
+    status_info->detected = DEVICE_DISCONNECTED;
 
-    return NULL;
+    return status_info;
 }
 
-static dm_device* _device_manager_get_device_with_id(pa_idxset *device_list, uint32_t id) {
-    dm_device *device_item;
-    uint32_t idx;
-
-    pa_assert(device_list);
+static void _device_status_free(struct device_status_info *status_info) {
+    if (!status_info)
+        return ;
 
-    PA_IDXSET_FOREACH(device_item, device_list, idx) {
-        if (device_item->id == id) {
-            return device_item;
-        }
-    }
-    return NULL;
+    pa_xfree(status_info->type);
+    pa_xfree(status_info->profile);
+    pa_xfree(status_info->name);
+    pa_xfree(status_info->system_id);
+    pa_xfree(status_info);
 }
 
-static char* get_playback_list_str(pa_hashmap *playback_devices) {
-    pa_sink *sink = NULL;
-    void *state = NULL;
-    const char *role;
-    pa_strbuf *buf;
+static struct device_status_info* _get_device_status(pa_device_manager *manager, const char *type,
+        const char *device_profile, const char *system_id) {
+    struct device_status_info *status_info = NULL;
+    uint32_t status_idx;
 
-    if (!playback_devices || !pa_hashmap_size(playback_devices))
-        return NULL;
+    pa_assert(manager);
+    pa_assert(manager->device_status);
 
-    buf = pa_strbuf_new();
-    pa_strbuf_printf(buf, "    Playback device list\n");
-    PA_HASHMAP_FOREACH_KEY(sink, playback_devices, state, role)
-        pa_strbuf_printf(buf, "        %-13s -> %s\n", role, sink->name);
+    PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
+        if (device_type_is_equal(status_info->type, status_info->profile, type, device_profile)) {
+            if (device_type_is_avail_multi_device(type)) {
+                /* if system_id is null, just compare type */
+                if (system_id == NULL)
+                    return status_info;
+                else if (status_info->system_id == NULL)
+                    continue;
+                else if (pa_streq(status_info->system_id, system_id))
+                    return status_info;
+                else
+                    continue;
+            } else {
+                return status_info;
+            }
+        }
+    }
 
-    return pa_strbuf_tostring_free(buf);
+    return NULL;
 }
 
-static char* get_capture_list_str(pa_hashmap *capture_devices) {
-    pa_source *source = NULL;
-    void *state = NULL;
-    const char *role;
-    pa_strbuf *buf;
-
-    if (!capture_devices || !pa_hashmap_size(capture_devices))
-        return NULL;
-
-    buf = pa_strbuf_new();
-    pa_strbuf_printf(buf, "    Capture device list\n");
-    PA_HASHMAP_FOREACH_KEY(source, capture_devices, state, role)
-        pa_strbuf_printf(buf, "        %-13s -> %s\n", role, source->name);
-
-    return pa_strbuf_tostring_free(buf);
-}
+static const char* _file_infos_get_param(pa_idxset *file_infos, const char *device_string, const char *role) {
+    struct device_file_info *file_info;
+    const char *params;
 
-/* Returned string must be freed */
-static char* get_device_profile_info_str(dm_device_profile *profile_item) {
-    pa_strbuf *buf;
-    char *playback_str, *capture_str;
-    if (!profile_item)
+    if (!(file_info = _device_manager_get_file_info(file_infos, device_string))) {
+        pa_log_error("No file map for '%s'", device_string);
         return NULL;
+    }
 
-    buf = pa_strbuf_new();
-    pa_strbuf_printf(buf, "    Profile      : %s\n", pa_strna(profile_item->profile));
-    pa_strbuf_printf(buf, "    Direction    : %s\n", device_direction_to_string(profile_item->direction));
-    pa_strbuf_printf(buf, "    Is activated : %s\n", pa_yes_no(COMPOUND_STATE(profile_item) == DM_DEVICE_STATE_ACTIVATED));
-    playback_str = get_playback_list_str(profile_item->playback_devices);
-    capture_str = get_capture_list_str(profile_item->capture_devices);
-
-    if (playback_str)
-        pa_strbuf_puts(buf, playback_str);
-    if (capture_str)
-        pa_strbuf_puts(buf, capture_str);
-
-    pa_xfree(playback_str);
-    pa_xfree(capture_str);
+    if (!(params = pa_hashmap_get(file_info->roles, role)))
+        pa_log_error("No params for '%s:%s'", device_string, role);
 
-    return pa_strbuf_tostring_free(buf);
+    return params;
 }
 
-static char* get_device_info_str(dm_device *device_item) {
-    pa_strbuf *buf;
-    dm_device_profile *profile_item = NULL;
-    uint32_t device_idx = 0;
-    char *profile_info;
-
-    if (!device_item || !device_item->profiles)
-        return NULL;
-
-    buf = pa_strbuf_new();
-    pa_strbuf_printf(buf, "[Device #%u]\n", device_item->id);
-    pa_strbuf_printf(buf, "  ID             : %u\n", device_item->id);
-    pa_strbuf_printf(buf, "  Type           : %s\n", device_item->type);
-    pa_strbuf_printf(buf, "  Name           : %s\n", device_item->name);
-    pa_strbuf_printf(buf, "  Active Profile : %u\n", device_item->active_profile);
-    PA_IDXSET_FOREACH(profile_item, device_item->profiles, device_idx) {
-        pa_strbuf_printf(buf, "  (Profile #%u)\n", device_idx);
-        profile_info = get_device_profile_info_str(profile_item);
-        if (profile_info)
-            pa_strbuf_puts(buf, profile_info);
-        pa_xfree(profile_info);
-    }
-
-    return pa_strbuf_tostring_free(buf);
-}
+static device_detected_type_t _device_get_detected(pa_device_manager *manager, const char *type, const char *device_profile,
+        const char *system_id) {
+    struct device_status_info *status_info;
 
-static char* get_device_list_str(pa_device_manager *dm) {
-    dm_device *device_item = NULL;
-    uint32_t device_idx = 0;
-    pa_strbuf *buf;
-    char *device_info;
+    pa_assert(manager);
+    pa_assert(manager->device_status);
+    pa_assert(type);
 
-    if (!dm || !dm->device_list)
-        return NULL;
+    if (!device_type_is_need_detect(type, device_profile))
+        return DEVICE_CONNECTED;
 
-    buf = pa_strbuf_new();
-    pa_strbuf_printf(buf, "=========== Device List ================\n");
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        device_info = get_device_info_str(device_item);
-        if (device_info)
-            pa_strbuf_puts(buf, device_info);
-        pa_xfree(device_info);
+    status_info = _get_device_status(manager, type, device_profile, system_id);
+    if (!status_info) {
+        pa_log_info("No status info for type(%s) profile(%s) system_id(%s)",
+                type, pa_strempty(device_profile), pa_strempty(system_id));
+        return DEVICE_DISCONNECTED;
     }
-    pa_strbuf_printf(buf, "========================================\n");
-
-    return pa_strbuf_tostring_free(buf);
-}
-
-static void dump_device_info(dm_device *device_item, pa_log_level_t log_level) {
-    char *info;
 
-    if (!device_item)
-        return;
+    pa_log_debug("Get device detected, type(%s) profile(%s) system_id(%s) : %s(%d)",
+            type, pa_strempty(device_profile), pa_strempty(system_id),
+             (status_info->detected & DEVICE_CONNECTED) ? "Connected" : "Disconnected", status_info->detected);
 
-    if ((info = get_device_info_str(device_item))) {
-        pa_logl(log_level, "%s", info);
-        pa_xfree(info);
-    }
+    return status_info->detected;
 }
 
-static void dump_device_list_info(pa_device_manager *dm, pa_log_level_t log_level) {
-    char *info;
+static void _device_set_detected(pa_device_manager *manager, const char *type, const char *device_profile,
+        const char *name, const char *system_id, device_detected_type_t detected_type) {
+    struct device_status_info *status_info;
 
-    if (!dm || !dm->device_list)
-        return;
+    pa_assert(manager);
+    pa_assert(manager->device_status);
+    pa_assert(type);
 
-    if ((info = get_device_list_str(dm))) {
-        pa_logl(log_level, "%s", info);
-        pa_xfree(info);
-    }
-}
+    if (!device_type_is_need_detect(type, device_profile))
+        return ;
 
-static bool pulse_device_class_is_sound(pa_proplist *prop) {
-    const char *device_class = NULL;
+    pa_log_info("Set device detected, type(%s) profile(%s) system_id(%s) -> %s(%d)",
+            type, pa_strempty(device_profile), pa_strempty(system_id),
+            (detected_type & DEVICE_CONNECTED) ? "Connected" : "Disconnected", detected_type);
 
-    if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
-        if (device_class && pa_streq(device_class, DEVICE_CLASS_SOUND)) {
-            return true;
-        } else {
-            return false;
+    if (detected_type & DEVICE_CONNECTED) {
+        status_info = _get_device_status(manager, type, device_profile, system_id);
+        if (!status_info) {
+            status_info = _device_status_new(type, device_profile, name, system_id);
+            pa_idxset_put(manager->device_status, status_info, NULL);
         }
+        status_info->detected = detected_type;
     } else {
-        return false;
+        status_info = _get_device_status(manager, type, device_profile, system_id);
+        if (status_info) {
+            pa_idxset_remove_by_data(manager->device_status, status_info, NULL);
+            _device_status_free(status_info);
+        }
     }
 }
 
-static bool pulse_device_class_is_monitor(pa_proplist *prop) {
-    const char *device_class = NULL;
+/* return system_id of sco connected/opened bt device */
+static int _device_get_detected_sco(pa_device_manager *manager, device_detected_type_t detected,
+        char **system_id, char **name) {
+    struct device_status_info *status_info;
+    uint32_t status_idx;
 
-    if (!prop) {
-        return false;
-    }
+    pa_assert(manager);
+    pa_assert(manager->device_status);
 
-    if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) {
-        if (device_class && pa_streq(device_class, DEVICE_CLASS_MONITOR)) {
-            return true;
-        } else {
-            return false;
-        }
-    } else {
-        return false;
+    if (detected != DEVICE_CONNECTED_SCO && detected != DEVICE_OPENED_SCO) {
+        pa_log_warn("Invalid detected type for sco");
+        return -1;
     }
-}
-static void* pulse_device_get_opposite_sibling_device(void *pulse_device, pa_device_type_t pdt) {
-    const char *sysfs_path, *sysfs_path_tmp;
-    uint32_t device_idx;
-    void *pulse_device_tmp;
-    pa_core *core;
 
-    pa_assert(pulse_device);
-
-    if (!(sysfs_path = pa_proplist_gets(pulse_device_get_proplist(pulse_device, pdt), "sysfs.path"))) {
-        pa_log_warn("No sysfs.path for '%s'", pulse_device_get_name(pulse_device, pdt));
-        return NULL;
+    PA_IDXSET_FOREACH(status_info, manager->device_status, status_idx) {
+        if (device_type_is_equal(status_info->type, status_info->profile, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO)) {
+            if (status_info->detected == detected) {
+                if (system_id)
+                    *system_id = status_info->system_id;
+                if (name)
+                    *name = status_info->name;
+                return 0;
+            }
+        }
     }
 
-    core = pulse_device_get_core(pulse_device, pdt);
+    return -1;
+}
 
-    PA_IDXSET_FOREACH(pulse_device_tmp, pulse_core_get_device_list(core, !pdt), device_idx) {
-        if (!pulse_device_class_is_sound(pulse_device_get_proplist(pulse_device_tmp, !pdt)))
-            continue;
-        sysfs_path_tmp = pa_proplist_gets(pulse_device_get_proplist(pulse_device_tmp, !pdt), "sysfs.path");
-        if (sysfs_path_tmp && pa_streq(sysfs_path_tmp, sysfs_path)) {
-            return pulse_device_tmp;
+static pa_tz_device* _device_list_get_device(pa_device_manager *manager, const char *type, const char *system_id) {
+    pa_tz_device *device;
+    uint32_t idx;
+    char *_type, *_system_id;
+
+    pa_assert(manager);
+    pa_assert(manager->device_list);
+    pa_assert(type);
+
+    PA_IDXSET_FOREACH(device, manager->device_list, idx) {
+        _type = pa_tz_device_get_type(device);
+        _system_id = pa_tz_device_get_system_id(device);
+        if (pa_streq(_type, type)) {
+            if (device_type_is_avail_multi_device(type)) {
+                if (system_id == NULL)
+                    return device;
+                else if (_system_id == NULL)
+                    continue;
+                else if (pa_streq(_system_id, system_id))
+                    return device;
+                else
+                    continue;
+            } else {
+                return device;
+            }
         }
     }
 
     return NULL;
 }
 
-static int pulse_device_get_alsa_device_string(pa_proplist *prop, char **device_string) {
-    const char *device_string_prop = NULL;
-    char *device_string_tmp;
 
-    if (!prop || !device_string) {
-        pa_log_error("Invalid Parameter");
-        return -1;
-    }
+static pa_tz_device* _device_list_get_device_with_id(pa_device_manager *manager, uint32_t id) {
+    pa_tz_device *device;
+    uint32_t idx;
 
-    if (!(device_string_prop = pa_proplist_gets(prop, "device.string"))) {
-        pa_log_error("failed to get property 'device.string'");
-        return -1;
-    }
-    if (!(device_string_tmp = strchr(device_string_prop, ':'))) {
-        pa_log_error("failed to parse device string");
-        return -1;
-    }
+    pa_assert(manager);
+    pa_assert(manager->device_list);
 
-    if (((device_string_tmp + 1) == '\0')) {
-        pa_log_error("no device string value");
-        return -1;
+    PA_IDXSET_FOREACH(device, manager->device_list, idx) {
+        if (pa_tz_device_get_id(device) == id) {
+            return device;
+        }
     }
+    return NULL;
+}
 
-    *device_string = device_string_tmp + 1;
+static void dump_device_list_info(pa_device_manager *dm, pa_log_level_t log_level) {
+    pa_tz_device *device;
+    uint32_t device_idx;
 
-    return 0;
+    if (!dm || !dm->device_list)
+        return;
+
+    pa_logl(log_level, "=========== Device List ================\n");
+    PA_IDXSET_FOREACH(device, dm->device_list, device_idx)
+        pa_tz_device_dump_info(device, log_level);
+    pa_logl(log_level, "========================================\n");
 }
 
 static const char* build_params_to_load_device(const char *device_string, const char *params, dm_device_class_t device_class) {
@@ -1228,93 +984,45 @@ static const char* build_params_to_load_device(const char *device_string, const
     return (const char*) args;
 }
 
-static const char* pulse_device_get_device_string_removed_argument(void *pulse_device, pa_device_type_t pdt) {
-    static char removed_param[DEVICE_PARAM_STRING_MAX] = {0,};
-    char *device_string_p = NULL;
-    char *next_p = NULL;
-    const char *params_p, *params;
-    char *end_p = NULL;
-    int len = 0, prev_len = 0;
-    pa_sink *sink;
-    pa_source *source;
+static bool device_params_is_equal(const char *params1, const char *params2) {
+    const char *key = NULL;
+    const char *value1, *value2;
+    pa_modargs *modargs1, *modargs2;
+    void *state = NULL;
+    bool equal = true;
 
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        sink = (pa_sink *) pulse_device;
-    else
-        source = (pa_source *) pulse_device;
+    if (!params1 && !params2)
+        return true;
+    if (!params1 || !params2)
+        return false;
 
-    params = pdt == PA_DEVICE_TYPE_SINK ? sink->module->argument : source->module->argument;
-    params_p = params;
+    modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
+    modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
 
-    if (!params) {
-        return NULL;
-    }
-    if (!(device_string_p = strstr(params, "device="))) {
-        return params;
+    if (!modargs1 || !modargs2) {
+        equal = false;
+        goto finish;
     }
 
-    next_p = device_string_p;
-    while (!isblank(*next_p)) {
-        next_p++;
-    }
-    while (isblank(*next_p)) {
-        next_p++;
-    }
-
-    strncpy(removed_param, next_p, DEVICE_PARAM_STRING_MAX);
-
-    if (device_string_p > params_p) {
-        prev_len = device_string_p - params_p;
-        len = strlen(removed_param);
-        end_p = removed_param + len;
-        *end_p = ' ';
-        end_p++;
-        strncpy(end_p, params_p, prev_len);
-    }
-
-    return removed_param;
-}
-
-
-static int compare_device_params(const char *params1, const char *params2) {
-    const char *key = NULL;
-    const char *value1, *value2;
-    pa_modargs *modargs1, *modargs2;
-    void *state = NULL;
-    int ret = 0;
-
-    if (!params1 && !params2)
-        return 0;
-    if (!params1 || !params2)
-        return -1;
-
-    modargs1 = pa_modargs_new(params1, valid_alsa_device_modargs);
-    modargs2 = pa_modargs_new(params2, valid_alsa_device_modargs);
-
-    if (!modargs1 || !modargs2) {
-        ret = 1;
-        goto end;
-    }
-
-    for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
-        value1 = pa_modargs_get_value(modargs1, key, NULL);
-        value2 = pa_modargs_get_value(modargs2, key, NULL);
-        if (!value1 || !value2 || !pa_streq(value1, value2)) {
-            ret = 1;
-            goto end;
-        }
+    for (state = NULL, key = pa_modargs_iterate(modargs1, &state); key; key = pa_modargs_iterate(modargs1, &state)) {
+        value1 = pa_modargs_get_value(modargs1, key, NULL);
+        value2 = pa_modargs_get_value(modargs2, key, NULL);
+        if (!value1 || !value2 || !pa_streq(value1, value2)) {
+            equal = false;
+            goto finish;
+        }
     }
 
     for (state = NULL, key = pa_modargs_iterate(modargs2, &state); key; key = pa_modargs_iterate(modargs2, &state)) {
         value1 = pa_modargs_get_value(modargs1, key, NULL);
         value2 = pa_modargs_get_value(modargs2, key, NULL);
         if (!value1 || !value2 || !pa_streq(value1, value2)) {
-            ret = 1;
-            goto end;
+            equal = false;
+            goto finish;
         }
     }
 
-end:
+finish:
 
     if (modargs1)
         pa_modargs_free(modargs1);
@@ -1322,20 +1030,22 @@ end:
         pa_modargs_free(modargs2);
 
 
-    return ret;
+    return equal;
 }
 
-static int compare_device_params_with_module_args(void *pulse_device, pa_device_type_t pdt, const char *params) {
+static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) {
     const char *removed_module_args;
     const char *module_args;
     pa_sink *sink;
     pa_source *source;
 
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        sink = (pa_sink *) pulse_device;
+    pa_assert(pdevice);
+
+    if (pa_sink_isinstance(pdevice)) {
+        sink = PA_SINK(pdevice);
         module_args = sink->module->argument;
     } else {
-        source = (pa_source *) pulse_device;
+        source = PA_SOURCE(pdevice);
         module_args = source->module->argument;
     }
 
@@ -1344,31 +1054,23 @@ static int compare_device_params_with_module_args(void *pulse_device, pa_device_
     if (!params || !module_args)
         return -1;
 
-    removed_module_args = pulse_device_get_device_string_removed_argument(pulse_device, pdt);
-    return compare_device_params(params, removed_module_args);
+    removed_module_args = pulse_device_get_device_string_removed_argument(pdevice);
+    return device_params_is_equal(params, removed_module_args);
 }
 
-static const char* pulse_device_get_device_string(void *pulse_device, pa_device_type_t pdt) {
+static const char* pulse_device_get_device_string(pa_object *pdevice) {
     dm_device_class_t device_class;
     static char device_string[DEVICE_STR_MAX] = {0,};
     char *device_string_val = NULL;
-    pa_sink *sink;
-    pa_source *source;
-
-    if (!pulse_device) {
-        pa_log_error("pulse_device null");
-        return NULL;
-    }
+    pa_proplist *prop;
 
-    device_class = pulse_device_get_class(pulse_device, pdt);
+    pa_assert(pdevice);
 
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        sink = (pa_sink *) pulse_device;
-    else
-        source = (pa_source *) pulse_device;
+    device_class = pulse_device_get_class(pdevice);
+    prop = pulse_device_get_proplist(pdevice);
 
     if (device_class == DM_DEVICE_CLASS_ALSA) {
-        if (pulse_device_get_alsa_device_string(pdt == PA_DEVICE_TYPE_SINK ? sink->proplist : source->proplist, &device_string_val) < 0)
+        if (pulse_device_get_alsa_device_string(prop, &device_string_val) < 0)
             return NULL;
         snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_string_val);
         return device_string;
@@ -1383,1446 +1085,971 @@ static const char* pulse_device_get_device_string(void *pulse_device, pa_device_
     }
 }
 
-/*  pulse_device is sink or source */
-static bool pulse_device_same_device_string(void *pulse_device, pa_device_type_t pdt, const char *device_string) {
-    const char *pulse_device_string;
+/*  pdevice is sink or source */
+static bool pulse_device_same_device_string(pa_object *pdevice, const char *device_string) {
+    const char *_device_string;
 
-    if (!pulse_device || !device_string) {
-        return false;
-    }
+    pa_assert(pdevice);
+    pa_assert(device_string);
 
-    if (!(pulse_device_string = pulse_device_get_device_string(pulse_device, pdt))) {
+    if (!(_device_string = pulse_device_get_device_string(pdevice)))
         return false;
-    }
 
-    return pa_streq(pulse_device_string, device_string);
+    return pa_streq(_device_string, device_string);
 }
 
-static int get_profile_priority(const char *device_profile) {
-    if (!device_profile) {
-        return 0;
-    } else if (pa_streq(device_profile,  DEVICE_PROFILE_BT_A2DP)) {
-        return 1;
-    } else if (pa_streq(device_profile,  DEVICE_PROFILE_BT_SCO)) {
-        return 2;
-    } else {
-        return -1;
-    }
-}
+static const char* device_type_info_get_role(struct device_type_info *type_info, bool is_playback, const char *device_string) {
+    pa_hashmap *pcm_devices;
+    void *state;
+    const char *role, *_device_string;
+    dm_device_direction_t direction;
 
-static int compare_profile_priority(const char *device_profile1,  const char *device_profile2) {
-    int priority1, priority2;
+    pa_assert(type_info);
+    pa_assert(device_string);
 
-    priority1 = get_profile_priority(device_profile1);
-    priority2 = get_profile_priority(device_profile2);
+    direction = device_type_get_static_direction(type_info->type, type_info->profile);
+    if (direction == DM_DEVICE_DIRECTION_NONE) {
+        pa_log_debug("Not static direction");
+        return NULL;
+    }
 
-    if (priority1 > priority2) {
-        return 1;
-    } else if (priority1 == priority2) {
-        return 0;
+    if (is_playback) {
+        if (direction == DM_DEVICE_DIRECTION_IN) {
+            pa_log_debug("Invalid direction");
+            return NULL;
+        }
+        pcm_devices = type_info->playback_devices;
     } else {
-        return -1;
+        if (direction == DM_DEVICE_DIRECTION_OUT) {
+            pa_log_debug("Invalid direction");
+            return NULL;
+        }
+        pcm_devices = type_info->capture_devices;
     }
-}
 
-static dm_device* _device_item_set_active_profile_auto(dm_device *device_item) {
-    dm_device_profile *profile_item = NULL, *prev_profile_item = NULL;
-    uint32_t idx, prev_active_profile;
-    unsigned int device_size;
-
-    if (!device_item || !device_item->profiles) {
-        pa_log_error("Invalid Parameter");
+    if (!pcm_devices) {
+        pa_log_warn("No %s pcm devices for %s %s", is_playback ? "playback" : "capture",
+                type_info->type, pa_strempty(type_info->profile));
         return NULL;
     }
 
-    prev_active_profile = device_item->active_profile;
-
-    device_size = pa_idxset_size(device_item->profiles);
-    if (device_size == 1) {
-        pa_idxset_first(device_item->profiles,  &idx);
-        device_item->active_profile = idx;
-    } else if (device_size == 0) {
-        device_item->active_profile = PA_INVALID_INDEX;
-        return device_item;
-    } else {
-        PA_IDXSET_FOREACH(profile_item, device_item->profiles, idx) {
-            if (prev_profile_item) {
-                if (compare_profile_priority(profile_item->profile, prev_profile_item->profile) > 0) {
-                    device_item->active_profile = idx;
-                }
-            }
-            prev_profile_item = profile_item;
+    PA_HASHMAP_FOREACH_KEY(_device_string, pcm_devices, state, role) {
+        if (pa_streq(_device_string, device_string)) {
+            return role;
         }
     }
 
-    /* notify direction changed, if only new added profile is active */
-    if ((prev_active_profile != PA_INVALID_INDEX) && (prev_active_profile != device_item->active_profile)) {
-        pa_log_debug("%s's active profile : %u", device_item->name, device_item->active_profile);
-        notify_device_info_changed(device_item, DM_DEVICE_CHANGED_INFO_IO_DIRECTION, device_item->dm);
-    }
-
-    return device_item;
+    return NULL;
 }
 
-static dm_device* _device_item_add_profile(dm_device *device_item, dm_device_profile *profile_item, uint32_t *idx, pa_device_manager *dm) {
-    uint32_t profile_idx;
+pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager *dm) {
+    pa_dynarray *ctypes;
+    struct composite_type *ctype;
+    struct device_type_info *type_info;
+    const char *device_string, *role;
+    uint32_t type_idx;
+    pa_device_type_t pdt;
 
-    pa_assert(device_item);
-    pa_assert(device_item->profiles);
-    pa_assert(profile_item);
-    pa_assert(dm);
+    pa_assert(pdevice);
+
+    if (pulse_device_is_monitor(pdevice))
+        return NULL;
+    if (pulse_device_is_usb(pdevice))
+        return NULL;
+    if (pulse_device_is_bluez(pdevice))
+        return NULL;
 
-    pa_idxset_put(device_item->profiles, profile_item, &profile_idx);
-    _device_item_set_active_profile_auto(device_item);
-    profile_item->device_item = device_item;
+    ctypes = pa_dynarray_new(pa_xfree);
 
-    return device_item;
-}
+    if (pa_sink_isinstance(pdevice))
+        pdt = PA_DEVICE_TYPE_SINK;
+    else
+        pdt = PA_DEVICE_TYPE_SOURCE;
+
+    PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
+        device_string = pulse_device_get_device_string(pdevice);
+        role = device_type_info_get_role(type_info, pdt, device_string);
+        /* Found type_info which is matching with pulse_device */
+        if (role) {
+            ctype = pa_xmalloc0(sizeof(struct composite_type));
+            ctype->type = type_info->type;
+            ctype->profile = type_info->profile;
+            ctype->role = role;
+            pa_dynarray_append(ctypes, ctype);
+        }
+    }
 
+    if (pa_dynarray_size(ctypes) == 0) {
+        pa_dynarray_free(ctypes);
+        ctypes = NULL;
+    }
 
-static int _device_list_add_device(pa_idxset *device_list, dm_device *device_item, pa_device_manager *dm) {
-    pa_assert(device_list);
-    pa_assert(device_item);
+    return ctypes;
+}
 
-    if (pa_idxset_put(device_list, device_item, NULL) < 0)
-        return -1;
+static const char* pulse_device_get_device_name(pa_object *pdevice, const char *type) {
+    pa_proplist *prop;
 
-    pa_log_debug("Notify Device connected");
+    pa_assert(pdevice);
+    pa_assert(device_type_is_valid(type));
 
-    return 0;
+    prop = pulse_device_get_proplist(pdevice);
+
+    if (pa_streq(type, DEVICE_TYPE_USB_AUDIO))
+        return pa_proplist_gets(prop, "udev.id");
+    else if (pa_streq(type, DEVICE_TYPE_BT))
+        return pa_proplist_gets(prop, "bluez.alias");
+    else
+        return NULL;
 }
 
+static void pulse_device_set_use_internal_codec(pa_object *pdevice, bool use_internal_codec) {
+    pa_assert(pdevice);
 
-static int _device_list_remove_device(pa_idxset *device_list, dm_device *device_item, pa_device_manager *dm) {
-    pa_assert(device_list);
-    pa_assert(device_item);
+    if (pa_sink_isinstance(pdevice)) {
+        pa_sink *sink = PA_SINK(pdevice);
+        sink->use_internal_codec = use_internal_codec;
+    } else {
+        pa_source *source = PA_SOURCE(pdevice);
+        source->use_internal_codec = use_internal_codec;
+    }
+}
 
-    if (!pa_idxset_remove_by_data(device_list, device_item, NULL))
-        return -1;
+/* Get system_id of physical device, if external device */
+static const char* pulse_device_get_system_id(pa_object *pdevice) {
+    pa_proplist *prop;
 
-    return 0;
+    prop = pulse_device_get_proplist(pdevice);
+    if (pulse_device_is_usb(pdevice))
+        return pa_proplist_gets(prop, "sysfs.path");
+    else if (pulse_device_is_bluez(pdevice))
+        return pa_proplist_gets(prop, "bluez.path");
+    else
+        return NULL;
 }
 
-static pa_sink* _device_profile_get_sink(dm_device_profile *profile_item, const char *role) {
+static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm,  const char *type,  const char *device_profile,  const char *role) {
+    pa_tz_device *device;
     pa_sink *sink;
 
-    if (!profile_item || !role || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
+    if (!type || !role) {
+        pa_log_warn("Argument for set_default_sink invalid");
+        return NULL;
+    }
+
+    if (!(device = _device_list_get_device(dm, type, NULL))) {
+        pa_log_warn("cannot get device item for %s", type);
         return NULL;
     }
 
-    if (!profile_item->playback_devices) {
-        pa_log_error("No playback devices");
+    if (!(sink = pa_tz_device_get_sink(device, role))) {
+        pa_log_warn("cannot get sink for %s", role);
         return NULL;
     }
 
-    sink = pa_hashmap_get(profile_item->playback_devices, role);
+    sink = pa_namereg_set_default_sink(dm->core, sink);
     return sink;
 }
 
-static pa_source* _device_profile_get_source(dm_device_profile *profile_item, const char *role) {
+static pa_source* _device_manager_set_default_source(pa_device_manager *dm,  const char *type,  const char *device_profile,  const char *role) {
+    pa_tz_device *device;
     pa_source *source;
 
-    if (!profile_item || !role || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
+    if (!type || !role) {
+        pa_log_warn("Argument for set_default_source invalid");
+        return NULL;
+    }
+
+    if (!(device = _device_list_get_device(dm, type, NULL))) {
+        pa_log_warn("cannot get device item for %s", type);
         return NULL;
     }
 
-    if (!profile_item->capture_devices) {
-        pa_log_error("No capture devices");
+    if (!(source = pa_tz_device_get_source(device, role))) {
+        pa_log_warn("cannot get source for %s", role);
         return NULL;
     }
 
-    source = pa_hashmap_get(profile_item->capture_devices, role);
+    source = pa_namereg_set_default_source(dm->core, source);
     return source;
 }
 
-static dm_device* create_device_item(const char *device_type, const char *name, dm_device_profile *profile_item, pa_device_manager *dm) {
-    dm_device *device_item = NULL;
-    pa_sink *sink = NULL;
-    pa_source *source = NULL;
-
-    pa_assert(device_type);
-    pa_assert(profile_item);
+static void handle_usb_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
+    const char *name, *system_id;
+    dm_device_direction_t direction;
+    pa_tz_device *device;
 
-    pa_log_info("Create device item for %s", device_type);
+    pa_assert(pdevice);
+    pa_assert(manager);
 
-    device_item = (dm_device *)pa_xmalloc(sizeof(dm_device));
-    device_item->id = device_id_max_g++;
-    device_item->type = strdup(device_type);
-    device_item->active_profile = PA_INVALID_INDEX;
-    device_item->profiles = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-    device_item->dm = dm;
+    pa_log_info("Handle usb pulse device");
 
-    if (name) {
-        device_item->name = strdup(name);
-    } else {
-        device_item->name = strdup(device_type);
-    }
+    system_id = pulse_device_get_system_id(pdevice);
+    direction = pulse_device_get_direction(pdevice);
 
-    _device_item_add_profile(device_item, profile_item, NULL, dm);
-    _device_list_add_device(dm->device_list, device_item, dm);
+    if (is_loaded) {
+        pa_tz_device_new_data data;
 
-    // just for external device
-    if ((sink = _device_profile_get_sink(profile_item, DEVICE_ROLE_NORMAL)))
-        sink->device_item = device_item;
-    if ((source = _device_profile_get_source(profile_item, DEVICE_ROLE_NORMAL)))
-        source->device_item = device_item;
+        name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_USB_AUDIO);
 
-    notify_device_connection_changed(device_item, true, dm);
+        pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, NULL);
+        pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_USB_AUDIO);
+        pa_tz_device_new_data_set_name(&data, name);
+        pa_tz_device_new_data_set_direction(&data, direction);
+        pa_tz_device_new_data_set_system_id(&data, system_id);
+        pa_tz_device_new_data_set_use_internal_codec(&data, false);
+        if (direction == DM_DEVICE_DIRECTION_OUT)
+            pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
+        else
+            pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
 
-    return device_item;
+        pa_tz_device_new(&data);
+        pa_tz_device_new_data_done(&data);
+    } else {
+        if (!(device = _device_list_get_device(manager, DEVICE_TYPE_USB_AUDIO, system_id)))
+            pa_log_warn("Can't get usb device for %s", system_id);
+        else
+            pa_tz_device_free(device);
+    }
 }
 
-static void destroy_device_item(dm_device *device_item, pa_device_manager *dm) {
-    if (!device_item) {
-        return;
-    }
+static void handle_bt_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
+    dm_device_direction_t direction;
+    pa_tz_device *device;
+    const char *system_id;
 
-    pa_log_info("Destroy device item which of type is %s", device_item->type);
+    pa_assert(pdevice);
+    pa_assert(manager);
 
-    device_item_free_func(device_item);
-}
+    pa_log_info("Handle bt pulse device");
 
-static unsigned _device_item_get_size(dm_device *device_item) {
-    unsigned int profile_num;
-    pa_assert(device_item);
+    direction = pulse_device_get_direction(pdevice);
+    system_id = pulse_device_get_system_id(pdevice);
 
-    profile_num = pa_idxset_size(device_item->profiles);
-    return profile_num;
-}
+    if (is_loaded) {
+        pa_tz_device_new_data data;
+        pa_tz_profile_new_data profile_data;
 
-static dm_device* _device_item_remove_profile(dm_device *device_item, dm_device_profile *profile_item, pa_device_manager *dm) {
-    unsigned int profile_num;
+        /* Use profile_new_data, because BT is multi profile type */
+        pa_tz_profile_new_data_init(&profile_data);
+        pa_tz_profile_new_data_set_profile(&profile_data, DEVICE_PROFILE_BT_A2DP);
+        pa_tz_profile_new_data_set_direction(&profile_data, direction);
+        pa_tz_profile_new_data_set_use_internal_codec(&profile_data, false);
+        if (direction == DM_DEVICE_DIRECTION_OUT)
+            pa_tz_profile_new_data_add_sink(&profile_data, DEVICE_ROLE_NORMAL, PA_SINK(pdevice));
+        else
+            pa_tz_profile_new_data_add_source(&profile_data, DEVICE_ROLE_NORMAL, PA_SOURCE(pdevice));
+
+        device = _device_list_get_device(manager, DEVICE_TYPE_BT, system_id);
+        /* Just add profile, if already exists */
+        if (device) {
+            dm_device_bt_sco_status_t sco_status;
+            if (pa_tz_device_sco_get_status(device, &sco_status) < 0) {
+                pa_log_error("Failed to get sco status");
+                return ;
+            }
+            if (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED)
+                pa_tz_device_add_profile(device, &profile_data, false);
+            else
+                pa_tz_device_add_profile(device, &profile_data, true);
+        } else {
+            /* Create new device with profile */
+            const char *name;
+            name = pulse_device_get_device_name(pdevice, DEVICE_TYPE_BT);
 
-    pa_assert(device_item);
-    pa_assert(device_item->profiles);
-    pa_assert(profile_item);
-    pa_assert(dm);
+            pa_tz_device_new_data_init(&data, manager->device_list, manager->comm, manager->dbus_conn);
+            pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_BT);
+            pa_tz_device_new_data_set_name(&data, name);
+            pa_tz_device_new_data_set_system_id(&data, system_id);
+            pa_tz_device_new_data_add_profile(&data, &profile_data, true);
 
-    profile_num = pa_idxset_size(device_item->profiles);
+            pa_tz_device_new(&data);
+            pa_tz_device_new_data_done(&data);
+        }
+        pa_tz_profile_new_data_done(&profile_data);
+    } else {
 
-    if (profile_num == 0) {
-        pa_log_error("Already Empty device_item");
-        return NULL;
+        if (!(device = _device_list_get_device(manager, DEVICE_TYPE_BT, system_id)))
+            pa_log_warn("Can't get bt device for %s", system_id);
+        else {
+            if (pa_tz_device_get_profile_num(device) > 1)
+                pa_tz_device_remove_profile(device, DEVICE_PROFILE_BT_A2DP);
+            else
+                pa_tz_device_free(device);
+        }
     }
+}
+
+static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *manager) {
+    pa_tz_device *device;
+    struct composite_type *ctype;
+    pa_dynarray *ctypes;
+    dm_device_direction_t direction;
 
-    pa_idxset_remove_by_data(device_item->profiles, profile_item, NULL);
-    _device_item_set_active_profile_auto(device_item);
+    pa_assert(pdevice);
+    pa_assert(manager);
+
+    pa_log_info("Handle internal pulse device");
+    direction = pulse_device_get_direction(pdevice);
+
+    /* Get types which this pulse_device belongs to */
+    if ((ctypes = pulse_device_get_belongs_type(pdevice, manager)) == NULL) {
+        pa_log_debug("Failed to get device type. Skip this");
+        return ;
+    }
+
+    if (is_loaded) {
+        /* Put this pulse_device to already loaded devices */
+        for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
+            ctype = pa_dynarray_get(ctypes, i);
+            pa_log_info("Found belongs type %s %s %s", ctype->type, pa_strempty(ctype->profile), ctype->role);
+            if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
+                pa_log_info("Add this pulse_device to device(%u)", pa_tz_device_get_id(device));
+                if (direction == DM_DEVICE_DIRECTION_OUT)
+                    pa_tz_device_profile_add_sink(device, ctype->profile, ctype->role, PA_SINK(pdevice));
+                else
+                    pa_tz_device_profile_add_source(device, ctype->profile, ctype->role, PA_SOURCE(pdevice));
+            } else {
+                pa_log_info("No device for %s", ctype->type);
+            }
+        }
+    } else {
+        /* Remove this pulse_device from already loaded devices */
+        for (int i = 0; i < pa_dynarray_size(ctypes); i++) {
+            ctype = pa_dynarray_get(ctypes, i);
+            pa_log_info("Found belongs type %s %s %s", ctype->type, ctype->profile, ctype->role);
+            if ((device = _device_list_get_device(manager, ctype->type, NULL))) {
+                pa_log_info("Remove this pulse_device from device(%u)", pa_tz_device_get_id(device));
+                if (direction == DM_DEVICE_DIRECTION_OUT)
+                    pa_tz_device_remove_sink(device, PA_SINK(pdevice));
+                else
+                    pa_tz_device_remove_source(device, PA_SOURCE(pdevice));
+            } else {
+                pa_log_info("No device for %s", ctype->type);
+            }
+        }
+    }
 
-    return device_item;
+    pa_dynarray_free(ctypes);
 }
 
-static dm_device_profile* create_device_profile(const char *device_profile, dm_device_direction_t direction, pa_hashmap *playback, pa_hashmap *capture) {
-    dm_device_profile *profile_item = NULL;
+static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(dm);
 
-    pa_assert(direction >= DM_DEVICE_DIRECTION_IN && direction <= DM_DEVICE_DIRECTION_BOTH);
+    pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
 
-    pa_log_debug("Create device profile for %s, direction:%s", device_profile, device_direction_to_string(direction));
+    if (pulse_device_is_monitor(PA_OBJECT(sink)))
+        return PA_HOOK_OK;
 
-    if (!(profile_item = (dm_device_profile *)pa_xmalloc(sizeof(dm_device_profile)))) {
-        pa_log_error("Cannot alloc for device item");
-        return NULL;
+    if (pulse_device_is_usb(PA_OBJECT(sink))) {
+        pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
+        handle_usb_pulse_device(PA_OBJECT(sink), true, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
+        pulse_device_set_use_internal_codec(PA_OBJECT(sink), false);
+        handle_bt_pulse_device(PA_OBJECT(sink), true, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
+        pulse_device_set_use_internal_codec(PA_OBJECT(sink), true);
+        handle_internal_pulse_device(PA_OBJECT(sink), true, dm);
+        return PA_HOOK_OK;
+    } else {
+        pa_log_debug("Don't care this sink");
     }
-    profile_item->profile = device_profile ? strdup(device_profile) : NULL;
-    profile_item->direction = direction;
-    profile_item->playback_state = DM_DEVICE_STATE_DEACTIVATED;
-    profile_item->capture_state = DM_DEVICE_STATE_DEACTIVATED;
-    profile_item->playback_devices = playback;
-    profile_item->capture_devices = capture;
-    profile_item->creation_time = pa_rtclock_now();
 
-    return profile_item;
+    return PA_HOOK_OK;
 }
 
-static dm_device* destroy_device_profile(dm_device_profile *profile_item, pa_device_manager *dm) {
-    dm_device *device_item;
-
-    pa_assert(profile_item);
-    pa_assert(profile_item->device_item);
+static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(dm);
 
-    device_item = profile_item->device_item;
+    pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
 
-    pa_log_info("Destroy device profile item which of profile is %s", profile_item->profile);
+    if (pulse_device_is_monitor(PA_OBJECT(sink)))
+        return PA_HOOK_OK;
 
-    if (_device_item_get_size(device_item) == 1) {
-        destroy_device_item(device_item, dm);
-        return NULL;
+    if (pulse_device_is_usb(PA_OBJECT(sink))) {
+        handle_usb_pulse_device(PA_OBJECT(sink), false, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_bluez(PA_OBJECT(sink))) {
+        handle_bt_pulse_device(PA_OBJECT(sink), false, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) {
+        handle_internal_pulse_device(PA_OBJECT(sink), false, dm);
+        return PA_HOOK_OK;
     } else {
-        _device_item_remove_profile(device_item, profile_item, dm);
-        profile_item_free_func(profile_item);
-        return device_item;
+        pa_log_debug("Don't care this sink");
     }
-}
 
-static void _device_profile_update_direction(dm_device_profile *profile_item) {
-    int prev_direction;
-    bool playback_exist = false, capture_exist = false;
+    return PA_HOOK_OK;
+}
 
-    if (!profile_item)
-        return;
+static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
+    pa_assert(c);
+    pa_assert(source);
+    pa_assert(dm);
 
-    prev_direction = profile_item->direction;
+    pa_log_info("========== source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
 
-    if (profile_item->playback_devices) {
-        if (pa_hashmap_size(profile_item->playback_devices) > 0) {
-            playback_exist = true;
-        }
-    }
-    if (profile_item->capture_devices) {
-        if (pa_hashmap_size(profile_item->capture_devices) > 0) {
-            capture_exist = true;
-        }
-    }
+    if (pulse_device_is_monitor(PA_OBJECT(source)))
+        return PA_HOOK_OK;
 
-    if (playback_exist && capture_exist) {
-        profile_item->direction = DM_DEVICE_DIRECTION_BOTH;
-    } else if (playback_exist) {
-        profile_item->direction = DM_DEVICE_DIRECTION_OUT;
-    } else if (capture_exist) {
-        profile_item->direction = DM_DEVICE_DIRECTION_IN;
+    if (pulse_device_is_usb(PA_OBJECT(source))) {
+        pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
+        handle_usb_pulse_device(PA_OBJECT(source), true, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
+        pulse_device_set_use_internal_codec(PA_OBJECT(source), false);
+        handle_bt_pulse_device(PA_OBJECT(source), true, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
+        pulse_device_set_use_internal_codec(PA_OBJECT(source), true);
+        handle_internal_pulse_device(PA_OBJECT(source), true, dm);
+        return PA_HOOK_OK;
     } else {
-        profile_item->direction = DM_DEVICE_DIRECTION_NONE;
+        pa_log_debug("Don't care this source");
     }
 
-    pa_log_debug("direction updated '%s'->'%s'", device_direction_to_string(prev_direction), device_direction_to_string(profile_item->direction));
+    return PA_HOOK_OK;
 }
 
-static dm_device_profile* _device_profile_add_pulse_device(dm_device_profile *profile_item, const char *role, void *pulse_device, pa_device_type_t pdt) {
-    if (!profile_item || !pulse_device || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
-        return NULL;
-    }
+static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
+    pa_assert(c);
+    pa_assert(source);
+    pa_assert(dm);
 
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        if (!(profile_item->playback_devices))
-            profile_item->playback_devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-        if (pa_hashmap_put(profile_item->playback_devices, (void *)role, pulse_device) < 0)
-            return NULL;
+    pa_log_info("=========== source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
+
+    if (pulse_device_is_monitor(PA_OBJECT(source)))
+        return PA_HOOK_OK;
+
+    if (pulse_device_is_usb(PA_OBJECT(source))) {
+        handle_usb_pulse_device(PA_OBJECT(source), false, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_bluez(PA_OBJECT(source))) {
+        handle_bt_pulse_device(PA_OBJECT(source), false, dm);
+        return PA_HOOK_OK;
+    } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) {
+        handle_internal_pulse_device(PA_OBJECT(source), false, dm);
+        return PA_HOOK_OK;
     } else {
-        if (!(profile_item->capture_devices))
-            profile_item->capture_devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-        if (pa_hashmap_put(profile_item->capture_devices, (void *)role, pulse_device) < 0)
-            return NULL;
+        pa_log_debug("Don't care this source");
     }
 
-    return profile_item;
+    return PA_HOOK_OK;
 }
 
-static dm_device_profile* _device_profile_add_sink(dm_device_profile *profile_item, const char *role, pa_sink *sink) {
-    if (!profile_item || !sink || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
-        return NULL;
-    }
 
-    if (!(profile_item->playback_devices))
-        profile_item->playback_devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    if (pa_hashmap_put(profile_item->playback_devices, (void *)role, sink) < 0)
-        return NULL;
 
-    return profile_item;
-}
+static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
+    pa_tz_device *device;
+    bool use_internal_codec = false;
+    uint32_t idx = 0;
 
-static dm_device_profile* _device_profile_remove_sink(dm_device_profile *profile_item, const char *role) {
-    if (!profile_item || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
-        return NULL;
-    }
-    pa_hashmap_remove(profile_item->playback_devices, role);
-    return profile_item;
-}
+    pa_assert(c);
+    pa_object_assert_ref(pdevice);
+    pa_assert(dm);
 
-static dm_device_profile* _device_profile_add_source(dm_device_profile *profile_item, const char *role, pa_source *source) {
-    if (!profile_item || !source || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
-        return NULL;
+    if (pa_sink_isinstance(pdevice)) {
+        pa_sink *s = PA_SINK(pdevice);
+        pa_sink_state_t state = pa_sink_get_state(s);
+        pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
+        if (s->use_internal_codec) {
+            if (state == PA_SINK_SUSPENDED) {
+                PA_IDXSET_FOREACH(device, dm->device_list, idx) {
+                    use_internal_codec = pa_tz_device_is_use_internal_codec(device);
+                    if (use_internal_codec)
+                        pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
+                }
+            }
+        } else {
+            if ((device = pa_device_manager_get_device_with_sink(s))) {
+                if (state == PA_SINK_RUNNING)
+                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_ACTIVATED);
+                else if (state == PA_SINK_SUSPENDED)
+                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
+            }
+        }
+    } else if (pa_source_isinstance(pdevice)) {
+        pa_source *s = PA_SOURCE(pdevice);
+        pa_source_state_t state = pa_source_get_state(s);
+        pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
+        if (s->use_internal_codec) {
+            if (state == PA_SOURCE_SUSPENDED) {
+                PA_IDXSET_FOREACH(device, dm->device_list, idx) {
+                    use_internal_codec = pa_tz_device_is_use_internal_codec(device);
+                    if (use_internal_codec)
+                        pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
+                }
+            }
+        } else {
+            if ((device = pa_device_manager_get_device_with_source(s))) {
+                if (state == PA_SOURCE_RUNNING)
+                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_ACTIVATED);
+                else if (state == PA_SOURCE_SUSPENDED)
+                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
+            }
+        }
     }
+    pa_log_debug("========= device_state_changed_hook_cb END =====");
 
-    if (!(profile_item->capture_devices))
-        profile_item->capture_devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    if (pa_hashmap_put(profile_item->capture_devices, (void *)role, source) < 0)
-        return NULL;
-
-    return profile_item;
+    return PA_HOOK_OK;
 }
 
-static int _device_profile_get_size(dm_device_profile *profile_item, unsigned int *playback_num, unsigned int *capture_num) {
-    if (!profile_item || !playback_num || !capture_num) {
-        pa_log_error("Invalid Parameter");
-        return -1;
-    }
+/*
+    Build params for load sink or source, and load it.
+*/
 
-    if (!(profile_item->playback_devices))
-        *playback_num = 0;
-    else
-        *playback_num = pa_hashmap_size(profile_item->playback_devices);
-
-    if (!(profile_item->capture_devices))
-        *capture_num = 0;
-    else
-        *capture_num = pa_hashmap_size(profile_item->capture_devices);
-
-    return 0;
-}
-
-
-static dm_device_profile* _device_profile_remove_source(dm_device_profile *profile_item, const char *role) {
-    if (!profile_item || !(profile_item->capture_devices) || !device_role_is_valid(role)) {
-        pa_log_error("Invalid Parameter");
-        return NULL;
-    }
-    pa_hashmap_remove(profile_item->capture_devices, role);
-    return profile_item;
-}
-
-static void _device_profile_set_state(dm_device_profile *profile_item,  dm_device_direction_t direction, dm_device_state_t state) {
-    dm_device_state_t prev_state, new_state;
-    pa_assert(profile_item);
-
-    prev_state = COMPOUND_STATE(profile_item);
-    pa_log_debug("previous playback_state : %d, capture_state : %d => state %d", profile_item->playback_state, profile_item->capture_state, prev_state);
-    if (direction & DM_DEVICE_DIRECTION_IN)
-        profile_item->capture_state = state;
-    if (direction & DM_DEVICE_DIRECTION_OUT)
-        profile_item->playback_state = state;
-    new_state = COMPOUND_STATE(profile_item);
-    pa_log_debug("new playback_state : %d, capture_state : %d => state %d", profile_item->playback_state, profile_item->capture_state, new_state);
-
-    if (prev_state != new_state) {
-        notify_device_info_changed(profile_item->device_item, DM_DEVICE_CHANGED_INFO_STATE, profile_item->device_item->dm);
-    }
-}
-
-static int device_type_get_direction(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *identifier) {
-    struct device_type_info *type_info = NULL;
-    struct device_status_info *status_info;
-
-    if (!dm || !device_type) {
-        pa_log_error("Invalid Parameter");
-        return -1;
-    }
-
-    if (pa_streq(device_type, DEVICE_TYPE_SPEAKER)) {
-        return DM_DEVICE_DIRECTION_OUT;
-    } else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER)) {
-        return DM_DEVICE_DIRECTION_OUT;
-    } else if (pa_streq(device_type, DEVICE_TYPE_MIC)) {
-        return DM_DEVICE_DIRECTION_IN;
-    } else if (pa_streq(device_type, DEVICE_TYPE_BT) && pa_streq(device_profile, DEVICE_PROFILE_BT_A2DP)) {
-        return -1;
-    } else if (pa_streq(device_type, DEVICE_TYPE_BT) && pa_streq(device_profile, DEVICE_PROFILE_BT_SCO)) {
-        return DM_DEVICE_DIRECTION_BOTH;
-    } else if (pa_streq(device_type, DEVICE_TYPE_HDMI)) {
-        return DM_DEVICE_DIRECTION_OUT;
-    } else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO)) {
-        return -1;
-    } else if (pa_streq(device_type, DEVICE_TYPE_FORWARDING)) {
-        return DM_DEVICE_DIRECTION_BOTH;
-    } else if (pa_streq(device_type, DEVICE_TYPE_AUDIO_JACK)) {
-        if (!(type_info = _device_manager_get_type_info(dm->type_infos, device_type, device_profile))) {
-            pa_log_error("No type map for %s", device_type);
-            return -1;
-        }
-        status_info = _device_manager_get_status_info(dm->device_status, type_info->type, type_info->profile, identifier);
-        if (status_info->detected_type == DEVICE_DETECTED_AUDIO_JACK_BOTH_DIREC) {
-            return DM_DEVICE_DIRECTION_BOTH;
-        } else if (status_info->detected_type == DEVICE_DETECTED_AUDIO_JACK_OUT_DIREC) {
-            return  DM_DEVICE_DIRECTION_OUT;
-        } else {
-            pa_log_debug("Cannot get audio jack device direction");
-            return -1;
-        }
-    }
-
-    return -1;
-}
-
-static int pulse_device_get_device_type(void *pulse_device, pa_device_type_t pdt, dm_device_class_t device_class, const char **device_type, const char **device_profile, const char **device_name) {
-    pa_proplist *prop;
+static void* load_device(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
+    const char *args = NULL;
+    const char *module_name;
+    pa_module *module;
     pa_sink *sink;
     pa_source *source;
+    uint32_t device_idx;
+    dm_device_class_t device_class;
 
-    pa_assert(pulse_device);
-    pa_assert(device_type);
-    pa_assert(device_profile);
-
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        sink = (pa_sink *) pulse_device;
-        prop = sink->proplist;
-    } else {
-        source = (pa_source*) pulse_device;
-        prop = source->proplist;
-    }
-
-    if (device_class == DM_DEVICE_CLASS_ALSA) {
-        if (pulse_device_is_usb(prop)) {
-            *device_type = DEVICE_TYPE_USB_AUDIO;
-            *device_profile = NULL;
-            *device_name = pa_proplist_gets(prop, "udev.id");
-        } else {
-            pa_log_warn("This is alsa device, but not usb. really unknown device");
-            return -1;
-        }
-    } else if (device_class == DM_DEVICE_CLASS_BT) {
-        *device_type = DEVICE_TYPE_BT;
-        *device_profile = DEVICE_PROFILE_BT_A2DP;
-        *device_name = pa_proplist_gets(prop, "bluez.alias");
-    } else {
-        pa_log_warn("Invalid device type, neither alsa nor bluez");
-        return -1;
-    }
-
-    return 0;
-}
-
-static dm_device_profile* _device_item_get_profile(dm_device *device_item, const char *profile) {
-    dm_device_profile *profile_item;
-    uint32_t profile_idx;
-
-    if (!device_item || !device_item->profiles)
-        return NULL;
-
-    PA_IDXSET_FOREACH(profile_item, device_item->profiles, profile_idx) {
-        if (!compare_device_profile(profile_item->profile, profile)) {
-            return profile_item;
-        }
-    }
-    return NULL;
-}
-
-static dm_device_profile* _device_item_get_active_profile(dm_device *device_item) {
-    dm_device_profile *profile_item;
-
-    if (!device_item || !device_item->profiles)
-        return NULL;
-
-    if ((profile_item = pa_idxset_get_by_index(device_item->profiles, device_item->active_profile)))
-        return profile_item;
-
-
-    return NULL;
-}
-
-static pa_sink* _device_manager_set_default_sink(pa_device_manager *dm,  const char *device_type,  const char *device_profile,  const char *role) {
-    dm_device *device_item;
-    dm_device_profile *profile_item;
-    pa_sink *sink;
-
-    if (!device_type || !role) {
-        pa_log_warn("Argument for set_default_sink invalid");
-        return NULL;
-    }
-
-    if (!(device_item = _device_manager_get_device(dm->device_list, device_type))) {
-        pa_log_warn("cannot get device item for %s", device_type);
-        return NULL;
-    }
-    if (!(profile_item = _device_item_get_profile(device_item, device_profile))) {
-        pa_log_warn("cannot get profile item for %s", device_profile);
-        return NULL;
-    }
-
-    if (!(sink = pa_hashmap_get(profile_item->playback_devices, role))) {
-        pa_log_warn("cannot get sink for %s", role);
-        return NULL;
-    }
-
-    sink = pa_namereg_set_default_sink(dm->core, sink);
-    return sink;
-}
+    pa_assert(c);
+    pa_assert(device_string);
+    pa_assert(device_params);
 
-static pa_source* _device_manager_set_default_source(pa_device_manager *dm,  const char *device_type,  const char *device_profile,  const char *role) {
-    dm_device *device_item;
-    dm_device_profile *profile_item;
-    pa_source *source;
+    pa_log_info("Load %s Device : String'%s' Param'%s'", is_sink ? "Playback" : "Capture", device_string, device_params);
 
-    if (!device_type || !role) {
-        pa_log_warn("Argument for set_default_source invalid");
+    device_class = device_string_get_class(device_string);
+    if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
+        pa_log_warn("Invalid device_string '%s'", device_string);
         return NULL;
     }
 
-    if (!(device_item = _device_manager_get_device(dm->device_list, device_type))) {
-        pa_log_warn("cannot get device item for %s", device_type);
+    if (!(module_name = device_class_get_module_name(device_class, is_sink))) {
+        pa_log_error("Get proper module name to load failed");
         return NULL;
     }
-    if (!(profile_item = _device_item_get_profile(device_item, device_profile))) {
-        pa_log_warn("cannot get profile item for %s", device_profile);
+    if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
+        pa_log_error("Get proper module name to load failed");
         return NULL;
     }
-
-    if (!(source = pa_hashmap_get(profile_item->capture_devices, role))) {
-        pa_log_warn("cannot get source for %s", role);
+    if (!(module = pa_module_load(c, module_name, args))) {
+        pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
         return NULL;
     }
 
-    source = pa_namereg_set_default_source(dm->core, source);
-    return source;
-}
-
-static dm_device_profile* handle_not_predefined_device_profile(void *pulse_device, pa_device_type_t pdt, const char *device_profile) {
-    dm_device_profile *profile_item = NULL;
-    dm_device_direction_t direc;
 
-    pa_log_info("Create device profile item %s", device_profile);
-    if (pdt == PA_DEVICE_TYPE_SINK)
-        direc = DM_DEVICE_DIRECTION_OUT;
-    else
-        direc = DM_DEVICE_DIRECTION_IN;
-
-    if (!(profile_item = create_device_profile(device_profile, direc, NULL, NULL))) {
-        pa_log_error("create_device_profile failed");
-        goto failed;
-    }
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        if (!(_device_profile_add_sink(profile_item, DEVICE_ROLE_NORMAL, pulse_device))) {
-            pa_log_error("failed to add sink");
-            goto failed;
+    if (is_sink) {
+        PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
+            if (sink->module == module) {
+                return sink;
+            }
         }
     } else {
-        if (!(_device_profile_add_source(profile_item, DEVICE_ROLE_NORMAL, pulse_device))) {
-            pa_log_error("failed to add source");
-            goto failed;
-        }
-    }
-
-    return profile_item;
-failed:
-    if (profile_item)
-        pa_xfree(profile_item);
-    return NULL;
-}
-
-
-static dm_device* handle_not_predefined_device(pa_device_manager *dm, void *pulse_device, pa_device_type_t pdt, dm_device_class_t device_class) {
-    dm_device_profile *profile_item = NULL;
-    const char *device_type, *device_profile, *device_name;
-    dm_device *device_item = NULL;
-    pa_source *sibling_source, *source;
-    pa_sink *sibling_sink, *sink;
-
-    pa_assert(dm);
-    pa_assert(pulse_device);
-
-    pa_log_info("handle_not_predefined_device");
-
-    if (pdt == PA_DEVICE_TYPE_SINK)
-       ((pa_sink*)pulse_device)->use_internal_codec = false;
-    else
-       ((pa_source*)pulse_device)->use_internal_codec = false;
-
-    if (pulse_device_get_device_type(pulse_device, pdt, device_class, &device_type, &device_profile, &device_name) < 0) {
-        pa_log_warn("Cannot get device type of this device");
-        return NULL;
-    }
-
-    /*
-       Find opposite direction sink/sources on same device.
-       If Found, add sink or source to same device_item.
-    */
-    if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO)) {
-        if (pdt == PA_DEVICE_TYPE_SINK) {
-            sink = (pa_sink *) pulse_device;
-            if ((sibling_source = pulse_device_get_opposite_sibling_device(sink, PA_DEVICE_TYPE_SINK))) {
-                if (sibling_source->device_item) {
-                    device_item = (dm_device *) sibling_source->device_item;
-                    profile_item = _device_item_get_profile(device_item, NULL);
-                    if (!(_device_profile_add_sink(profile_item, DEVICE_ROLE_NORMAL, sink))) {
-                        pa_log_error("failed to add sink beside sibling source");
-                        goto failed;
-                    }
-                    _device_profile_update_direction(profile_item);
-                    notify_device_info_changed(device_item, DM_DEVICE_CHANGED_INFO_IO_DIRECTION, dm);
-                    goto end;
-                }
-            }
-        } else {
-            source = (pa_source*) pulse_device;
-            if ((sibling_sink = pulse_device_get_opposite_sibling_device(source, PA_DEVICE_TYPE_SOURCE))) {
-                if (sibling_sink->device_item) {
-                    device_item = (dm_device *) sibling_sink->device_item;
-                    profile_item = _device_item_get_profile(device_item, NULL);
-                    if (!(_device_profile_add_source(profile_item, DEVICE_ROLE_NORMAL, source))) {
-                        pa_log_error("failed to add source beside sibling sink");
-                        goto failed;
-                    }
-                    _device_profile_update_direction(profile_item);
-                    notify_device_info_changed(device_item, DM_DEVICE_CHANGED_INFO_IO_DIRECTION, dm);
-                    goto end;
-                }
+        PA_IDXSET_FOREACH(source, c->sources, device_idx) {
+            if (source->module == module) {
+                return source;
             }
         }
     }
 
-    if (!(profile_item = handle_not_predefined_device_profile(pulse_device, pdt, device_profile))) {
-        pa_log_error("failed to handle unknown device profile");
-        goto failed;
-    }
-    _device_profile_update_direction(profile_item);
-
-    if (device_class == DM_DEVICE_CLASS_BT) {
-        if ((device_item = _device_manager_get_device(dm->device_list, DEVICE_TYPE_BT))) {
-            pa_log_debug("found bt device");
-            _device_item_add_profile(device_item, profile_item, NULL, dm);
-            goto end;
-        }
-    }
-
-    if (!(device_item = create_device_item(device_type, device_name, profile_item, dm))) {
-        pa_log_error("failed to create device item for not predefined device");
-        goto failed;
-    }
-
-end:
-
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        sink = (pa_sink *) pulse_device;
-        sink->device_item = device_item;
-    } else {
-        source = (pa_source *) pulse_device;
-        source->device_item = device_item;
-    }
-
-    return device_item;
-
-failed:
-    pa_log_error("Failed to handle external device");
-    if (profile_item)
-        pa_xfree(profile_item);
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        sink = (pa_sink *) pulse_device;
-        sink->device_item = device_item;
-    } else {
-        source = (pa_source *) pulse_device;
-        source->device_item = device_item;
-    }
-
-
     return NULL;
 }
 
-static bool pulse_device_loaded_with_param(pa_core *core, pa_device_type_t pdt, const char *device_string, const char *params) {
-    pa_sink *sink;
-    pa_source *source;
+static pa_sink* _core_get_sink(pa_core *core, const char *device_string, const char *params) {
     uint32_t device_idx;
+    pa_sink *sink;
 
     pa_assert(core);
     pa_assert(device_string);
 
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
-            if (pulse_device_class_is_monitor(sink->proplist))
-                continue;
-            if (pa_streq(device_string, pulse_device_get_device_string(sink, pdt))) {
-                if (!compare_device_params_with_module_args(sink, pdt, params)) {
-                    return true;
-                }
-            }
-        }
-    } else {
-        PA_IDXSET_FOREACH(source, core->sources, device_idx) {
-            if (pulse_device_class_is_monitor(source->proplist))
-                continue;
-            if (pa_streq(device_string, pulse_device_get_device_string(source, pdt))) {
-                if (!compare_device_params_with_module_args(source, pdt, params)) {
-                    return true;
-                }
-            }
+    PA_IDXSET_FOREACH(sink, core->sinks, device_idx) {
+        if (pulse_device_is_monitor(PA_OBJECT(sink)))
+            continue;
+        if (pulse_device_same_device_string(PA_OBJECT(sink), device_string)) {
+            if (params == NULL)
+                return sink;
+            else if (pulse_device_params_is_equal(PA_OBJECT(sink), params))
+                return sink;
         }
     }
-    return false;
+
+    return NULL;
 }
 
-static int device_type_get_pulse_devices(struct device_type_info *type_info, pa_hashmap **playback, pa_hashmap **capture, pa_device_manager *dm) {
-    struct device_file_info *file_info;
-    const char *device_string, *params, *role;
+static pa_source* _core_get_source(pa_core *core, const char *device_string, const char *params) {
     uint32_t device_idx;
-    pa_sink *sink;
     pa_source *source;
-    void *state;
-
-    pa_assert(type_info);
-    pa_assert(playback);
-    pa_assert(capture);
-    pa_assert(dm);
-
-    if (pa_streq(type_info->type, DEVICE_TYPE_FORWARDING)) {
-        dm_device *device_item;
-        dm_device_profile *device_profile;
-        pa_sink *spk_sink;
-
-        /* Let sink of forwading device same as speaker,
-         * source of forwarding device will be monitor of that sink */
-        if (!(device_item = _device_manager_get_device(dm->device_list, DEVICE_TYPE_SPEAKER))) {
-            pa_log_error("get speaker item failed");
-            goto failed;
-        } else if (!(device_profile = _device_item_get_profile(device_item, NULL))) {
-            pa_log_error("get speaker profile failed");
-            goto failed;
-        } else if (!(spk_sink = _device_profile_get_sink(device_profile, DEVICE_ROLE_NORMAL)) || !(spk_sink->monitor_source)) {
-            pa_log_error("get speaker sink and monitor source failed");
-            goto failed;
-        } else {
-            *playback = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-            *capture = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-            pa_hashmap_put(*playback, (void *)DEVICE_ROLE_NORMAL, spk_sink);
-            pa_hashmap_put(*capture, (void *)DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
-            ((pa_source*)(spk_sink->monitor_source))->use_internal_codec = true;
-        }
-    } else {
-        if (type_info->playback_devices) {
-            *playback = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-            PA_HASHMAP_FOREACH_KEY(device_string, type_info->playback_devices, state, role) {
-                if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
-                    pa_log_error("No playback file map for '%s'", device_string);
-                    goto failed;
-                }
 
-                if (!(params = pa_hashmap_get(file_info->roles, role))) {
-                    pa_log_error("No params for '%s:%s'", device_string, role);
-                    goto failed;
-                }
+    pa_assert(core);
+    pa_assert(device_string);
 
-                PA_IDXSET_FOREACH(sink, dm->core->sinks, device_idx) {
-                    if (pulse_device_class_is_monitor(sink->proplist))
-                        continue;
-                    if (pulse_device_same_device_string(sink, PA_DEVICE_TYPE_SINK, device_string)) {
-                        if (!compare_device_params_with_module_args(sink, PA_DEVICE_TYPE_SINK, params)) {
-                            pa_hashmap_put(*playback, (void *)role, sink);
-                            pa_log_debug("role:%s <- sink:%s", role, sink->name);
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        if (type_info->capture_devices) {
-            *capture = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-            PA_HASHMAP_FOREACH_KEY(device_string, type_info->capture_devices, state, role) {
-                if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
-                    pa_log_error("No capture file map for '%s'", device_string);
-                    goto failed;
-                }
-                if (!(params = pa_hashmap_get(file_info->roles, role))) {
-                    pa_log_error("No params for '%s:%s'", device_string, role);
-                    goto failed;
-                }
-                PA_IDXSET_FOREACH(source, dm->core->sources, device_idx) {
-                    if (pulse_device_class_is_monitor(source->proplist))
-                        continue;
-                    if (pulse_device_same_device_string(source, PA_DEVICE_TYPE_SOURCE, device_string)) {
-                        if (!compare_device_params_with_module_args(source, PA_DEVICE_TYPE_SOURCE, params)) {
-                            pa_hashmap_put(*capture, (void *)role, source);
-                            pa_log_debug("role:%s <- source:%s", role, source->name);
-                            break;
-                        }
-                    }
-                }
-            }
+    PA_IDXSET_FOREACH(source, core->sources, device_idx) {
+        if (pulse_device_is_monitor(PA_OBJECT(source)))
+            continue;
+        if (pulse_device_same_device_string(PA_OBJECT(source), device_string)) {
+            if (params == NULL)
+                return source;
+            else if (pulse_device_params_is_equal(PA_OBJECT(source), params))
+                return source;
         }
     }
 
-    return 0;
-
-failed:
-    if (!(*playback))
-        pa_hashmap_free(*playback);
-    if (!(*capture))
-        pa_hashmap_free(*capture);
-    *playback = NULL;
-    *capture = NULL;
-
-    return -1;
-}
-
-static const char* device_type_info_get_device_string(struct device_type_info *type_info, const char *role, pa_device_type_t pdt) {
-    pa_assert(type_info);
-    pa_assert(role);
-
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        if (type_info->playback_devices)
-            return pa_hashmap_get(type_info->playback_devices, role);
-        else
-            return NULL;
-    } else {
-        if (type_info->capture_devices)
-            return pa_hashmap_get(type_info->capture_devices, role);
-        else
-            return NULL;
-    }
-
-}
-
-static const char* device_file_info_get_role_with_params(struct device_file_info *file_info, const char *params) {
-    char *params_tmp, *role;
-    void *state;
-
-    PA_HASHMAP_FOREACH_KEY(params_tmp, file_info->roles, state, role) {
-        if (!compare_device_params(params_tmp, params)) {
-            return role;
-        }
-    }
     return NULL;
 }
 
-static dm_device* handle_device_type_available(struct device_type_info *type_info, const char *name, pa_device_manager *dm) {
-    dm_device_profile *profile_item = NULL;
-    dm_device *device_item = NULL;
-    dm_device_direction_t direction;
-    pa_hashmap *playback = NULL, *capture = NULL;
-
-    pa_assert(dm);
-    pa_assert(dm->type_infos);
-
-    pa_log_debug("handle_device_type_available, type:%s, profile:%s, name:%s", type_info->type, type_info->profile, name);
-
-    /* Directions of some types are not statically defined, ex) earjack */
-    if ((direction = device_type_get_direction(dm, type_info->type, type_info->profile, NULL)) < 0) {
-        pa_log_error("Failed to get direction of %s.%s", type_info->type, type_info->profile);
-        return NULL;
-    }
-    pa_log_debug("Direction of %s.%s is %s", type_info->type, type_info->profile, device_direction_to_string(direction));
-
-    /* Get Sink/Sources for device_type, profile */
-    if (device_type_get_pulse_devices(type_info, &playback, &capture, dm) < 0) {
-        pa_log_error("Failed to get sink/sources related to %s.%s", type_info->type, type_info->profile);
-        return NULL;
-    }
-
-    /* Check whether Sink/Sources for direction of type are loaded */
-    if ((((direction & DM_DEVICE_DIRECTION_IN) && !capture) || ((direction & DM_DEVICE_DIRECTION_OUT) && !playback))) {
-        pa_log_debug("Sink/Sources for %s.%s are not fully loaded yet", type_info->type, type_info->profile);
-        goto failed;
-    }
 
-    profile_item = create_device_profile(type_info->profile,  direction,  playback,  capture);
+static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
+        dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
+    pa_assert(data);
 
-    if (!(device_item = _device_manager_get_device(dm->device_list, type_info->type))) {
-        pa_log_debug("No device item for %s, Create", type_info->type);
-        device_item = create_device_item(type_info->type, name, profile_item, dm);
-    } else {
-        _device_item_add_profile(device_item, profile_item, NULL, dm);
-    }
-
-    return device_item;
-
-failed:
-    if (playback)
-        pa_hashmap_free(playback);
-    if (capture)
-        pa_hashmap_free(capture);
-    return NULL;
+    pa_tz_device_new_data_set_type(data, type);
+    pa_tz_device_new_data_set_direction(data, direction);
+    pa_tz_device_new_data_set_use_internal_codec(data, use_internal_codec);
 }
 
-/* FIXME to get identifier of physical device */
-static const char* pulse_device_get_identifier(void *pulse_device, pa_device_type_t pdt, dm_device_class_t device_class) {
-/*
-    const char *sysfs_path;
+static void _fill_profile_new_data_basic(pa_tz_profile_new_data *profile_data,
+        const char *profile, dm_device_direction_t direction, bool use_internal_codec, pa_device_manager *dm) {
+    pa_assert(profile_data);
 
-    if (device_class == TIZEN_AUDIO_DEVICE_CLASS_ALSA) {
-        if (!(sysfs_path = pa_proplist_gets(sink->proplist, "sysfs.path"))) {
-            pa_log_warn("No sysfs.path for sink '%s'", sink->name);
-            return NULL;
-        } else {
-            return sysfs_path;
-        }
-    } else if (device_class == TIZEN_AUDIO_DEVICE_CLASS_BT) {
-    }
-    */
-    return NULL;
+    pa_tz_profile_new_data_set_profile(profile_data, profile);
+    pa_tz_profile_new_data_set_direction(profile_data, direction);
+    pa_tz_profile_new_data_set_use_internal_codec(profile_data, use_internal_codec);
 }
 
-static void handle_predefined_device_loaded(void *pulse_device, pa_device_type_t pdt, dm_device_class_t device_class, const char *device_string, const char *role,  pa_device_manager *dm) {
-    const char *identifier, *device_string_tmp;
-    struct device_type_info *type_info;
-    struct device_status_info *status_info;
-    uint32_t type_idx;
-    dm_device *device_item;
-    dm_device_profile *profile_item;
-
-    pa_assert(pulse_device);
-    pa_assert(dm);
-    pa_assert(dm->file_map);
-    pa_assert(device_string);
-    pa_assert(role);
-
-    pa_log_info("Predefined device loaded, Type:%s, Class:%d, device_string:%s, role:%s",
-            pdt == PA_DEVICE_TYPE_SINK ? "sink" : "source", device_class, device_string, role);
-
-    if (pdt == PA_DEVICE_TYPE_SINK)
-       ((pa_sink*)pulse_device)->use_internal_codec = true;
-    else
-       ((pa_source*)pulse_device)->use_internal_codec = true;
-
-    identifier = pulse_device_get_identifier(pulse_device, pdt, device_class);
-    PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
-        /* foreach matching types (which has device_string-role) */
-        if ((device_string_tmp = device_type_info_get_device_string(type_info, role, pdt)) && pa_streq(device_string_tmp, device_string)) {
-            /*
-               Check device_item is already exists.
-               If already exists, add loaded sink or source to that.
-            */
-            if ((device_item = _device_manager_get_device(dm->device_list, type_info->type))) {
-                if ((profile_item = _device_item_get_profile(device_item, type_info->profile))) {
-                    pa_log_debug("device_item for %s.%s already exists", type_info->type, type_info->profile);
-                    if (!_device_profile_add_pulse_device(profile_item,  role,  pulse_device,  pdt))
-                        pa_log_error("add pulse device to profile_item failed");
-                    continue;
-                }
-            }
+static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
+    pa_sink *sink;
+    char *device_string, *role;
+    void *state;
 
-            /* Get status_info for device_type, profile*/
-            if (!(status_info = _device_manager_get_status_info(dm->device_status, type_info->type, type_info->profile, identifier))) {
-                pa_log_error("%s.%s.%s doesn't have status_info", type_info->type, type_info->profile, identifier);
-                continue;
-            }
-            /* Only if device_type is on detected state*/
-            if (status_info->detected == DEVICE_DETECTED) {
-                pa_log_debug("%s.%s type is detected status", type_info->type, type_info->profile);
+    pa_assert(data);
+    pa_assert(type_info);
 
-                handle_device_type_available(type_info, NULL, dm);
-            } else {
-                pa_log_debug("  This type is not detected status");
-            }
-        }
+    if (type_info->playback_devices == NULL) {
+        pa_log_error("No playback devices for %s %s", type_info->type, pa_strempty(type_info->profile));
+        return -1;
     }
-}
 
-static void handle_sink_unloaded(pa_sink *sink, pa_device_manager *dm) {
-    dm_device_profile *profile_item = NULL;
-    dm_device *device_item;
-    uint32_t device_idx = 0, profile_idx;
-    pa_sink *sink_iter = NULL;
-    void *state = NULL;
-    const char *role;
-
-    if (!sink || !dm) {
-        pa_log_error("Invalid Paramter");
-        return;
+    PA_HASHMAP_FOREACH_KEY(device_string, type_info->playback_devices, state, role) {
+        sink = _core_get_sink(dm->core, device_string, NULL);
+        if (sink)
+            pa_tz_device_new_data_add_sink(data, role, sink);
+        else
+            pa_log_error("Failed to get matching sink for %s %s", role, device_string);
     }
-    pa_assert(sink);
-    pa_assert(dm);
-    pa_assert(dm->device_list);
 
-    pa_log_debug("Sink unloaded, Let's remove associated device_profiles with this sink");
-
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        PA_IDXSET_FOREACH(profile_item, device_item->profiles, profile_idx) {
-            if (profile_item->playback_devices) {
-                PA_HASHMAP_FOREACH_KEY(sink_iter, profile_item->playback_devices, state, role) {
-                    if (sink_iter == sink) {
-                        unsigned int profile_playback_size = 0, profile_capture_size = 0, item_size = 0;
-                        pa_log_info("device '%s' have this sink", device_item->name);
-                        _device_profile_get_size(profile_item, &profile_playback_size, &profile_capture_size);
-                        item_size = _device_item_get_size(device_item);
-                        pa_log_debug("profile playback size : %u, capture size : %u, item size : %u", profile_playback_size, profile_capture_size, item_size);
-                        if (profile_playback_size == 1 && profile_capture_size == 0) {
-                            if (item_size == 1) {
-                                pa_log_debug("notify device disconnected");
-                                _device_list_remove_device(dm->device_list, device_item, dm);
-                                notify_device_connection_changed(device_item, false, dm);
-                            }
-                        }
-                        _device_profile_remove_sink(profile_item, role);
-                    }
-                }
-                if (!pa_hashmap_size(profile_item->playback_devices)) {
-                    pa_hashmap_free(profile_item->playback_devices);
-                    profile_item->playback_devices = NULL;
-
-                    if (profile_item->direction == DM_DEVICE_DIRECTION_BOTH) {
-                        if (device_type_is_valid_direction(profile_item->device_item->type, profile_item->profile, DM_DEVICE_DIRECTION_IN)) {
-                            profile_item->direction = DM_DEVICE_DIRECTION_IN;
-                        } else {
-                            if (!destroy_device_profile(profile_item, dm))
-                                break;
-                        }
-                    } else {
-                        if (!destroy_device_profile(profile_item, dm))
-                            break;
-                    }
-                } else {
-                    _device_profile_update_direction(profile_item);
-                }
-            }
-        }
-    }
+    return 0;
 }
 
-static void handle_source_unloaded(pa_source *source, pa_device_manager *dm) {
-    dm_device_profile *profile_item = NULL;
-    dm_device *device_item;
-    uint32_t device_idx = 0, profile_idx;
-    pa_source *source_iter = NULL;
-    void *state = NULL;
-    const char *role;
-
-    if (!source || !dm) {
-        pa_log_error("Invalid Paramter");
-        return;
-    }
-    pa_assert(source);
-    pa_assert(dm);
-    pa_assert(dm->device_list);
+static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
+    pa_source *source;
+    char *device_string, *role;
+    void *state;
 
-    pa_log_debug("Source unloaded, Let's remove associated device_profiles with this source");
-
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        PA_IDXSET_FOREACH(profile_item, device_item->profiles, profile_idx) {
-            if (profile_item->capture_devices) {
-                PA_HASHMAP_FOREACH_KEY(source_iter, profile_item->capture_devices, state, role) {
-                    if (source_iter == source) {
-                        unsigned int profile_playback_size = 0, profile_capture_size = 0, item_size = 0;
-                        pa_log_info("device '%s' have this source", device_item->name);
-                        _device_profile_get_size(profile_item, &profile_playback_size, &profile_capture_size);
-                        item_size = _device_item_get_size(device_item);
-                        pa_log_debug("profile playback size : %u, capture size : %u, item size : %u", profile_playback_size, profile_capture_size, item_size);
-                        if (profile_capture_size == 1 && profile_playback_size == 0) {
-                            if (item_size == 1) {
-                                pa_log_debug("notify device disconnected");
-                                _device_list_remove_device(dm->device_list, device_item, dm);
-                                notify_device_connection_changed(device_item, false, dm);
-                            }
-                        }
-
-                        _device_profile_remove_source(profile_item, role);
-                    }
-                }
+    pa_assert(data);
+    pa_assert(type_info);
 
-                if (!pa_hashmap_size(profile_item->capture_devices)) {
-                    pa_hashmap_free(profile_item->capture_devices);
-                    profile_item->capture_devices = NULL;
-
-                    if (profile_item->direction == DM_DEVICE_DIRECTION_BOTH) {
-                        if (device_type_is_valid_direction(profile_item->device_item->type, profile_item->profile, DM_DEVICE_DIRECTION_OUT)) {
-                            profile_item->direction = DM_DEVICE_DIRECTION_OUT;
-                        } else {
-                            if (!destroy_device_profile(profile_item, dm))
-                                break;
-                        }
-                    } else {
-                        if (!destroy_device_profile(profile_item, dm))
-                            break;
-                    }
-                } else {
-                    _device_profile_update_direction(profile_item);
-                }
-            }
-        }
+    if (type_info->capture_devices == NULL) {
+        pa_log_error("No capture devices for %s %s", type_info->type, pa_strempty(type_info->profile));
+        return -1;
     }
-}
 
-static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
-    const char *device_string = NULL, *role = NULL, *device_string_removed_params = NULL;
-    struct device_file_info *file_info = NULL;
-    dm_device_class_t device_class;
-
-    pa_assert(c);
-    pa_assert(sink);
-    pa_assert(sink->proplist);
-    pa_assert(dm);
-
-    if (pulse_device_class_is_monitor(sink->proplist)) {
-        pa_log_debug("This device's class is monitor. Skip this");
-        return PA_HOOK_OK;
+    PA_HASHMAP_FOREACH_KEY(device_string, type_info->capture_devices, state, role) {
+        source = _core_get_source(dm->core, device_string, NULL);
+        if (source)
+            pa_tz_device_new_data_add_source(data, role, source);
+        else
+            pa_log_error("Failed to get matching source for %s %s", role, device_string);
     }
 
-    pa_log_info("========== Sink Put Hook Callback '%s'(%d) ==========", sink->name, sink->index);
+    return 0;
+}
 
-    device_class = pulse_device_get_class(sink, PA_DEVICE_TYPE_SINK);
-    pa_log_info("Device Class '%s'", device_class_to_string(device_class));
+static int _fill_profile_new_data_sinks(pa_tz_profile_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
+    pa_sink *sink;
+    char *device_string, *role;
+    void *state;
 
-    if (!(device_string = pulse_device_get_device_string(sink, PA_DEVICE_TYPE_SINK))) {
-        return PA_HOOK_OK;
-    } else {
-        pa_log_info("Device String '%s'", device_string);
-    }
+    pa_assert(data);
+    pa_assert(type_info);
 
-    if (device_class == DM_DEVICE_CLASS_BT) {
-        handle_not_predefined_device(dm, sink, PA_DEVICE_TYPE_SINK, device_class);
-    } else if ((file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
-        /* module's argument includes device-string(ex. device=hw:0,0 ),
-           but key params for device_types hashmap is not. */
-        if (!(device_string_removed_params = pulse_device_get_device_string_removed_argument(sink, PA_DEVICE_TYPE_SINK))) {
-            pa_log_debug("argument null");
-            return PA_HOOK_OK;
-        }
-        if (!(role = device_file_info_get_role_with_params(file_info, device_string_removed_params))) {
-            pa_log_error("No role for %s", file_info->device_string);
-            return PA_HOOK_OK;
-        }
+    if (type_info->playback_devices == NULL) {
+        pa_log_error("No playback devices for %s %s", type_info->type, pa_strempty(type_info->profile));
+        return -1;
+    }
 
-        handle_predefined_device_loaded(sink, PA_DEVICE_TYPE_SINK, device_class, device_string, role, dm);
-    } else {
-        pa_log_debug("Not-predefined device");
-        handle_not_predefined_device(dm, sink, PA_DEVICE_TYPE_SINK, device_class);
+    PA_HASHMAP_FOREACH_KEY(device_string, type_info->playback_devices, state, role) {
+        sink = _core_get_sink(dm->core, device_string, NULL);
+        if (sink)
+            pa_tz_profile_new_data_add_sink(data, role, sink);
+        else
+            pa_log_error("Failed to get matching sink for %s %s", role, device_string);
     }
 
-    dump_device_list_info(dm, PA_LOG_INFO);
-    return PA_HOOK_OK;
+    return 0;
 }
 
-static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_device_manager *dm) {
-    pa_assert(c);
-    pa_assert(sink);
-    pa_assert(sink->proplist);
-    pa_assert(dm);
+static int _fill_profile_new_data_sources(pa_tz_profile_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
+    pa_source *source;
+    char *device_string, *role;
+    void *state;
 
-    if (pulse_device_class_is_monitor(sink->proplist)) {
-        pa_log_debug("This device's class is monitor. Skip this");
-        return PA_HOOK_OK;
+    pa_assert(data);
+    pa_assert(type_info);
+
+    if (type_info->capture_devices == NULL) {
+        pa_log_error("No capture devices for %s %s", type_info->type, pa_strempty(type_info->profile));
+        return -1;
     }
 
-    pa_log_info("=========== Sink unlink Hook Callback '%s'(%d) ==========", sink->name, sink->index);
-    handle_sink_unloaded(sink, dm);
-    dump_device_list_info(dm, PA_LOG_INFO);
-    return PA_HOOK_OK;
+    PA_HASHMAP_FOREACH_KEY(device_string, type_info->capture_devices, state, role) {
+        source = _core_get_source(dm->core, device_string, NULL);
+        if (source)
+            pa_tz_profile_new_data_add_source(data, role, source);
+        else
+            pa_log_error("Failed to get matching source for %s %s", role, device_string);
+    }
+
+    return 0;
 }
 
-static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, pa_device_manager *dm) {
-    dm_device *device_item;
-    dm_device *_device_item;
-    bool use_internal_codec = false;
-    uint32_t idx = 0;
+static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
+    pa_hashmap *pcm_devices;
+    pa_idxset *file_infos;
+    void *state = NULL;
+    char *role;
+    const char *device_string, *params;
 
-    pa_assert(c);
-    pa_object_assert_ref(o);
     pa_assert(dm);
+    pa_assert(type_info);
 
-    if (pa_sink_isinstance(o)) {
-        pa_sink *s = PA_SINK(o);
-        pa_sink_state_t state = pa_sink_get_state(s);
-        pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
-        if (s->use_internal_codec) {
-            if (state == PA_SINK_SUSPENDED) {
-                PA_IDXSET_FOREACH(_device_item, dm->device_list, idx) {
-                    use_internal_codec = pa_device_manager_is_device_use_internal_codec(_device_item, DM_DEVICE_DIRECTION_OUT, DEVICE_ROLE_NORMAL);
-                    if (use_internal_codec)
-                        pa_device_manager_set_device_state(_device_item, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
-                }
-            }
-        } else {
-            if ((device_item = pa_device_manager_get_device_with_sink(s))) {
-                if (state == PA_SINK_RUNNING)
-                    pa_device_manager_set_device_state(device_item, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_ACTIVATED);
-                else if (state == PA_SINK_SUSPENDED)
-                    pa_device_manager_set_device_state(device_item, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
-            }
+    pa_log_info("Load type devices : %s %s %s", type_info->type, pa_strempty(type_info->profile),
+            is_playback ? "playback" : "capture");
+
+    if (is_playback) {
+        pcm_devices = type_info->playback_devices;
+        file_infos = dm->file_map->playback;
+    } else {
+        pcm_devices = type_info->capture_devices;
+        file_infos = dm->file_map->capture;
+    }
+
+    if (!pcm_devices || !file_infos) {
+        pa_log_error("No information to load");
+        return -1;
+    }
+
+    PA_HASHMAP_FOREACH_KEY(device_string, pcm_devices, state, role) {
+        params = _file_infos_get_param(file_infos, device_string, role);
+        /* Check duplicate load */
+        if (is_playback && _core_get_sink(dm->core, device_string, params)) {
+            pa_log_debug("Already loaded %s %s", device_string, params);
+            continue;
         }
-    } else if (pa_source_isinstance(o)) {
-        pa_source *s = PA_SOURCE(o);
-        pa_source_state_t state = pa_source_get_state(s);
-        pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
-        if (s->use_internal_codec) {
-            if (state == PA_SOURCE_SUSPENDED) {
-                PA_IDXSET_FOREACH(_device_item, dm->device_list, idx) {
-                    use_internal_codec = pa_device_manager_is_device_use_internal_codec(_device_item, DM_DEVICE_DIRECTION_IN, DEVICE_ROLE_NORMAL);
-                    if (use_internal_codec)
-                        pa_device_manager_set_device_state(_device_item, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
-                }
-            }
-        } else {
-            if ((device_item = pa_device_manager_get_device_with_source(s))) {
-                if (state == PA_SOURCE_RUNNING)
-                    pa_device_manager_set_device_state(device_item, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_ACTIVATED);
-                else if (state == PA_SOURCE_SUSPENDED)
-                    pa_device_manager_set_device_state(device_item, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
-            }
+        if (!is_playback && _core_get_source(dm->core, device_string, params)) {
+            pa_log_debug("Already loaded %s %s", device_string, params);
+            continue;
+        }
+        if (!(load_device(dm->core, is_playback, device_string, params))) {
+            pa_log_warn("load device failed %s %s", device_string, params);
         }
     }
 
-    return PA_HOOK_OK;
+    return 0;
 }
 
-static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
-    const char *device_string = NULL, *role = NULL, *device_string_removed_params = NULL;
-    struct device_file_info *file_info = NULL;
-    dm_device_class_t device_class;
+/*
+    Handle device connection detected through dbus.
+    First, update device-status hashmap.
+    And if correnspondent sink/sources for device_type exist, should make device and notify it.
+    Use [device_type->roles] mappings in sink/source for find proper sink/source.
+*/
+static void handle_device_connected(pa_device_manager *dm, const char *type, const char *device_profile,
+        const char *name, const char *system_id, device_detected_type_t detected_type) {
+    struct device_type_info *type_info;
+    pa_tz_device *device;
+    pa_tz_device_new_data data;
 
-    pa_assert(c);
-    pa_assert(source);
-    pa_assert(source->proplist);
     pa_assert(dm);
+    pa_assert(dm->device_status);
+    pa_assert(dm->device_list);
 
-    if (pulse_device_class_is_monitor(source->proplist)) {
-        pa_log_debug("This device's class is monitor. Skip this");
-        return PA_HOOK_OK;
-    }
+    pa_log_info("Device connected, type(%s) profile(%s) name(%s) system_id(%s) detected_type(%d)",
+            type, pa_strempty(device_profile), pa_strempty(name), pa_strempty(system_id), detected_type);
 
-    pa_log_info("========== Source Put Hook Callback '%s'(%d) ==========", source->name, source->index);
+    type_info = _device_manager_get_type_info(dm->type_infos, type, device_profile);
 
+    if (device_type_is_equal(type, device_profile, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO)) {
+        pa_tz_profile_new_data profile_data;
 
-    device_class = pulse_device_get_class(source, PA_DEVICE_TYPE_SOURCE);
-    pa_log_info("Device Class '%s'", device_class_to_string(device_class));
+        /* Use profile_new_data, because BT is multi profile type */
+        pa_tz_profile_new_data_init(&profile_data);
+        _fill_profile_new_data_basic(&profile_data, DEVICE_PROFILE_BT_SCO,
+                DM_DEVICE_DIRECTION_BOTH, true, dm);
 
-    if (!(device_string = pulse_device_get_device_string(source, PA_DEVICE_TYPE_SOURCE))) {
-        return PA_HOOK_OK;
-    } else {
-        pa_log_info("Device String '%s'", device_string);
-    }
+        _fill_profile_new_data_sinks(&profile_data, type_info, dm);
+        _fill_profile_new_data_sources(&profile_data, type_info, dm);
 
-    if (device_class == DM_DEVICE_CLASS_BT) {
-        handle_not_predefined_device(dm, source, PA_DEVICE_TYPE_SOURCE, device_class);
-    } else if ((file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
-        /* module's argument includes device-string(ex. device=hw:0,0 ),
-           but key params for device_types hashmap is not. */
-        if (!(device_string_removed_params = pulse_device_get_device_string_removed_argument(source, PA_DEVICE_TYPE_SOURCE))) {
-            pa_log_debug("argument null");
-            return PA_HOOK_OK;
-        }
-        if (!(role = device_file_info_get_role_with_params(file_info, device_string_removed_params))) {
-            pa_log_error("No role for %s", file_info->device_string);
-            return PA_HOOK_OK;
+        device = _device_list_get_device(dm, DEVICE_TYPE_BT, system_id);
+        if (device) {
+            /* Just add profile, if already exists */
+            pa_tz_device_add_profile(device, &profile_data, false);
+        } else {
+            /* Create new device with profile */
+
+            pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn);
+            pa_tz_device_new_data_set_type(&data, DEVICE_TYPE_BT);
+            pa_tz_device_new_data_set_name(&data, name);
+            pa_tz_device_new_data_set_system_id(&data, system_id);
+            pa_tz_device_new_data_add_profile(&data, &profile_data, true);
+
+            pa_tz_device_new(&data);
+            pa_tz_device_new_data_done(&data);
         }
+        pa_tz_profile_new_data_done(&profile_data);
+    } else if (device_type_is_equal(type, device_profile, DEVICE_TYPE_AUDIO_JACK, NULL)) {
+        dm_device_direction_t direction;
 
-        handle_predefined_device_loaded(source, PA_DEVICE_TYPE_SOURCE, device_class, device_string, role, dm);
-    } else {
-        pa_log_debug("Not-predefined device");
-        handle_not_predefined_device(dm, source, PA_DEVICE_TYPE_SOURCE, device_class);
-    }
+        if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P)
+            direction = DM_DEVICE_DIRECTION_BOTH;
+        else
+            direction = DM_DEVICE_DIRECTION_OUT;
+        pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
+        _fill_new_data_basic(&data, DEVICE_TYPE_AUDIO_JACK, direction, true, dm);
+        _fill_new_data_sinks(&data, type_info, dm);
+        _fill_new_data_sources(&data, type_info, dm);
+
+        pa_tz_device_new(&data);
+        pa_tz_device_new_data_done(&data);
+    } else if (device_type_is_equal(type, device_profile, DEVICE_TYPE_HDMI, NULL)) {
+        pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
+        _fill_new_data_basic(&data, DEVICE_TYPE_HDMI, DM_DEVICE_DIRECTION_OUT, true, dm);
+        _fill_new_data_sinks(&data, type_info, dm);
+
+        pa_tz_device_new(&data);
+        pa_tz_device_new_data_done(&data);
+    } else if (device_type_is_equal(type, device_profile, DEVICE_TYPE_FORWARDING, NULL)) {
+        pa_tz_device *spk_device;
+        pa_sink *spk_sink;
 
-    dump_device_list_info(dm, PA_LOG_INFO);
-    return PA_HOOK_OK;
-}
+        if (!(spk_device = _device_list_get_device(dm, DEVICE_TYPE_SPEAKER, NULL))) {
+            pa_log_error("Get speaker device failed");
+            return;
+        }
+        if (!(spk_sink = pa_tz_device_get_sink(spk_device, DEVICE_ROLE_NORMAL))) {
+            pa_log_error("Get speaker sink failed");
+            return;
+        }
 
-static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, pa_device_manager *dm) {
-    pa_assert(c);
-    pa_assert(source);
-    pa_assert(source->proplist);
-    pa_assert(dm);
+        pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
+        _fill_new_data_basic(&data, DEVICE_TYPE_FORWARDING, DM_DEVICE_DIRECTION_BOTH, true, dm);
+        pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_NORMAL, spk_sink);
+        pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_NORMAL, spk_sink->monitor_source);
 
-    if (pulse_device_class_is_monitor(source->proplist)) {
-        pa_log_debug("This device's class is monitor. Skip this");
-        return PA_HOOK_OK;
+        pa_tz_device_new(&data);
+        pa_tz_device_new_data_done(&data);
+    } else {
+        dm_device_direction_t direction;
+
+        direction = device_type_get_static_direction(type, device_profile);
+        if (direction != DM_DEVICE_DIRECTION_NONE) {
+            pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
+            _fill_new_data_basic(&data, type, direction, true, dm);
+            if (direction & DM_DEVICE_DIRECTION_OUT)
+                _fill_new_data_sinks(&data, type_info, dm);
+            if (direction & DM_DEVICE_DIRECTION_IN)
+                _fill_new_data_sources(&data, type_info, dm);
+
+            pa_tz_device_new(&data);
+            pa_tz_device_new_data_done(&data);
+        } else {
+            pa_log_error("Invalid case : not static direction");
+            return ;
+        }
     }
 
-    pa_log_info("========== Source unlink Hook Callback '%s'(%d) ==========", source->name, source->index);
-    handle_source_unloaded(source, dm);
-    dump_device_list_info(dm, PA_LOG_INFO);
-
-    return PA_HOOK_OK;
+    return ;
 }
 
 /*
-    Build params for load sink or source, and load it.
+    Handle device disconnection detected through dbus.
+    First, update device-status hashmap.
+    And if there is device which has the device_type, remove it.
 */
+static int handle_device_disconnected(pa_device_manager *dm, const char *type, const char *device_profile, const char *system_id) {
+    pa_tz_device *device;
+    uint32_t n_profile;
 
-static void* load_device(pa_core *c, pa_device_type_t pdt, const char *device_string, const char *device_params) {
-    const char *args = NULL;
-    const char *module_name;
-    pa_module *module;
-    pa_sink *sink;
-    pa_source *source;
-    uint32_t device_idx;
-    dm_device_class_t device_class;
-
-    pa_assert(c);
-    pa_assert(device_string);
-    pa_assert(device_params);
-
-    pa_log_info("Load %s Device : String'%s' Param'%s'", pdt == PA_DEVICE_TYPE_SINK ? "Playback" : "Capture", device_string, device_params);
+    pa_assert(dm);
+    pa_assert(dm->device_status);
 
-    device_class = device_string_get_class(device_string);
-    if (device_class <= DM_DEVICE_CLASS_NONE || device_class >= DM_DEVICE_CLASS_MAX) {
-        pa_log_warn("Invalid device_string '%s'", device_string);
-        return NULL;
-    }
+    pa_log_info("Device type(%s) profile(%s) system_id(%s) disconnected",
+            type, pa_strempty(device_profile), pa_strempty(system_id));
 
-    if (!(module_name = device_class_get_module_name(device_class, pdt))) {
-        pa_log_error("Get proper module name to load failed");
-        return NULL;
-    }
-    if (!(args = build_params_to_load_device(device_string, device_params, device_class))) {
-        pa_log_error("Get proper module name to load failed");
-        return NULL;
-    }
-    if (!(module = pa_module_load(c, module_name, args))) {
-        pa_log_error("Load module with name '%s' argu '%s' failed", module_name, args);
-        return NULL;
+    device = _device_list_get_device(dm, type, system_id);
+    if (!device) {
+        pa_log_error("Disconnection detected but no device for that");
+        return -1;
     }
 
+    if ((n_profile = pa_tz_device_get_profile_num(device)) > 1)
+        pa_tz_device_remove_profile(device, device_profile);
+    else
+        pa_tz_device_free(device);
 
-    if (pdt == PA_DEVICE_TYPE_SINK) {
-        PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
-            if (sink->module == module) {
-                return sink;
-            }
-        }
-    } else {
-        PA_IDXSET_FOREACH(source, c->sources, device_idx) {
-            if (source->module == module) {
-                return source;
-            }
-        }
-    }
-
-    return NULL;
+    return 0;
 }
 
-/*
-     Load sink/sources with information written in device-file map,
-    If there is several roles in same device-file, then first load with 'normal' params
-    and other roles with same params just reference it. if there is a role which is on same device
-    but have different params, then do not load it. (ex.uhqa)
-    This does not make device_item , just load sink or source.
-*/
 static int load_builtin_devices(pa_device_manager *dm) {
-    void *role_state = NULL;
-    struct device_file_info *file_info = NULL;
-    const char *params, *role;
-    uint32_t file_idx;
+    struct device_type_info *type_info;
+    uint32_t type_idx;
+    device_detected_type_t detected_type = DEVICE_CONNECTED;
+    const char *type, *profile;
 
     pa_assert(dm);
 
     pa_log_debug("\n==================== Load Builtin Devices ====================");
 
-    if (dm->file_map->playback) {
-        PA_IDXSET_FOREACH(file_info, dm->file_map->playback, file_idx) {
-            pa_log_debug("---------------- load sink for '%s' ------------------", file_info->device_string);
+    PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
 
-            /* if normal device exists , load first */
-            if ((params = pa_hashmap_get(file_info->roles, DEVICE_ROLE_NORMAL))) {
-                if (!load_device(dm->core, PA_DEVICE_TYPE_SINK, file_info->device_string, params))
-                    pa_log_error("load normal playback device failed");
-            }
+        type = type_info->type;
+        profile = type_info->profile;
 
-            PA_HASHMAP_FOREACH_KEY(params, file_info->roles, role_state, role) {
-                if (pa_streq(role, DEVICE_ROLE_NORMAL))
-                    continue;
-                pa_log_debug("load sink for role %s", role);
-                if (!pulse_device_loaded_with_param(dm->core, PA_DEVICE_TYPE_SINK, file_info->device_string, params)) {
-                    if (!load_device(dm->core, PA_DEVICE_TYPE_SINK, file_info->device_string, params))
-                        pa_log_error("load playback device failed");
-                }
-            }
+        pa_log_info("type_info : %s %s", type, pa_strempty(profile));
+        detected_type = _device_get_detected(dm, type, profile, NULL);
+        if (detected_type == DEVICE_DISCONNECTED) {
+            pa_log_info("Not detected yet");
+            continue;
         }
-    }
-
-    if (dm->file_map->capture) {
-        PA_IDXSET_FOREACH(file_info, dm->file_map->capture, file_idx) {
-            pa_log_debug("---------------- load source for '%s' ------------------", file_info->device_string);
 
-            /* if normal device exists , load first */
-            if ((params = pa_hashmap_get(file_info->roles, DEVICE_ROLE_NORMAL))) {
-                if (!load_device(dm->core, PA_DEVICE_TYPE_SOURCE, file_info->device_string, params)) pa_log_error("load normal capture device failed");
+        if (device_type_is_equal(type, profile, DEVICE_TYPE_AUDIO_JACK, NULL)) {
+            if (detected_type == DEVICE_CONNECTED_AUDIO_JACK_4P) {
+                _load_type_devices(type_info, true, dm);
+                _load_type_devices(type_info, false, dm);
+            } else {
+                _load_type_devices(type_info, true, dm);
             }
-
-            PA_HASHMAP_FOREACH_KEY(params, file_info->roles, role_state, role) {
-                if (pa_streq(role, DEVICE_ROLE_NORMAL))
-                    continue;
-                pa_log_debug("load source for role %s", role);
-                if (!pulse_device_loaded_with_param(dm->core, PA_DEVICE_TYPE_SOURCE, file_info->device_string, params)) {
-                    if (!load_device(dm->core, PA_DEVICE_TYPE_SOURCE, file_info->device_string, params)) {
-                        pa_log_error("load capture device failed");
-                    }
-                }
+            handle_device_connected(dm, type, profile, NULL, NULL, detected_type);
+        } else if (device_type_is_use_external_card(type, profile) == false) {
+            dm_device_direction_t direction;
+            direction = device_type_get_static_direction(type, profile);
+            if (direction == DM_DEVICE_DIRECTION_NONE) {
+                pa_log_warn("Wrong direction");
+                continue;
             }
+            if (direction & DM_DEVICE_DIRECTION_OUT)
+                _load_type_devices(type_info, true, dm);
+            if (direction & DM_DEVICE_DIRECTION_IN)
+                _load_type_devices(type_info, false, dm);
+            handle_device_connected(dm, type, profile, NULL, NULL, detected_type);
+        } else {
+            pa_log_warn("Invalid case");
         }
     }
 
     return 0;
 }
 
-
 /***************** Parse json file *******************/
 static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
     pa_hashmap *roles = NULL;
@@ -2836,7 +2063,7 @@ static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
     roles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     if (!roles) {
         pa_log_debug("hashmap new failed");
-        goto failed;
+        goto fail;
     }
 
     it = json_object_iter_begin(device_role_o);
@@ -2853,7 +2080,7 @@ static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
         if (device_role_is_valid(device_role)) {
             if (pa_hashmap_put(roles, (void *)device_role, (void *)params)) {
                 pa_log_error("put new role to hashmap faild");
-                goto failed;
+                goto fail;
             }
         } else {
             pa_log_error("Invalid device role '%s'", device_role);
@@ -2870,7 +2097,7 @@ static pa_hashmap* parse_device_role_object(json_object *device_role_o) {
 
     return roles;
 
-failed:
+fail:
     if (roles)
         pa_hashmap_free(roles);
 
@@ -2902,7 +2129,7 @@ static struct device_file_info* parse_device_file_object(json_object *device_fil
     if (json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
         if (!(roles = parse_device_role_object(device_file_prop_o))) {
             pa_log_error("Parse device role for '%s' failed", device_string);
-            goto failed;
+            goto fail;
         }
     } else {
         pa_log_error("Get device role object failed");
@@ -2917,7 +2144,7 @@ static struct device_file_info* parse_device_file_object(json_object *device_fil
 
     return file_info;
 
-failed:
+fail:
 
     return NULL;
 }
@@ -2941,11 +2168,11 @@ static pa_idxset* parse_device_file_array_object(json_object *device_file_array_
                 pa_idxset_put(device_files, file_info, NULL);
             } else {
                 pa_log_error("parse device file object failed");
-                goto failed;
+                goto fail;
             }
         } else {
             pa_log_error("Get device file object failed");
-            goto failed;
+            goto fail;
         }
     }
 
@@ -2953,8 +2180,10 @@ static pa_idxset* parse_device_file_array_object(json_object *device_file_array_
         pa_idxset_free(device_files, NULL);
         device_files = NULL;
     }
+
     return device_files;
-failed:
+
+fail:
     if (device_files)
         pa_xfree(device_files);
     return NULL;
@@ -3019,11 +2248,11 @@ static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
         if (device_role_is_valid(device_role)) {
             if (pa_hashmap_put(roles, (void *)device_role, (void *)device_string)) {
                 pa_log_error("put new role to hashmap faild");
-                goto failed;
+                goto fail;
             }
         } else {
             pa_log_error("Invalid device role '%s'", device_role);
-            goto failed;
+            goto fail;
         }
 
         json_object_iter_next(&it);
@@ -3031,7 +2260,7 @@ static pa_hashmap* parse_device_role_map(json_object *device_role_map_o) {
 
     return roles;
 
-failed:
+fail:
     if (roles)
         pa_xfree(roles);
 
@@ -3044,7 +2273,6 @@ static pa_idxset* parse_device_type_infos() {
     json_object *o, *device_array_o = NULL;
     int device_type_num = 0;
     int device_type_idx = 0;
-    json_bool builtin;
     struct device_type_info *type_info = NULL;
     //pa_hashmap *type_infos = NULL;
     pa_idxset *type_infos = NULL;
@@ -3065,16 +2293,16 @@ static pa_idxset* parse_device_type_infos() {
 
             if ((device_o = json_object_array_get_idx(device_array_o, device_type_idx)) && json_object_is_type(device_o, json_type_object)) {
                 json_object *device_prop_o;
-                const char *device_type = NULL, *device_profile = NULL;
+                const char *type = NULL, *device_profile = NULL;
                 type_info = pa_xmalloc0(sizeof(struct device_type_info));
 
                 if (json_object_object_get_ex(device_o, DEVICE_TYPE_PROP_DEVICE_TYPE, &device_prop_o) && json_object_is_type(device_prop_o, json_type_string)) {
-                    device_type = json_object_get_string(device_prop_o);
-                    pa_log_info("[ Device - %s ]", device_type);
-                    type_info->type = device_type;
+                    type = json_object_get_string(device_prop_o);
+                    pa_log_info("[ Device - %s ]", type);
+                    type_info->type = type;
                 } else {
                     pa_log_error("Get device type failed");
-                    goto failed;
+                    goto fail;
                 }
                 if (json_object_object_get_ex(device_o, "profile", &device_prop_o) && json_object_is_type(device_prop_o, json_type_string)) {
                     device_profile = json_object_get_string(device_prop_o);
@@ -3104,7 +2332,7 @@ static pa_idxset* parse_device_type_infos() {
     }
     return type_infos;
 
-failed:
+fail:
     if (type_infos)
         pa_xfree(type_infos);
 
@@ -3112,139 +2340,34 @@ failed:
 }
 
 /*
-    Handle device connection detected through dbus.
-    First, update device-status hashmap.
-    And if correnspondent sink/sources for device_type exist, should make device_item and notify it.
-    Use [device_type->roles] mappings in sink/source for find proper sink/source.
-*/
-static int handle_device_connected(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *name, const char *identifier, int detected_type) {
-    struct device_status_info *status_info;
-    struct device_type_info *type_info;
-    dm_device *device_item;
-    dm_device_profile *profile_item;
-
-    pa_assert(dm);
-    pa_assert(dm->device_status);
-
-    pa_log_info("Device %s connected, detected_type : %d", device_type, detected_type);
-    if (!(status_info = _device_manager_get_status_info(dm->device_status, device_type, device_profile, identifier))) {
-        pa_log_error("No device_status_info for %s.%s", device_type, device_profile);
-        return -1;
-    }
-    status_info->detected = DEVICE_DETECTED;
-    status_info->detected_type = detected_type;
-
-    if (!(type_info = _device_manager_get_type_info(dm->type_infos, device_type, device_profile))) {
-        pa_log_error("Failed to get type_info for %s.%s", device_type, device_profile);
-        return -1;
-    }
-
-    if ((device_item = _device_manager_get_device(dm->device_list, type_info->type))) {
-        if ((profile_item = _device_item_get_profile(device_item, type_info->profile))) {
-            pa_log_debug("device_item for %s.%s already exists", type_info->type, type_info->profile);
-            return 0;
-        }
-    }
-
-    handle_device_type_available(type_info, name, dm);
-
-    return 0;
-}
-
-/*
-    Handle device disconnection detected through dbus.
-    First, update device-status hashmap.
-    And if there is device_item which has the device_type, remove it.
-*/
-static int handle_device_disconnected(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *identifier) {
-    dm_device_profile *profile_item;
-    dm_device *device_item;
-    struct device_status_info *status_info;
-    uint32_t device_idx = 0;
-
-    pa_assert(dm);
-    pa_assert(dm->device_status);
-
-    pa_log_info("Device %s disconnected", device_type);
-    if (!(status_info = _device_manager_get_status_info(dm->device_status, device_type, device_profile, identifier))) {
-        pa_log_error("No device_status_info for %s.%s", device_type, device_profile);
-        return -1;
-    }
-    status_info->detected = DEVICE_NOT_DETECTED;
-
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        if (pa_streq(device_item->type, device_type)) {
-            if ((profile_item = _device_item_get_profile(device_item, device_profile))) {
-                if (_device_item_get_size(device_item) == 1) {
-                    _device_list_remove_device(dm->device_list, device_item, dm);
-                    notify_device_connection_changed(device_item, false, dm);
-                }
-                destroy_device_profile(profile_item, dm);
-            } else {
-                pa_log_debug("no matching profile");
-            }
-        }
-    }
-
-    return 0;
-}
-
-
-/*
    look detected status which is external value, make conversion to internal consistent value, and handle it
    device_type, device_profile : which type of device is detected
-   identifier : identifier among same device types for support multi-device
+   system_id : system_id among same device types for support multi-device
 */
-static int handle_device_status_changed(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *name, const char *identifier, int detected_status) {
+static int handle_device_status_changed(pa_device_manager *dm, const char *type,
+        const char *profile, const char *name, const char *system_id, device_detected_type_t detected) {
     pa_assert(dm);
-    pa_assert(device_type_is_valid(device_type));
-
-    pa_log_info("Device Status Changed, type : '%s', profile : '%s', identifier : '%s', detected_status : %d",
-            device_type, device_profile, identifier, detected_status);
-    if (pa_streq(device_type, DEVICE_TYPE_AUDIO_JACK)) {
-        if (detected_status == EARJACK_DISCONNECTED) {
-            handle_device_disconnected(dm, device_type, device_profile, identifier);
-        } else if (detected_status == EARJACK_TYPE_SPK_ONLY) {
-            handle_device_connected(dm, device_type, device_profile, name, identifier, DEVICE_DETECTED_AUDIO_JACK_OUT_DIREC);
-        } else if (detected_status == EARJACK_TYPE_SPK_WITH_MIC) {
-            handle_device_connected(dm, device_type, device_profile, name, identifier, DEVICE_DETECTED_AUDIO_JACK_BOTH_DIREC);
-        } else {
-            pa_log_warn("Got invalid audio-jack detected value");
-            return -1;
-        }
-    } else if (pa_streq(device_type, DEVICE_TYPE_BT) && device_profile && pa_streq(device_profile, DEVICE_PROFILE_BT_SCO)) {
-        if (detected_status == BT_SCO_DISCONNECTED) {
-            dm->bt_sco_status = DM_DEVICE_BT_SCO_STATUS_DISCONNECTED;
-        } else if (detected_status == BT_SCO_CONNECTED) {
-            dm->bt_sco_status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
-        } else {
-            pa_log_warn("Got invalid bt-sco detected value");
-            return -1;
-        }
-    } else if (pa_streq(device_type, DEVICE_TYPE_HDMI)) {
-        if (detected_status == HDMI_AUDIO_DISCONNECTED) {
-            handle_device_disconnected(dm, device_type, device_profile, identifier);
-        } else if (detected_status >= HDMI_AUDIO_AVAILABLE) {
-            handle_device_connected(dm, device_type, device_profile, name, identifier, DEVICE_DETECTED_HDMI);
-        } else if (detected_status == HDMI_AUDIO_NOT_AVAILABLE) {
-            pa_log_debug("HDMI audio not available");
-            return -1;
-        } else {
-            pa_log_warn("Got invalid hdmi detected value");
-            return -1;
-        }
-    } else if (pa_streq(device_type, DEVICE_TYPE_FORWARDING)) {
-        if (detected_status == FORWARDING_DISCONNECTED) {
-            handle_device_disconnected(dm, device_type, device_profile, identifier);
-        } else if (detected_status == FORWARDING_CONNECTED) {
-            handle_device_connected(dm, device_type, device_profile, name, identifier, DEVICE_DETECTED_FORWARDING);
-        } else {
-            pa_log_warn("Got invalid mirroring detected value");
-            return -1;
-        }
+    pa_assert(device_type_is_valid(type));
+
+    pa_log_info("Device Status Changed, type(%s) profile(%s) system_id(%s), detected_type(%d)",
+            type, pa_strempty(profile), pa_strempty(system_id), detected);
+
+    if (device_type_is_equal(type, profile, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO)) {
+        _device_set_detected(dm, type, profile, name, system_id, detected);
+        if (detected == DEVICE_DISCONNECTED)
+            handle_device_disconnected(dm, type, profile, system_id);
+        else
+            handle_device_connected(dm, type, profile, name, system_id, detected);
+    } else if (device_type_is_need_detect(type, profile)) {
+        _device_set_detected(dm, type, profile, name, system_id, detected);
+        if (detected == DEVICE_DISCONNECTED)
+            handle_device_disconnected(dm, type, profile, system_id);
+        else
+            handle_device_connected(dm, type, profile, name, system_id, detected);
     } else {
-        pa_log_debug("unknown device type");
+        pa_log_debug("No need to detect type %s %s", type, pa_strempty(profile));
     }
+
     return 0;
 }
 
@@ -3254,82 +2377,101 @@ static int handle_device_status_changed(pa_device_manager *dm, const char *devic
     So, if device_type is not detected through dbus, let's initialize them to detected. (ex. spk, rcv,...)
     If not, initialize to not detected.
 */
-static pa_idxset* device_type_status_init(pa_idxset *type_infos) {
-    int avail_cond_idx = 0, avail_cond_num = 0, correct_avail_cond = 0;
+static void device_type_status_init(pa_device_manager *manager) {
     struct device_type_info *type_info;
-    struct device_status_info *status_info;
-    pa_idxset *device_status;
     uint32_t type_idx;
+    const char *type, *profile;
 
-    pa_assert(type_infos);
+    pa_assert(manager);
+    pa_assert(manager->type_infos);
 
     pa_log_debug("\n==================== Init Device Status ====================");
 
-    device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-
-    PA_IDXSET_FOREACH(type_info, type_infos, type_idx) {
-        status_info = (struct device_status_info *) pa_xmalloc0(sizeof(struct device_status_info));
-        status_info->type = type_info->type;
-        status_info->profile = type_info->profile;
-        if (!compare_device_type(status_info->type, status_info->profile, DEVICE_TYPE_AUDIO_JACK, NULL)) {
+    PA_IDXSET_FOREACH(type_info, manager->type_infos, type_idx) {
+        type = type_info->type;
+        profile = type_info->profile;
+        if (device_type_is_equal(type, profile, DEVICE_TYPE_AUDIO_JACK, NULL)) {
             int earjack_status = 0;
             if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earjack_status) < 0) {
-                status_info->detected = DEVICE_NOT_DETECTED;
                 pa_log_error("Get earjack status failed");
-            } else if (earjack_status == EARJACK_DISCONNECTED) {
-                status_info->detected = DEVICE_NOT_DETECTED;
-            } else if (earjack_status == EARJACK_TYPE_SPK_ONLY) {
-                status_info->detected = DEVICE_DETECTED;
-                status_info->detected_type = DEVICE_DETECTED_AUDIO_JACK_OUT_DIREC;
-            } else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC) {
-                status_info->detected = DEVICE_DETECTED;
-                status_info->detected_type = DEVICE_DETECTED_AUDIO_JACK_BOTH_DIREC;
-            } else {
-                status_info->detected = DEVICE_NOT_DETECTED;
-                pa_log_warn("Unknown earjack status : %d", earjack_status);
+                continue;
             }
-        } else if (!compare_device_type(status_info->type, status_info->profile, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO)) {
-                status_info->detected = DEVICE_NOT_DETECTED;
-        } else if (!compare_device_type(status_info->type, status_info->profile, DEVICE_TYPE_HDMI, NULL)) {
-                status_info->detected = DEVICE_NOT_DETECTED;
-        } else if (!compare_device_type(status_info->type, status_info->profile, DEVICE_TYPE_FORWARDING, NULL)) {
+            if (earjack_status == EARJACK_TYPE_SPK_ONLY)
+                _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_3P);
+            else if (earjack_status == EARJACK_TYPE_SPK_WITH_MIC)
+                _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_CONNECTED_AUDIO_JACK_4P);
+            else if (earjack_status == EARJACK_DISCONNECTED)
+                _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_DISCONNECTED);
+            else
+                pa_log_warn("Unknown earjack status : %d", earjack_status);
+        } else if (device_type_is_equal(type, profile, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO)) {
+                _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_DISCONNECTED);
+        } else if (device_type_is_equal(type, profile, DEVICE_TYPE_HDMI, NULL)) {
+                _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_DISCONNECTED);
+        } else if (device_type_is_equal(type, profile, DEVICE_TYPE_FORWARDING, NULL)) {
             int miracast_wfd_status = 0;
             if (vconf_get_bool(VCONFKEY_MIRACAST_WFD_SOURCE_STATUS, &miracast_wfd_status) < 0) {
-                status_info->detected = DEVICE_NOT_DETECTED;
                 pa_log_error("Get mirroring status failed");
-            } else if (miracast_wfd_status == FORWARDING_DISCONNECTED) {
-                status_info->detected = DEVICE_NOT_DETECTED;
-            } else if (miracast_wfd_status == FORWARDING_CONNECTED) {
-                status_info->detected = DEVICE_DETECTED;
-                status_info->detected_type = DEVICE_DETECTED_FORWARDING;
-            } else {
-                status_info->detected = DEVICE_NOT_DETECTED;
-                pa_log_warn("Unknown mirroring status : %d", miracast_wfd_status);
+                continue;
             }
+            if (miracast_wfd_status == FORWARDING_CONNECTED)
+                _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_CONNECTED);
         } else {
-            status_info->detected = DEVICE_DETECTED;
+            _device_set_detected(manager, type, profile, NULL, NULL, DEVICE_CONNECTED);
         }
-
-        pa_log_debug("Set %-17s %s detected", type_info->type, (status_info->detected == DEVICE_DETECTED) ? "" : "not");
-        pa_idxset_put(device_status, status_info, NULL);
     }
-    return device_status;
+    return ;
 }
 
-static int device_list_init(pa_device_manager *dm) {
-    pa_assert(dm);
+#ifdef HAVE_DBUS
 
-    dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+static int _translate_external_value(const char *type, const char *profile, int value, device_detected_type_t *detected) {
+
+    if (!type || !detected) {
+        pa_log_error("Invalid Parameter for translate");
+        return -1;
+    }
+
+    if (device_type_is_equal(DEVICE_TYPE_AUDIO_JACK, NULL, type, profile)) {
+        if (value == EARJACK_DISCONNECTED)
+            *detected = DEVICE_DISCONNECTED;
+        else if (value == EARJACK_TYPE_SPK_ONLY)
+            *detected = DEVICE_CONNECTED_AUDIO_JACK_3P;
+        else if (value == EARJACK_TYPE_SPK_WITH_MIC)
+            *detected = DEVICE_CONNECTED_AUDIO_JACK_4P;
+        else
+            return -1;
+    } else if (device_type_is_equal(DEVICE_TYPE_HDMI, NULL, type, profile)) {
+        if (value == HDMI_AUDIO_DISCONNECTED)
+            *detected = DEVICE_DISCONNECTED;
+        else if (value == HDMI_AUDIO_AVAILABLE)
+            *detected = DEVICE_CONNECTED;
+        else
+            return -1;
+    } else if (device_type_is_equal(DEVICE_TYPE_FORWARDING, NULL, type, profile)) {
+        if (value == FORWARDING_DISCONNECTED)
+            *detected = DEVICE_DISCONNECTED;
+        else if (value == FORWARDING_CONNECTED)
+            *detected = DEVICE_CONNECTED;
+        else
+            return -1;
+    } else if (device_type_is_equal(DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO, type, profile)) {
+        if (value == BT_SCO_DISCONNECTED)
+            *detected = DEVICE_DISCONNECTED;
+        else if (value == BT_SCO_CONNECTED)
+            *detected = DEVICE_CONNECTED_SCO;
+        else
+            return -1;
+    }
 
     return 0;
 }
 
-#ifdef HAVE_DBUS
-
 static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
     DBusError error;
     int status = 0;
     pa_device_manager *dm = (pa_device_manager *) userdata;
+    device_detected_type_t detected;
 
     pa_assert(userdata);
 
@@ -3345,19 +2487,31 @@ static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DB
         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
             goto fail;
         } else {
-            handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, NULL, status);
+            if (_translate_external_value(DEVICE_TYPE_AUDIO_JACK, NULL, status, &detected) < 0) {
+                pa_log_warn("failed to translate audio-jack detected value");
+                goto fail;
+            }
+            handle_device_status_changed(dm, DEVICE_TYPE_AUDIO_JACK, NULL, NULL, NULL, detected);
         }
     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_DEVICED_SYSNOTI, "ChangedHDMIAudio")) {
         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
             goto fail;
         } else {
-            handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, NULL, status);
+            if (_translate_external_value(DEVICE_TYPE_HDMI, NULL, status, &detected) < 0) {
+                pa_log_warn("failed to translate HDMI detected value");
+                goto fail;
+            }
+            handle_device_status_changed(dm, DEVICE_TYPE_HDMI, NULL, NULL, NULL, detected);
         }
     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_MIRRORING_SERVER, "miracast_wfd_source_status_changed")) {
         if (!dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &status, DBUS_TYPE_INVALID)) {
             goto fail;
         } else {
-            handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, NULL, status);
+            if (_translate_external_value(DEVICE_TYPE_FORWARDING, NULL, status, &detected) < 0) {
+                pa_log_warn("failed to translate forwarding detected value");
+                goto fail;
+            }
+            handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, NULL, detected);
         }
     } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) {
         DBusMessageIter msg_iter, variant_iter;
@@ -3396,7 +2550,12 @@ static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DB
                 } else {
                     status = BT_SCO_DISCONNECTED;
                 }
-                handle_device_status_changed(dm, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO, name, NULL, status);
+                if (_translate_external_value(DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO, status, &detected) < 0) {
+                    pa_log_warn("failed to translate bt-sco detected value");
+                    goto fail;
+                }
+                handle_device_status_changed(dm, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO,
+                        name, dbus_message_get_path(s),  detected);
             }
         }
     } else {
@@ -3453,129 +2612,99 @@ static void unwatch_signals(pa_device_manager *dm) {
 }
 
 
-static void send_device_connected_signal(uint32_t event_id, dm_device *device_item, bool connected, pa_device_manager *dm) {
+static void send_device_connected_signal(uint32_t event_id, pa_tz_device *device, bool connected, pa_device_manager *dm) {
     DBusMessage *signal_msg;
     DBusMessageIter msg_iter, device_iter;
-    dm_device_profile *profile_item;
     dbus_bool_t _connected = connected;
     dm_device_state_t compound_state;
-    dbus_int32_t device_id;
-    const char *device_info_str;
+    dbus_int32_t device_id, direction;
+    char *type, *name;
 
-    pa_assert(device_item);
-    pa_assert(device_item->profiles);
+    pa_assert(device);
     pa_assert(dm);
 
     pa_log_info("Send following device %s signal", connected ? "Connected" : "Disconnected");
-    dump_device_info(device_item, PA_LOG_INFO);
 
     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceConnected"));
     dbus_message_iter_init_append(signal_msg, &msg_iter);
     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
-    if (!(profile_item = _device_item_get_active_profile(device_item))) {
-        pa_log_error("active profile null");
-        goto finish;
-    }
 
-    device_id = (dbus_int32_t) device_item->id;
-    compound_state = COMPOUND_STATE(profile_item);
+    direction = (dbus_int32_t) pa_tz_device_get_direction(device);
+    type = pa_tz_device_get_type(device);
+    name = pa_tz_device_get_name(device);
+
+    device_id = (dbus_int32_t) pa_tz_device_get_id(device);
+    compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
-    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &device_item->type);
-    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &profile_item->direction);
+    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
+    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
-    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &device_item->name);
+    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &_connected);
 
     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
-finish:
+
     dbus_message_unref(signal_msg);
 }
 
-static void send_device_info_changed_signal(uint32_t event_id, dm_device *device_item, int changed_type, pa_device_manager *dm) {
+static void send_device_info_changed_signal(uint32_t event_id, pa_tz_device *device, int changed_type, pa_device_manager *dm) {
     DBusMessage *signal_msg;
     DBusMessageIter msg_iter, device_iter;
-    dm_device_profile *profile_item;
     dm_device_state_t compound_state;
-    dbus_int32_t device_id;
-    const char *device_info_str;
+    dbus_int32_t device_id, direction;
+    char *type, *name;
 
-    pa_assert(device_item);
-    pa_assert(device_item->profiles);
+    pa_assert(device);
     pa_assert(dm);
 
     pa_log_debug("Send following device info changed signal");
-    dump_device_info(device_item, PA_LOG_DEBUG);
 
     pa_assert_se(signal_msg = dbus_message_new_signal(DBUS_OBJECT_DEVICE_MANAGER, DBUS_INTERFACE_DEVICE_MANAGER, "DeviceInfoChanged"));
     dbus_message_iter_init_append(signal_msg, &msg_iter);
     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &event_id);
     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
-    if (!(profile_item = _device_item_get_active_profile(device_item))) {
-        pa_log_error("active profile null");
-        goto finish;
-    }
-    device_id = (dbus_int32_t) device_item->id;
-    compound_state = COMPOUND_STATE(profile_item);
+
+    direction = (dbus_int32_t) pa_tz_device_get_direction(device);
+    type = pa_tz_device_get_type(device);
+    name = pa_tz_device_get_name(device);
+    device_id = (dbus_int32_t) pa_tz_device_get_id(device);
+    compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
+
     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
-    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &device_item->type);
-    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &profile_item->direction);
+    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
+    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
     dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
-    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &device_item->name);
+    dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &device_iter));
     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &changed_type);
 
     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(dm->dbus_conn), signal_msg, NULL));
-finish:
-    dbus_message_unref(signal_msg);
-}
-
-static void notify_device_connection_changed(dm_device *device_item, bool connected, pa_device_manager *dm) {
-    pa_device_manager_hook_data_for_conn_changed hook_data;
-    uint32_t event_id;
 
-    event_id = _new_event_id();
-
-    hook_data.event_id = event_id;
-    hook_data.is_connected = connected;
-    hook_data.device = device_item;
-    pa_log_info("notify_device_connection_changed");
-    pa_hook_fire(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), &hook_data);
-    send_device_connected_signal(event_id, device_item, connected, dm);
-}
-
-static void notify_device_info_changed(dm_device *device_item, dm_device_changed_info_t changed_type, pa_device_manager *dm) {
-    pa_device_manager_hook_data_for_info_changed hook_data;
-    uint32_t event_id;
-
-    event_id = _new_event_id();
-
-    send_device_info_changed_signal(event_id, device_item, changed_type, dm);
-
-    hook_data.event_id = event_id;
-    hook_data.changed_info = changed_type;
-    hook_data.device = device_item;
-    pa_hook_fire(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED), &hook_data);
+    dbus_message_unref(signal_msg);
 }
 
-static bool device_item_match_for_mask(dm_device *device_item, int device_flags, pa_device_manager *dm) {
-    dm_device_profile *profile_item = NULL;
+static bool device_item_match_for_mask(pa_tz_device *device, int device_flags, pa_device_manager *dm) {
     bool match = false;
     int need_to_check_for_io_direction = device_flags & DEVICE_IO_DIRECTION_FLAGS;
     int need_to_check_for_state = device_flags & DEVICE_STATE_FLAGS;
     int need_to_check_for_type = device_flags & DEVICE_TYPE_FLAGS;
+    dm_device_direction_t direction;
+    char *type;
 
-    pa_assert(device_item);
+    pa_assert(device);
 
     if (device_flags == DEVICE_ALL_FLAG)
         return true;
 
-    profile_item = _device_item_get_active_profile(device_item);
+    direction = pa_tz_device_get_direction(device);
+    type = pa_tz_device_get_type(device);
+
     if (need_to_check_for_io_direction) {
-        if ((profile_item->direction == DM_DEVICE_DIRECTION_IN) && (device_flags & DEVICE_IO_DIRECTION_IN_FLAG)) match = true;
-        else if ((profile_item->direction == DM_DEVICE_DIRECTION_OUT) && (device_flags & DEVICE_IO_DIRECTION_OUT_FLAG)) match = true;
-        else if ((profile_item->direction == DM_DEVICE_DIRECTION_BOTH) && (device_flags & DEVICE_IO_DIRECTION_BOTH_FLAG)) match = true;
+        if ((direction == DM_DEVICE_DIRECTION_IN) && (device_flags & DEVICE_IO_DIRECTION_IN_FLAG)) match = true;
+        else if ((direction == DM_DEVICE_DIRECTION_OUT) && (device_flags & DEVICE_IO_DIRECTION_OUT_FLAG)) match = true;
+        else if ((direction == DM_DEVICE_DIRECTION_BOTH) && (device_flags & DEVICE_IO_DIRECTION_BOTH_FLAG)) match = true;
         if (match) {
             if (!need_to_check_for_state && !need_to_check_for_type) return true;
         } else {
@@ -3584,9 +2713,9 @@ static bool device_item_match_for_mask(dm_device *device_item, int device_flags,
     }
     if (need_to_check_for_state) {
         match = false;
-        if ((COMPOUND_STATE(profile_item) == DM_DEVICE_STATE_DEACTIVATED) && (device_flags & DEVICE_STATE_DEACTIVATED_FLAG))
+        if ((pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH) == DM_DEVICE_STATE_DEACTIVATED) && (device_flags & DEVICE_STATE_DEACTIVATED_FLAG))
             match = true;
-        else if ((COMPOUND_STATE(profile_item) == DM_DEVICE_STATE_ACTIVATED) && (device_flags & DEVICE_STATE_ACTIVATED_FLAG))
+        else if ((pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH) == DM_DEVICE_STATE_ACTIVATED) && (device_flags & DEVICE_STATE_ACTIVATED_FLAG))
             match = true;
         if (match) {
             if (!need_to_check_for_type)
@@ -3596,104 +2725,15 @@ static bool device_item_match_for_mask(dm_device *device_item, int device_flags,
         }
     }
     if (need_to_check_for_type) {
-        if (device_type_is_builtin(device_item->type) && (device_flags & DEVICE_TYPE_INTERNAL_FLAG))
+        if (device_type_is_builtin(type) && (device_flags & DEVICE_TYPE_INTERNAL_FLAG))
             return true;
-        else if (!device_type_is_builtin(device_item->type) && (device_flags & DEVICE_TYPE_EXTERNAL_FLAG))
+        else if (!device_type_is_builtin(type) && (device_flags & DEVICE_TYPE_EXTERNAL_FLAG))
             return true;
     }
 
     return false;
 }
 
-
-static int method_call_bt_sco(DBusConnection *conn, bool onoff) {
-    DBusMessage *msg, *reply;
-    DBusError err;
-    const char *method;
-
-    method = onoff ? "Play" : "Stop";
-    if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
-        pa_log_error("dbus method call failed");
-        return -1;
-    }
-
-    dbus_error_init(&err);
-    if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
-        pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
-        dbus_error_free(&err);
-        return -1;
-    }
-
-    dbus_message_unref(reply);
-    return 0;
-}
-
-static int method_call_bt_sco_get_property(DBusConnection *conn, bool *is_wide_band, bool *nrec) {
-    DBusMessage *msg, *reply;
-    DBusMessageIter reply_iter, reply_iter_entry;
-    DBusError err;
-    unsigned int codec;
-    const char *property;
-
-    pa_assert(conn);
-
-    if (!is_wide_band && !nrec) {
-        return -1;
-    }
-
-    if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, "GetProperties"))) {
-        pa_log_error("dbus method call failed");
-        return -1;
-    }
-
-    dbus_error_init(&err);
-    if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
-        pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, "GetProperties", err.message);
-        dbus_error_free(&err);
-        return -1;
-    }
-
-    dbus_message_iter_init(reply,  &reply_iter);
-
-    if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
-        pa_log_error("Cannot get reply argument");
-        return -1;
-    }
-
-    dbus_message_iter_recurse(&reply_iter,  &reply_iter_entry);
-
-    while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) {
-        DBusMessageIter dict_entry, dict_entry_val;
-        dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
-        dbus_message_iter_get_basic(&dict_entry, &property);
-        pa_log_debug("String received = %s", property);
-        if (property) {
-            if (pa_streq("codec", property) && is_wide_band) {
-                dbus_message_iter_next(&dict_entry);
-                dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
-                if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_UINT32)
-                    continue;
-                dbus_message_iter_get_basic(&dict_entry_val, &codec);
-                pa_log_debug("Codec = [%d]", codec);
-                *is_wide_band = (codec == BT_MSBC_CODEC_ID) ? true : false;
-            } else if (pa_streq("nrec", property) && nrec) {
-                dbus_message_iter_next(&dict_entry);
-                dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
-                if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_BOOLEAN)
-                    continue;
-                dbus_message_iter_get_basic(&dict_entry_val, nrec);
-                pa_log_debug("nrec= [%d]", *nrec);
-            }
-        }
-        dbus_message_iter_next(&reply_iter_entry);
-    }
-
-
-    dbus_message_unref(reply);
-    return 0;
-}
-
-
 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) {
     const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias";
     DBusMessage *msg, *reply;
@@ -3743,12 +2783,12 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *
     pa_device_manager *dm;
     DBusMessage *reply = NULL;
     DBusMessageIter msg_iter, array_iter, device_iter;
-    dm_device *device_item;
-    dm_device_profile *profile_item;
+    pa_tz_device *device;
     dm_device_state_t compound_state;
     uint32_t device_idx;
-    dbus_int32_t device_id;
+    dbus_int32_t device_id, direction;
     int mask_flags;
+    char *type, *name;
 
     pa_assert(conn);
     pa_assert(msg);
@@ -3767,20 +2807,19 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *
     dbus_message_iter_init_append(reply, &msg_iter);
     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiis)", &array_iter));
 
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        if (!(profile_item = pa_idxset_get_by_index(device_item->profiles, device_item->active_profile))) {
-            pa_log_error("no active profile");
-            continue;
-        }
-        compound_state = COMPOUND_STATE(profile_item);
-        if (device_item_match_for_mask(device_item,  mask_flags, dm)) {
-            device_id = (dbus_int32_t)device_item->id;
+    PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
+        compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
+        direction = pa_tz_device_get_direction(device);
+        type = pa_tz_device_get_type(device);
+        name = pa_tz_device_get_name(device);
+        if (device_item_match_for_mask(device,  mask_flags, dm)) {
+            device_id = (dbus_int32_t)pa_tz_device_get_id(device);
             pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
-            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &profile_item->device_item->type);
-            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &profile_item->direction);
+            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
+            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
-            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &device_item->name);
+            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
             pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
         }
     }
@@ -3795,8 +2834,7 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *
 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_device_manager *dm;
     DBusMessage *reply = NULL;
-    dm_device *device_item;
-    dm_device_profile *profile_item;
+    pa_tz_device *device;
     dbus_bool_t is_bt_on = false;
     const char *bt_name = "none";
 
@@ -3810,10 +2848,11 @@ static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, vo
 
     pa_assert_se((reply = dbus_message_new_method_return(msg)));
 
-    if ((device_item = _device_manager_get_device(dm->device_list, DEVICE_TYPE_BT)) != NULL) {
-        if ((profile_item = _device_item_get_profile(device_item, DEVICE_PROFILE_BT_A2DP)) != NULL) {
+    /* FIXME : Give system_id for multi device */
+    if ((device = _device_list_get_device(dm, DEVICE_TYPE_BT, NULL)) != NULL) {
+        if (pa_tz_device_have_profile(device, DEVICE_PROFILE_BT_A2DP)) {
             is_bt_on = true;
-            bt_name = device_item->name;
+            bt_name = pa_tz_device_get_name(device);
         }
     }
 
@@ -3829,27 +2868,27 @@ static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, vo
 
 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_device_manager *dm;
-    char *device_type, *device_profile, *role;
+    char *type, *device_profile, *role;
     DBusMessage *reply = NULL;
 
     pa_assert_se((reply = dbus_message_new_method_return(msg)));
     dm = (pa_device_manager *) userdata;
     pa_assert_se(dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &device_type,
+                                       DBUS_TYPE_STRING, &type,
                                        DBUS_TYPE_STRING, &device_profile,
                                        DBUS_TYPE_STRING, &role,
                                        DBUS_TYPE_INVALID));
 
     if (pa_streq(device_profile, "none"))
         device_profile = NULL;
-    pa_device_manager_load_sink(dm, device_type, device_profile, role);
+    pa_device_manager_load_sink(dm, type, device_profile, role);
     pa_assert_se(dbus_connection_send(conn, reply, NULL));
     dbus_message_unref(reply);
 }
 
 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_device_manager *dm = (pa_device_manager *)userdata;
-    char *device_type, *device_profile;
+    char *type, *device_profile;
     dbus_int32_t status;
     DBusMessage *reply = NULL;
     DBusError error;
@@ -3858,7 +2897,7 @@ static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *
 
     dbus_error_init(&error);
     if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &device_type,
+                                       DBUS_TYPE_STRING, &type,
                                        DBUS_TYPE_STRING, &device_profile,
                                        DBUS_TYPE_INT32, &status,
                                        DBUS_TYPE_INVALID)) {
@@ -3867,11 +2906,11 @@ static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *
         dbus_error_free(&error);
     }
 
-    pa_log_debug("handle_test_device_status_change, type:%s, profile:%s, status:%d", device_type, device_profile, status);
+    pa_log_debug("handle_test_device_status_change, type:%s, profile:%s, status:%d", type, device_profile, status);
     if (pa_streq(device_profile, "none"))
         device_profile = NULL;
 
-    handle_device_status_changed(dm, device_type, device_profile, NULL,  NULL, status);
+    handle_device_status_changed(dm, type, device_profile, NULL,  NULL, status);
     pa_assert_se(dbus_connection_send(conn, reply, NULL));
     dbus_message_unref(reply);
 }
@@ -4024,361 +3063,158 @@ pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm) {
     return dm->device_list;
 }
 
-dm_device* pa_device_manager_get_device(pa_device_manager *dm, const char *device_type) {
+pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *type) {
     pa_assert(dm);
 
-    return _device_manager_get_device(dm->device_list, device_type);
+    return _device_list_get_device(dm, type, NULL);
 }
 
-dm_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
+pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id) {
     pa_assert(dm);
 
-    return _device_manager_get_device_with_id(dm->device_list, id);
-}
-
-pa_sink* pa_device_manager_get_sink(dm_device *device_item, const char *role) {
-    dm_device_profile *profile_item;
-    pa_sink *sink;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    if (!profile_item->playback_devices) {
-        pa_log_debug("No playback device in %s", device_item->name);
-        return NULL;
-    }
-    if ((sink = pa_hashmap_get(profile_item->playback_devices, role)))
-        pa_log_debug("Got sink[%s] for [%s] role", sink->name, role);
-    else {
-        sink = pa_hashmap_get(profile_item->playback_devices, DEVICE_ROLE_NORMAL);
-        pa_log_debug("Could not get sink for [%s] role. so get sink[%s] for normal role", role, sink->name);
-    }
-
-    return sink;
-}
-
-pa_source* pa_device_manager_get_source(dm_device *device_item, const char *role) {
-    dm_device_profile *profile_item;
-    pa_source *source;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    if (!profile_item->capture_devices) {
-        pa_log_debug("No capture device in %s", device_item->name);
-        return NULL;
-    }
-
-    if ((source = pa_hashmap_get(profile_item->capture_devices, role)))
-        pa_log_debug("Got source[%s] for [%s] role", source->name, role);
-    else
-        pa_log_warn("Could not get source for [%s] role", role);
-
-    return source;
+    return _device_list_get_device_with_id(dm, id);
 }
 
-dm_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
+pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
     pa_assert(sink);
 
     return sink->device_item;
 }
 
-dm_device* pa_device_manager_get_device_with_source(pa_source *source) {
+pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source) {
     pa_assert(source);
 
     return source->device_item;
 }
 
-void pa_device_manager_set_device_state(dm_device *device_item, dm_device_direction_t direction, dm_device_state_t state) {
-    dm_device_profile *profile_item;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    pa_log_info("pa_device_manager_set_device_state : %s.%s  direction %s -> %d", device_item->type, profile_item->profile, device_direction_to_string(direction), state);
-    _device_profile_set_state(profile_item, direction, state);
-}
-
-dm_device_state_t pa_device_manager_get_device_state(dm_device *device_item, dm_device_direction_t direction) {
-    dm_device_profile *profile_item;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    if (direction == DM_DEVICE_DIRECTION_BOTH)
-        return COMPOUND_STATE(profile_item);
-    else if (direction == DM_DEVICE_DIRECTION_OUT)
-        return profile_item->playback_state;
-    else if (direction == DM_DEVICE_DIRECTION_IN)
-        return profile_item->capture_state;
-    else
-        return DM_DEVICE_STATE_DEACTIVATED;
-}
-
-uint32_t pa_device_manager_get_device_id(dm_device *device_item) {
-    pa_assert(device_item);
-
-    return device_item->id;
-}
-
-const char* pa_device_manager_get_device_type(dm_device *device_item) {
-    pa_assert(device_item);
-
-    return device_item->type;
-}
-
-const char* pa_device_manager_get_device_subtype(dm_device *device_item) {
-    dm_device_profile *profile_item;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    return profile_item->profile;
-}
-
-dm_device_direction_t pa_device_manager_get_device_direction(dm_device *device_item) {
-    dm_device_profile *profile_item;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    return profile_item->direction;
-}
-
-pa_usec_t pa_device_manager_get_device_creation_time(dm_device *device_item) {
-    dm_device_profile *profile_item;
-
-    pa_assert(device_item);
-    pa_assert(profile_item = _device_item_get_active_profile(device_item));
-
-    return profile_item->creation_time;
-}
-
-bool pa_device_manager_is_device_use_internal_codec(dm_device *device_item, dm_device_direction_t direction, const char *role) {
-    pa_sink *sink;
-    pa_source *source;
-    bool use_internal_codec = false;
-
-    pa_assert(device_item);
-    pa_assert(role);
-
-    if (direction == DM_DEVICE_DIRECTION_IN) {
-        if ((source = pa_device_manager_get_source(device_item, role)))
-            use_internal_codec = source->use_internal_codec;
-    } else if (direction == DM_DEVICE_DIRECTION_OUT) {
-        if ((sink = pa_device_manager_get_sink(device_item, role)))
-            use_internal_codec = sink->use_internal_codec;
-    } else if (direction == DM_DEVICE_DIRECTION_BOTH) {
-        if ((sink = pa_device_manager_get_sink(device_item, role)) && (source = pa_device_manager_get_source(device_item, role)))
-            use_internal_codec = sink->use_internal_codec & source->use_internal_codec;
-    } else {
-        pa_log_warn("invalid direction");
-    }
-
-    return use_internal_codec;
-}
-
-int pa_device_manager_bt_sco_open(pa_device_manager *dm) {
-    dm_device *bt_device;
-
-    pa_assert(dm);
-    pa_assert(dm->dbus_conn);
-
-    if (dm->bt_sco_status != DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
-        pa_log_error("BT SCO Not Connected");
-        return -1;
-    }
-
-    if ((bt_device = _device_manager_get_device(dm->device_list, DEVICE_TYPE_BT)) == NULL) {
-        pa_log_error("No BT Device");
-        return -1;
-    }
-
-    pa_log_info("BT SCO Open - Request to BT FW");
-    if (method_call_bt_sco(pa_dbus_connection_get(dm->dbus_conn), true) < 0) {
-        pa_log_error("Failed to bt sco on");
-        return -1;
-    }
-    pa_log_info("BT SCO Open - SUCCESS");
-
-    dm->bt_sco_status = DM_DEVICE_BT_SCO_STATUS_OPENED;
-    handle_device_connected(dm, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO, NULL, NULL, DEVICE_DETECTED_BT_SCO);
-
-    return 0;
-}
-
-void pa_device_manager_bt_sco_get_status(pa_device_manager *dm, dm_device_bt_sco_status_t *status) {
-    pa_assert(dm);
-    pa_assert(status);
-
-    pa_log_info("BT SCO get status %d", dm->bt_sco_status);
-    *status = dm->bt_sco_status;
-
-    return;
-}
-
-int pa_device_manager_bt_sco_close(pa_device_manager *dm) {
-    dm_device *bt_device;
-
-    pa_assert(dm);
-    pa_assert(dm->dbus_conn);
-
-
-    if (dm->bt_sco_status != DM_DEVICE_BT_SCO_STATUS_OPENED) {
-        pa_log_error("BT SCO Not Opened");
-        return -1;
-    }
-
-    if ((bt_device = _device_manager_get_device(dm->device_list, DEVICE_TYPE_BT)) == NULL) {
-        pa_log_error("No BT Device");
-        return -1;
-    }
-
-    pa_log_info("BT SCO Close - Request to BT FW");
-    if (method_call_bt_sco(pa_dbus_connection_get(dm->dbus_conn), false) < 0) {
-        pa_log_error("Failed to BT SCO Close");
-        return -1;
-    }
-    pa_log_info("BT SCO Close - Success");
-
-    dm->bt_sco_status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
-    handle_device_disconnected(dm, DEVICE_TYPE_BT, DEVICE_PROFILE_BT_SCO, NULL);
-
-
-    return 0;
-}
-
-int pa_device_manager_bt_sco_get_property(pa_device_manager *dm, bool *is_wide_band, bool *nrec) {
-    pa_assert(dm);
-    pa_assert(dm->dbus_conn);
-
-    pa_log_info("BT SCO Get Property - Request to BT FW");
-
-    if (method_call_bt_sco_get_property(pa_dbus_connection_get(dm->dbus_conn), is_wide_band, nrec) < 0) {
-        pa_log_error("Failed to get BT SCO Property");
-        return -1;
-    }
-
-    pa_log_info("BT SCO Get Property - Success, is wide band : %s, nrec : %s", pa_yes_no(is_wide_band), pa_yes_no(nrec));
-
-    return 0;
-}
-
-int pa_device_manager_load_sink(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *role) {
+int pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *device_profile, const char *role) {
     const char *device_string, *params;
     struct device_type_info *type_info;
     struct device_file_info *file_info;
-    dm_device_profile *profile_item;
-    dm_device *device_item;
+    pa_tz_device *device;
     pa_sink *sink;
     uint32_t device_idx;
 
     pa_assert(dm);
     pa_assert(dm->device_list);
 
-    pa_log_info("Load Sink for '%s.%s.%s'", device_type, device_profile, role);
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        if (pa_streq(device_type, device_item->type)) {
-            if ((profile_item = _device_item_get_profile(device_item, device_profile))) {
-                if (pa_hashmap_get(profile_item->playback_devices, role)) {
-                    pa_log_warn("Proper sink for '%s.%s.%s' already loaded", device_type, device_profile, role);
-                    return -1;
-                }
+    pa_log_info("Load Sink for '%s.%s.%s'", type, device_profile, role);
+    PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
+        if (pa_streq(type, pa_tz_device_get_type(device))) {
+            if (pa_tz_device_profile_get_sink(device, device_profile, role) == NULL) {
+                pa_log_warn("Proper sink for '%s.%s.%s' already loaded", type, device_profile, role);
+                return -1;
             }
         }
     }
 
-    if (!(type_info = _device_manager_get_type_info(dm->type_infos, device_type, device_profile))) {
-        pa_log_error("No type map for %s", device_type);
+    if (!(type_info = _device_manager_get_type_info(dm->type_infos, type, device_profile))) {
+        pa_log_error("No type map for %s", type);
         return -1;
     }
 
+    if (type_info->playback_devices == NULL) {
+        pa_log_error("No playback devices for %s %s", type_info->type, pa_strempty(type_info->profile));
+        goto fail;
+    }
+
     if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
-        pa_log_error("No device-string for '%s.%s.%s'", device_type, device_profile, role);
-        goto failed;
+        pa_log_error("No device-string for '%s.%s.%s'", type, device_profile, role);
+        goto fail;
     }
 
     if (!(file_info = _device_manager_get_file_info(dm->file_map->playback, device_string))) {
         pa_log_error("No playback file-map for '%s'", device_string);
-        goto failed;
+        goto fail;
     }
 
     if (!(params = pa_hashmap_get(file_info->roles, role))) {
         pa_log_error("No params for '%s,%s'", device_string, role);
-        goto failed;
+        goto fail;
     }
 
     if ((sink = load_device(dm->core, PA_DEVICE_TYPE_SINK, device_string, params))) {
-        pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, device_type, role);
+        pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
     } else {
         pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
-        goto failed;
+        goto fail;
     }
 
     return 0;
 
-failed:
+fail:
     return -1;
 }
 
-int pa_device_manager_load_source(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *role) {
+int pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *device_profile, const char *role) {
     const char *device_string, *params;
     struct device_type_info *type_info;
     struct device_file_info *file_info;
-    dm_device_profile *profile_item;
-    dm_device *device_item;
+    pa_tz_device *device;
     pa_source *source;
     uint32_t device_idx;
 
     pa_assert(dm);
 
-    pa_log_info("Load Source for '%s.%s.%s'", device_type, device_profile, role);
+    pa_log_info("Load Source for '%s.%s.%s'", type, device_profile, role);
 
-    PA_IDXSET_FOREACH(device_item, dm->device_list, device_idx) {
-        if (pa_streq(device_type, device_item->type)) {
-            if ((profile_item = _device_item_get_profile(device_item, device_profile))) {
-                if (pa_hashmap_get(profile_item->capture_devices, role)) {
-                    pa_log_warn("Proper source for '%s.%s.%s' already loaded", device_type, device_profile, role);
-                    return -1;
-                }
+    PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
+        if (pa_streq(type, pa_tz_device_get_type(device))) {
+            if (pa_tz_device_profile_get_source(device, device_profile, role) == NULL) {
+                pa_log_warn("Proper source for '%s.%s.%s' already loaded", type, device_profile, role);
+                return -1;
             }
         }
     }
 
-
-    if (!(type_info = _device_manager_get_type_info(dm->type_infos, device_type, device_profile))) {
-        pa_log_error("No type map for %s", device_type);
+    if (!(type_info = _device_manager_get_type_info(dm->type_infos, type, device_profile))) {
+        pa_log_error("No type map for %s", type);
         return -1;
     }
 
+    if (type_info->capture_devices == NULL) {
+        pa_log_error("No capture devices for %s %s", type_info->type, pa_strempty(type_info->profile));
+        goto fail;
+    }
+
     if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
-        pa_log_error("No device-string for '%s.%s.%s'", device_type, device_profile, role);
-        goto failed;
+        pa_log_error("No device-string for '%s.%s.%s'", type, device_profile, role);
+        goto fail;
     }
 
     if (!(file_info = _device_manager_get_file_info(dm->file_map->capture, device_string))) {
         pa_log_error("No capture file-map for '%s'", device_string);
-        goto failed;
+        goto fail;
     }
 
     if (!(params = pa_hashmap_get(file_info->roles, role))) {
         pa_log_error("No params for '%s,%s'", device_string, role);
-        goto failed;
+        goto fail;
     }
 
     if ((source = load_device(dm->core, PA_DEVICE_TYPE_SOURCE, device_string, params))) {
-        pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, device_type, role);
+        pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
     } else {
         pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
-        goto failed;
+        goto fail;
     }
 
     return 0;
 
-failed:
+fail:
     return -1;
 }
 
+static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_conn_changed *data, pa_device_manager *dm) {
+    send_device_connected_signal(data->event_id, data->device, data->is_connected, dm);
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t device_info_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_info_changed *data, pa_device_manager *dm) {
+    send_device_info_changed_signal(data->event_id, data->device, data->changed_info, dm);
+    return PA_HOOK_OK;
+}
+
 pa_device_manager* pa_device_manager_get(pa_core *c) {
     pa_device_manager *dm;
 
@@ -4392,7 +3228,8 @@ pa_device_manager* pa_device_manager_get(pa_core *c) {
     dm = pa_xnew0(pa_device_manager, 1);
     PA_REFCNT_INIT(dm);
     dm->core = c;
-    dm->bt_sco_status = DM_DEVICE_BT_SCO_STATUS_DISCONNECTED;
+    dm->device_list = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+    dm->device_status = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
     dbus_init(dm);
 
@@ -4402,8 +3239,11 @@ pa_device_manager* pa_device_manager_get(pa_core *c) {
     dm->source_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) source_put_hook_callback, dm);
     dm->source_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, dm);
     dm->source_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_unlink_hook_callback, dm);
-
     dm->comm = pa_communicator_get(dm->core);
+    dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
+            PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm);
+    dm->comm_hook_device_info_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED),
+            PA_HOOK_EARLY, (pa_hook_cb_t)device_info_changed_hook_cb, dm);
     if (!(dm->type_infos = parse_device_type_infos())) {
         pa_log_error("Parse device-type-map failed");
         return NULL;
@@ -4414,15 +3254,7 @@ pa_device_manager* pa_device_manager_get(pa_core *c) {
         return NULL;
     }
 
-    if (device_list_init(dm) < 0) {
-        pa_log_error("Init device list failed");
-        return NULL;
-    }
-
-    if (!(dm->device_status = device_type_status_init(dm->type_infos))) {
-        pa_log_error("Init device status failed");
-        return NULL;
-    }
+    device_type_status_init(dm);
 
     if (load_builtin_devices(dm) != 0) {
         pa_log_error("Load Builtin Devices faled");
@@ -4460,6 +3292,10 @@ void pa_device_manager_unref(pa_device_manager *dm) {
     if (PA_REFCNT_DEC(dm) > 0)
         return;
 
+    if (dm->comm_hook_device_connection_changed_slot)
+        pa_hook_slot_free(dm->comm_hook_device_connection_changed_slot);
+    if (dm->comm_hook_device_info_changed_slot)
+        pa_hook_slot_free(dm->comm_hook_device_info_changed_slot);
     if (dm->sink_put_hook_slot)
         pa_hook_slot_free(dm->sink_put_hook_slot);
     if (dm->sink_state_changed_slot)
@@ -4486,7 +3322,7 @@ void pa_device_manager_unref(pa_device_manager *dm) {
         pa_xfree(dm->file_map);
     }
     if (dm->device_list)
-        pa_idxset_free(dm->device_list, (pa_free_cb_t)device_item_free_func);
+        pa_idxset_free(dm->device_list, (pa_free_cb_t)pa_tz_device_free);
     if (dm->device_status)
         pa_idxset_free(dm->device_status, NULL);
 
index fbf9a9e..8e2c04d 100644 (file)
   USA.
 ***/
 
-#include <pulsecore/core.h>
-
-#define DEVICE_TYPE_SPEAKER                 "builtin-speaker"
-#define DEVICE_TYPE_RECEIVER                "builtin-receiver"
-#define DEVICE_TYPE_MIC                     "builtin-mic"
-#define DEVICE_TYPE_AUDIO_JACK              "audio-jack"
-#define DEVICE_TYPE_BT                      "bt"
-#define DEVICE_TYPE_HDMI                    "hdmi"
-#define DEVICE_TYPE_FORWARDING              "forwarding"
-#define DEVICE_TYPE_USB_AUDIO               "usb-audio"
-#define DEVICE_TYPE_NONE                    "none"
-
-#define DEVICE_PROFILE_BT_SCO               "sco"
-#define DEVICE_PROFILE_BT_A2DP              "a2dp"
-
-#define DEVICE_ROLE_NORMAL                  "normal"
-#define DEVICE_ROLE_CALL_VOICE              "call-voice"
-#define DEVICE_ROLE_CALL_VIDEO              "call-video"
-#define DEVICE_ROLE_VOIP                    "voip"
-#define DEVICE_ROLE_LOW_LATENCY             "low-latency"
-#define DEVICE_ROLE_HIGH_LATENCY            "high-latency"
-#define DEVICE_ROLE_UHQA                    "uhqa"
-
-typedef enum dm_device_direction_type {
-    DM_DEVICE_DIRECTION_NONE,
-    DM_DEVICE_DIRECTION_IN = 0x1,
-    DM_DEVICE_DIRECTION_OUT = 0x2,
-    DM_DEVICE_DIRECTION_BOTH = DM_DEVICE_DIRECTION_IN | DM_DEVICE_DIRECTION_OUT
-} dm_device_direction_t;
-
-typedef enum dm_device_changed_into_type {
-    DM_DEVICE_CHANGED_INFO_STATE,
-    DM_DEVICE_CHANGED_INFO_IO_DIRECTION
-} dm_device_changed_info_t;
+#ifndef footizendevicemanagerfoo
+#define footizendevicemanagerfoo
 
-typedef enum dm_device_state_type {
-    DM_DEVICE_STATE_DEACTIVATED = 0,
-    DM_DEVICE_STATE_ACTIVATED
-} dm_device_state_t;
-
-typedef enum dm_device_bt_sco_status_type {
-    DM_DEVICE_BT_SCO_STATUS_DISCONNECTED = 0,
-    DM_DEVICE_BT_SCO_STATUS_CONNECTED,
-    DM_DEVICE_BT_SCO_STATUS_OPENED
-} dm_device_bt_sco_status_t;
+#include <pulsecore/core.h>
+#include <pulsecore/core-util.h>
+#include "tizen-device-def.h"
+#include "tizen-device.h"
 
 typedef struct pa_device_manager pa_device_manager;
-typedef struct dm_device dm_device;
-
-typedef struct _hook_call_data_for_conn_changed {
-    uint32_t event_id;
-    bool is_connected;
-    dm_device *device;
-} pa_device_manager_hook_data_for_conn_changed;
-
-typedef struct _hook_call_data_for_info_changed {
-    uint32_t event_id;
-    dm_device_changed_info_t changed_info;
-    dm_device *device;
-} pa_device_manager_hook_data_for_info_changed;
 
 pa_device_manager* pa_device_manager_get(pa_core* c);
 pa_device_manager* pa_device_manager_ref(pa_device_manager *dm);
 void pa_device_manager_unref(pa_device_manager *dm);
 
-/* get device or list */
+/* Get device list, returned pa_idxset contains 'pa_tz_device' */
 pa_idxset* pa_device_manager_get_device_list(pa_device_manager *dm);
-dm_device* pa_device_manager_get_device(pa_device_manager *dm, const char *device_type);
-dm_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id);
-
-/* query device */
-pa_sink* pa_device_manager_get_sink(dm_device *device_item, const char *role);
-pa_source* pa_device_manager_get_source(dm_device *device_item, const char *role);
-uint32_t pa_device_manager_get_device_id(dm_device *device_item);
-const char* pa_device_manager_get_device_type(dm_device *device_item);
-const char* pa_device_manager_get_device_subtype(dm_device *device_item);
-dm_device_direction_t pa_device_manager_get_device_direction(dm_device *device_item);
-pa_usec_t pa_device_manager_get_device_creation_time(dm_device *device_item);
-bool pa_device_manager_is_device_use_internal_codec(dm_device *device_item, dm_device_direction_t direction, const char *role);
-
-/* set/get device state */
-void pa_device_manager_set_device_state(dm_device *device_item, dm_device_direction_t direction, dm_device_state_t state);
-dm_device_state_t pa_device_manager_get_device_state(dm_device *device_item, dm_device_direction_t direction);
+/* Get device which of type is 'device_type'
+ * When there is multi-device for that 'device_type', return first one */
+pa_tz_device* pa_device_manager_get_device(pa_device_manager *dm, const char *device_type);
+pa_tz_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id);
 
 /* get device with sink or source */
-dm_device* pa_device_manager_get_device_with_sink(pa_sink *sink);
-dm_device* pa_device_manager_get_device_with_source(pa_source *source);
+pa_tz_device* pa_device_manager_get_device_with_sink(pa_sink *sink);
+pa_tz_device* pa_device_manager_get_device_with_source(pa_source *source);
 
 /* load pulse device */
 int pa_device_manager_load_sink(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *role);
 int pa_device_manager_load_source(pa_device_manager *dm, const char *device_type, const char *device_profile, const char *role);
 
-/* bt sco control/query */
-int pa_device_manager_bt_sco_open(pa_device_manager *dm);
-void pa_device_manager_bt_sco_get_status(pa_device_manager *dm, dm_device_bt_sco_status_t *status);
-int pa_device_manager_bt_sco_close(pa_device_manager *dm);
-int pa_device_manager_bt_sco_get_property(pa_device_manager *dm, bool *is_wide_band, bool *nrec);
+#endif
index 9caedc7..fe46d7a 100644 (file)
@@ -227,8 +227,8 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
     const char *dm_device_type = NULL;
     const char *dm_device_subtype = NULL;
     dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
-    dm_device *device = NULL;
-    dm_device *latest_device = NULL;
+    pa_tz_device *device = NULL;
+    pa_tz_device *latest_device = NULL;
     pa_idxset *conn_devices = NULL;
     pa_sink *sink = NULL;
     pa_sink *null_sink = NULL;
@@ -276,10 +276,10 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                 if (cached_connected_devices[convert_device_type_str(device_type)][CONVERT_TO_DEVICE_DIRECTION(data->stream_type)-1] == 0)
                     continue;
                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
-                    dm_device_subtype = pa_device_manager_get_device_subtype(device);
-                    dm_device_direction = pa_device_manager_get_device_direction(device);
-                    dm_device_id = pa_device_manager_get_device_id(device);
+                    dm_device_type = pa_tz_device_get_type(device);
+                    dm_device_subtype = pa_tz_device_get_profile(device);
+                    dm_device_direction = pa_tz_device_get_direction(device);
+                    dm_device_id = pa_tz_device_get_id(device);
                     pa_log_debug("  -- type[%-16s], subtype[%-5s], direction[0x%x], id[%u]",
                                  dm_device_type, dm_device_subtype, dm_device_direction, dm_device_id);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
@@ -290,9 +290,9 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                                 *(data->proper_sink) = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
                                 pa_log_debug("  -- found the combine-sink, set it to the sink");
                             } else
-                                *(data->proper_sink) = pa_device_manager_get_sink(device, data->device_role);
+                                *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
                         } else
-                            *(data->proper_source) = pa_device_manager_get_source(device, data->device_role);
+                            *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
                         break;
                     }
                 }
@@ -305,11 +305,11 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                 if (cached_connected_devices[convert_device_type_str(device_type)][CONVERT_TO_DEVICE_DIRECTION(data->stream_type)-1] == 0)
                     continue;
                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
-                    dm_device_subtype = pa_device_manager_get_device_subtype(device);
-                    dm_device_direction = pa_device_manager_get_device_direction(device);
-                    dm_device_id = pa_device_manager_get_device_id(device);
-                    creation_time = pa_device_manager_get_device_creation_time(device);
+                    dm_device_type = pa_tz_device_get_type(device);
+                    dm_device_subtype = pa_tz_device_get_profile(device);
+                    dm_device_direction = pa_tz_device_get_direction(device);
+                    dm_device_id = pa_tz_device_get_id(device);
+                    creation_time = pa_tz_device_get_creation_time(device);
                     pa_log_debug("  -- type[%-16s], subtype[%-5s], direction[0x%x], id[%u], creation_time[%llu]",
                                  dm_device_type, dm_device_subtype, dm_device_direction, dm_device_id, creation_time);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
@@ -324,9 +324,9 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
             /* update active device info. */
             if (latest_device) {
                 if (data->stream_type == STREAM_SINK_INPUT)
-                    *(data->proper_sink) = pa_device_manager_get_sink(latest_device, data->device_role);
+                    *(data->proper_sink) = pa_tz_device_get_sink(latest_device, data->device_role);
                 else
-                    *(data->proper_source) = pa_device_manager_get_source(latest_device, data->device_role);
+                    *(data->proper_source) = pa_tz_device_get_source(latest_device, data->device_role);
 
                 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
             }
@@ -339,23 +339,23 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                 continue;
             PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
                 if ((device = pa_device_manager_get_device_by_id(u->device_manager, *device_id))) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
-                    dm_device_subtype = pa_device_manager_get_device_subtype(device);
-                    dm_device_direction = pa_device_manager_get_device_direction(device);
+                    dm_device_type = pa_tz_device_get_type(device);
+                    dm_device_subtype = pa_tz_device_get_profile(device);
+                    dm_device_direction = pa_tz_device_get_direction(device);
                     pa_log_debug("  -- type[%-16s], subtype[%-5s], direction[0x%x], device id[%u]",
                             dm_device_type, dm_device_subtype, dm_device_direction, *device_id);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
                         pa_log_info("  ** found a matched device: type[%-16s], direction[0x%x]", device_type, dm_device_direction);
                         if (data->stream_type == STREAM_SINK_INPUT) {
                             if ((*(data->proper_sink)) == null_sink)
-                                pa_sink_input_move_to((pa_sink_input*)(data->stream), pa_device_manager_get_sink(device, data->device_role), false);
+                                pa_sink_input_move_to((pa_sink_input*)(data->stream), pa_tz_device_get_sink(device, data->device_role), false);
                             else
-                                *(data->proper_sink) = pa_device_manager_get_sink(device, data->device_role);
+                                *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
                         } else {
                             if ((*(data->proper_source)) == null_source)
-                                pa_source_output_move_to((pa_source_output*)(data->stream), pa_device_manager_get_source(device, data->device_role), false);
+                                pa_source_output_move_to((pa_source_output*)(data->stream), pa_tz_device_get_source(device, data->device_role), false);
                             else
-                                *(data->proper_source) = pa_device_manager_get_source(device, data->device_role);
+                                *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
                         }
                     }
                 }
@@ -369,9 +369,9 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                 continue;
             PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
                 if ((device = pa_device_manager_get_device_by_id(u->device_manager, *device_id))) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
-                    dm_device_subtype = pa_device_manager_get_device_subtype(device);
-                    dm_device_direction = pa_device_manager_get_device_direction(device);
+                    dm_device_type = pa_tz_device_get_type(device);
+                    dm_device_subtype = pa_tz_device_get_profile(device);
+                    dm_device_direction = pa_tz_device_get_direction(device);
                     pa_log_debug("  -- type[%-16s], subtype[%-5s], direction[0x%x], device id[%u]",
                             dm_device_type, dm_device_subtype, dm_device_direction, *device_id);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
@@ -379,12 +379,12 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                         /* currently, we support two sinks for combining */
                         if (data->stream_type == STREAM_SINK_INPUT) {
                             if (!combine_sink_arg1) {
-                                if ((sink = combine_sink_arg1 = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL)))
+                                if ((sink = combine_sink_arg1 = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL)))
                                     pa_log_debug("  -- combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
                                 else
                                     pa_log_warn("  -- could not get combine_sink_arg1");
                             } else if (!combine_sink_arg2) {
-                                sink = combine_sink_arg2 = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                                sink = combine_sink_arg2 = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
                                 if (sink && !pa_streq(sink->name, combine_sink_arg1->name)) {
                                     pa_log_debug("  -- combine_sink_arg2[%s]", sink->name);
                                     /* load combine sink */
@@ -414,7 +414,7 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                                 }
 
                         } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
-                            if ((source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL))) {
+                            if ((source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL))) {
                                 if (data->origins_from_new_data)
                                     *(data->proper_source) = source;
                                 else {
@@ -443,48 +443,82 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
 
 /* The state of a device using internal audio codec is handled here.
  * Regarding the state of an external device, those is handled in device-manager.c */
-static void set_device_state_if_using_internal_codec(dm_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
+static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
     bool use_internal_codec = false;
     dm_device_direction_t direction;
 
     pa_assert(device);
 
-    direction = pa_device_manager_get_device_direction(device);
+    direction = pa_tz_device_get_direction(device);
     if (IS_AVAILABLE_DIRECTION(stream_type, direction))
-        if ((use_internal_codec = pa_device_manager_is_device_use_internal_codec(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), DEVICE_ROLE_NORMAL)))
-            pa_device_manager_set_device_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
+        if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device)))
+            pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
 
     return;
 }
 
+/* threre is only one sco connected device */
+static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) {
+    pa_idxset *device_list;
+    pa_tz_device *device;
+    uint32_t device_idx;
+
+    pa_assert(dm);
+
+    device_list = pa_device_manager_get_device_list(dm);
+
+    PA_IDXSET_FOREACH(device, device_list, device_idx) {
+        if (pa_streq(device->type, DEVICE_TYPE_BT)) {
+            /* FIXME : not works */
+            if (pa_tz_device_have_profile(device, DEVICE_PROFILE_BT_SCO)) {
+                return device;
+            }
+        }
+    }
+    return NULL;
+}
+
 /* Open/Close BT SCO if it is possible */
 static int update_bt_sco_state(pa_device_manager *dm, bool open) {
     dm_device_bt_sco_status_t sco_status;
+    pa_tz_device *bt_device;
 
     pa_assert(dm);
 
-    pa_device_manager_bt_sco_get_status(dm, &sco_status);
+    bt_device = _get_sco_connected_device(dm);
+    if (bt_device == NULL) {
+        pa_log_debug("No SCO connected bt device");
+        return 0;
+    } else
+        pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
 
-    if (!open && (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED)) {
-        /* close BT SCO */
-        if (pa_device_manager_bt_sco_close(dm)) {
-            pa_log_error("BT SCO was opened, but failed to close SCO");
-            return -1;
-        } else
-            pa_log_debug("BT SCO is now closed");
-
-    } else if (open) {
-        if (sco_status == DM_DEVICE_BT_SCO_STATUS_DISCONNECTED) {
-            pa_log_error("BT SCO is not available for this BT device");
-            return -1;
-        } else if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
-            /* open BT SCO */
-            if (pa_device_manager_bt_sco_open(dm)) {
+    if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
+        pa_log_error("get BT SCO status failed");
+        return -1;
+    }
+
+    if (sco_status == DM_DEVICE_BT_SCO_STATUS_DISCONNECTED) {
+        pa_log_info("BT SCO is not available for this BT device");
+        return 0;
+    }
+    if (open) {
+        if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
+            if (pa_tz_device_sco_open(bt_device) < 0) {
                 pa_log_error("failed to open BT SCO");
                 return -1;
             } else
                 pa_log_debug("BT SCO is now opened");
-        }
+        } else
+            pa_log_error("BT SCO is already opened for this BT device");
+    } else {
+        if (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED) {
+            if (pa_tz_device_sco_close(bt_device) < 0) {
+                pa_log_error("BT SCO was opened, but failed to close SCO");
+                return -1;
+            } else
+                pa_log_debug("BT SCO is now closed");
+        } else
+            pa_log_error("BT SCO is already closed for this BT device");
     }
 
     return 0;
@@ -560,9 +594,9 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
     uint32_t dm_device_id = 0;
     stream_route_type_t route_type;
     const char *device_type = NULL;
-    dm_device *device = NULL;
-    dm_device *_device = NULL;
-    dm_device *latest_device = NULL;
+    pa_tz_device *device = NULL;
+    pa_tz_device *_device = NULL;
+    pa_tz_device *latest_device = NULL;
     const char *dm_device_type = NULL;
     const char *dm_device_subtype = NULL;
     dm_device_state_t dm_device_state = DM_DEVICE_STATE_DEACTIVATED;
@@ -609,9 +643,9 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
         conn_devices = pa_device_manager_get_device_list(u->device_manager);
         /* set device state to deactivate */
         PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-            dm_device_type = pa_device_manager_get_device_type(device);
-            dm_device_state = pa_device_manager_get_device_state(device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type));
-            dm_device_direction = pa_device_manager_get_device_direction(device);
+            dm_device_type = pa_tz_device_get_type(device);
+            dm_device_state = pa_tz_device_get_state(device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type));
+            dm_device_direction = pa_tz_device_get_direction(device);
             if (dm_device_state == DM_DEVICE_STATE_ACTIVATED && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
                 pa_log_info("[ROUTE][RESET] found a matched device and set state to DE-ACTIVATED: type[%s], direction[0x%x]",
                             dm_device_type, dm_device_direction);
@@ -662,17 +696,15 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                 if (cached_connected_devices[convert_device_type_str(device_type)][CONVERT_TO_DEVICE_DIRECTION(data->stream_type)-1] == 0)
                     continue;
                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
-                    dm_device_subtype = pa_device_manager_get_device_subtype(device);
-                    dm_device_direction = pa_device_manager_get_device_direction(device);
-                    dm_device_id = pa_device_manager_get_device_id(device);
+                    dm_device_type = pa_tz_device_get_type(device);
+                    dm_device_subtype = pa_tz_device_get_profile(device);
+                    dm_device_direction = pa_tz_device_get_direction(device);
+                    dm_device_id = pa_tz_device_get_id(device);
                     pa_log_debug("  -- type[%-16s], subtype[%-5s], direction[0x%x], id[%u]",
                                  dm_device_type, dm_device_subtype, dm_device_direction, dm_device_id);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
                         pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
-                        use_internal_codec = pa_device_manager_is_device_use_internal_codec(device,
-                                                                                            CONVERT_TO_DEVICE_DIRECTION(data->stream_type),
-                                                                                            data->device_role);
+                        use_internal_codec = pa_tz_device_is_use_internal_codec(device);
                         if (use_internal_codec) {
                             hal_direction = CONVERT_TO_HAL_DIRECTION(data->stream_type);
                             route_info.num_of_devices++;
@@ -694,9 +726,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
 
                 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
                     /* check if this device uses internal codec */
-                    use_internal_codec = pa_device_manager_is_device_use_internal_codec(device,
-                                                                                        CONVERT_TO_DEVICE_DIRECTION(data->stream_type),
-                                                                                        data->device_role);
+                    use_internal_codec = pa_tz_device_is_use_internal_codec(device);
                     if (use_internal_codec) {
                         /* set other device's state to be deactivated */
                         PA_IDXSET_FOREACH(_device, conn_devices, conn_idx) {
@@ -712,7 +742,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
 
                 /* move sink-inputs/source-outputs if needed */
                 if (data->stream_type == STREAM_SINK_INPUT)
-                    sink = pa_device_manager_get_sink(device, data->device_role);
+                    sink = pa_tz_device_get_sink(device, data->device_role);
 
                     /* unload combine sink */
                     if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
@@ -739,13 +769,13 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                         sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
                         pa_log_info("[ROUTE][AUTO_ALL] found the combine_sink already existed");
                     } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg1) {
-                        sink = combine_sink_arg1 = pa_device_manager_get_sink(device, data->device_role);
+                        sink = combine_sink_arg1 = pa_tz_device_get_sink(device, data->device_role);
                         if (sink)
                             pa_log_debug("[ROUTE][AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
                         else
                             pa_log_error("[ROUTE][AUTO_ALL] could not get sink from pa_device_manager_get_sink");
                     } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg2) {
-                        sink = combine_sink_arg2 = pa_device_manager_get_sink(device, data->device_role);
+                        sink = combine_sink_arg2 = pa_tz_device_get_sink(device, data->device_role);
                         if (sink && !pa_streq(sink->name, combine_sink_arg1->name)) {
                             pa_log_debug("[ROUTE][AUTO_ALL] combine_sink_arg2[%s]", sink->name);
                             /* load combine sink */
@@ -767,7 +797,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                                 pa_log_error("[ROUTE][AUTO_ALL] could not get combine_sink");
                         }
                     } else if (data->stream_type == STREAM_SOURCE_OUTPUT)
-                        source = pa_device_manager_get_source(device, data->device_role);
+                        source = pa_tz_device_get_source(device, data->device_role);
 
                     if (data->origins_from_new_data) {
                         if (data->stream_type == STREAM_SINK_INPUT)
@@ -801,11 +831,11 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                 if (cached_connected_devices[convert_device_type_str(device_type)][CONVERT_TO_DEVICE_DIRECTION(data->stream_type)-1] == 0)
                     continue;
                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
-                    dm_device_subtype = pa_device_manager_get_device_subtype(device);
-                    dm_device_direction = pa_device_manager_get_device_direction(device);
-                    dm_device_id = pa_device_manager_get_device_id(device);
-                    creation_time = pa_device_manager_get_device_creation_time(device);
+                    dm_device_type = pa_tz_device_get_type(device);
+                    dm_device_subtype = pa_tz_device_get_profile(device);
+                    dm_device_direction = pa_tz_device_get_direction(device);
+                    dm_device_id = pa_tz_device_get_id(device);
+                    creation_time = pa_tz_device_get_creation_time(device);
                     pa_log_debug("  -- type[%-16s], subtype[%-5s], direction[0x%x], id[%u], creation_time[%llu]",
                                  dm_device_type, dm_device_subtype, dm_device_direction, dm_device_id, creation_time);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
@@ -819,11 +849,9 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
             }
             /* update activated device if it is found */
             if (latest_device) {
-                dm_device_type = pa_device_manager_get_device_type(latest_device);
-                dm_device_id = pa_device_manager_get_device_id(latest_device);
-                use_internal_codec = pa_device_manager_is_device_use_internal_codec(latest_device,
-                                                                                    CONVERT_TO_DEVICE_DIRECTION(data->stream_type),
-                                                                                    data->device_role);
+                dm_device_type = pa_tz_device_get_type(latest_device);
+                dm_device_id = pa_tz_device_get_id(latest_device);
+                use_internal_codec = pa_tz_device_is_use_internal_codec(latest_device);
                 if (use_internal_codec) {
                     hal_direction = CONVERT_TO_HAL_DIRECTION(data->stream_type);
                     route_info.num_of_devices++;
@@ -873,7 +901,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
             /* set other device's state to be deactivated */
             PA_IDXSET_FOREACH(_device, conn_devices, conn_idx) {
                 bool need_to_deactive = true;
-                dm_device_id = pa_device_manager_get_device_id(_device);
+                dm_device_id = pa_tz_device_get_id(_device);
                 for (i = 0; i < route_info.num_of_devices; i++) {
                     if (dm_device_id == route_info.device_infos[i].id) {
                         need_to_deactive = false;
@@ -893,10 +921,23 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
             PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, d_idx) {
                 pa_log_debug("  -- manual_device[%u] for this role[%-16s]: device_id(%u)", idx, data->stream_role, *device_id);
                 if ((device = pa_device_manager_get_device_by_id(u->device_manager, *device_id))) {
-                    dm_device_type = pa_device_manager_get_device_type(device);
+                    /* FIXME : This is temparary code, until App could give
+                     * proper BT-SCO device for call-voice */
+                    if (pa_streq(route_info.role, STREAM_ROLE_CALL_VOICE) && pa_streq(device->type, DEVICE_TYPE_BT)) {
+                        pa_tz_device *sco_device;
+                        if ((sco_device = _get_sco_connected_device(u->device_manager)) == NULL) {
+                            pa_log_error("  ** could not find BT SCO");
+                            continue;
+                        }
+                        if (sco_device->id != *device_id) {
+                            pa_log_info("Redirecting this manual routing for call-voice to SCO device(%u)", sco_device->id);
+                            device = sco_device;
+                        }
+                    }
+                    dm_device_type = pa_tz_device_get_type(device);
                     if (pa_streq(device_type, dm_device_type)) {
-                        dm_device_direction = pa_device_manager_get_device_direction(device);
-                        dm_device_subtype = pa_device_manager_get_device_subtype(device);
+                        dm_device_direction = pa_tz_device_get_direction(device);
+                        dm_device_subtype = pa_tz_device_get_profile(device);
                         pa_log_debug("  ** found a matched device: type[%-16s], subtype[%-5s], direction[0x%x]",
                                      dm_device_type, dm_device_subtype, dm_device_direction);
                         /* Check for BT SCO in case of call routing */
@@ -913,15 +954,13 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                         /* Check for in/out devices in case of loopback */
                         if (pa_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
                             if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT))
-                                u->loopback_args.sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                                u->loopback_args.sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
                             else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN))
-                                u->loopback_args.source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+                                u->loopback_args.source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL);
                         }
 
                         if (IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
-                            use_internal_codec = pa_device_manager_is_device_use_internal_codec(device,
-                                                                                                CONVERT_TO_DEVICE_DIRECTION(data->stream_type),
-                                                                                                DEVICE_ROLE_NORMAL);
+                            use_internal_codec = pa_tz_device_is_use_internal_codec(device);
                             if (use_internal_codec) {
                                 route_info.num_of_devices++;
                                 route_info.device_infos = pa_xrealloc(route_info.device_infos, sizeof(hal_device_info)*route_info.num_of_devices);
@@ -951,15 +990,15 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
 
         if (pa_streq(data->stream_role, STREAM_ROLE_CALL_VOICE)) {
             if (data->stream_type == STREAM_SINK_INPUT) {
-                if (!(sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL)) ||
-                    !(dst_sink = pa_device_manager_get_sink(device, DEVICE_ROLE_CALL_VOICE)) ||
+                if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL)) ||
+                    !(dst_sink = pa_tz_device_get_sink(device, DEVICE_ROLE_CALL_VOICE)) ||
                     sink == dst_sink)
                     pa_log_debug("[ROUTE][CALL-VOICE] no need to move streams, sink(%p), dst_sink(%p)", sink, dst_sink);
                 else
                     streams = sink->inputs;
             } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
-                if (!(source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL)) ||
-                    !(dst_source = pa_device_manager_get_source(device, DEVICE_ROLE_CALL_VOICE)) ||
+                if (!(source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL)) ||
+                    !(dst_source = pa_tz_device_get_source(device, DEVICE_ROLE_CALL_VOICE)) ||
                     source == dst_source)
                     pa_log_debug("[ROUTE][CALL-VOICE] no need to move streams, source(%p), dst_source(%p)", source, dst_source);
                 else
@@ -988,7 +1027,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
         } else if (pa_streq(data->stream_role, STREAM_ROLE_RADIO)) {
             if (data->stream_type == STREAM_SINK_INPUT &&
                 pa_stream_manager_check_name_is_vstream(data->stream, STREAM_SINK_INPUT, true)) {
-                if ((sink = pa_device_manager_get_sink(device, data->device_role))) {
+                if ((sink = pa_tz_device_get_sink(device, data->device_role))) {
                     *(data->proper_sink) = sink;
                     pa_log_debug("[ROUTE][RADIO] *** now, sink-input(%p,%u) uses the sink(%p,%s)",
                                  data->stream, ((pa_sink_input*)data->stream)->index, sink, sink->name);
@@ -1011,9 +1050,9 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
     if (device && data->stream && !data->origins_from_new_data &&
         data->route_type != STREAM_ROUTE_TYPE_MANUAL) {
         if (data->stream_type == STREAM_SINK_INPUT)
-            sink = pa_device_manager_get_sink(device, data->device_role);
+            sink = pa_tz_device_get_sink(device, data->device_role);
         else if (data->stream_type == STREAM_SOURCE_OUTPUT)
-            source = pa_device_manager_get_source(device, data->device_role);
+            source = pa_tz_device_get_source(device, data->device_role);
         if (data->idx_streams) {
             PA_IDXSET_FOREACH(s, data->idx_streams, idx) {
                 if (sink && sink != ((pa_sink_input*)s)->sink) {
@@ -1100,18 +1139,18 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_
     pa_sink *combine_sink = NULL;
     bool use_internal_codec = false;
     pa_idxset* conn_devices = NULL;
-    dm_device* device = NULL;
+    pa_tz_device *device = NULL;
 
     pa_assert(c);
     pa_assert(conn);
     pa_assert(u);
 
-    device_direction = pa_device_manager_get_device_direction(conn->device);
+    device_direction = pa_tz_device_get_direction(conn->device);
 
     pa_log_info("[CONN] device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p), direction(0x%x)",
                 conn, conn->is_connected, conn->device, device_direction);
 
-    update_connected_devices(pa_device_manager_get_device_type(conn->device), device_direction, conn->is_connected);
+    update_connected_devices(pa_tz_device_get_type(conn->device), device_direction, conn->is_connected);
     dump_connected_devices();
 
     null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
@@ -1120,7 +1159,7 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_
         return PA_HOOK_OK;
     }
 
-    use_internal_codec = pa_device_manager_is_device_use_internal_codec(conn->device, device_direction, DEVICE_ROLE_NORMAL);
+    use_internal_codec = pa_tz_device_is_use_internal_codec(conn->device);
     /* update for unloading modules when external device is disconnected */
     if (!use_internal_codec && !conn->is_connected) {
         if (device_direction & DM_DEVICE_DIRECTION_OUT) {
@@ -1129,10 +1168,10 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_
                 if ((combine_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK))) {
                     conn_devices = pa_device_manager_get_device_list(u->device_manager);
                     PA_IDXSET_FOREACH(device, conn_devices, idx) {
-                        device_direction = pa_device_manager_get_device_direction(device);
+                        device_direction = pa_tz_device_get_direction(device);
                         if (device_direction == DM_DEVICE_DIRECTION_OUT) {
-                            if ((use_internal_codec = pa_device_manager_is_device_use_internal_codec(device, device_direction, DEVICE_ROLE_NORMAL))) {
-                                sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                            if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device))) {
+                                sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
                                 break;
                             }
                         }
@@ -1169,13 +1208,13 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_
             }
             /* unload loopback module */
             if (u->module_loopback)
-                if (u->loopback_args.sink == pa_device_manager_get_sink(conn->device, DEVICE_ROLE_NORMAL))
+                if (u->loopback_args.sink == pa_tz_device_get_sink(conn->device, DEVICE_ROLE_NORMAL))
                     update_loopback_module(u, false);
         }
     if (device_direction & DM_DEVICE_DIRECTION_IN) {
         /* unload loopback module */
         if (u->module_loopback)
-            if (u->loopback_args.source == pa_device_manager_get_source(conn->device, DEVICE_ROLE_NORMAL))
+            if (u->loopback_args.source == pa_tz_device_get_source(conn->device, DEVICE_ROLE_NORMAL))
                 update_loopback_module(u, false);
         }
     }
@@ -1193,13 +1232,13 @@ static pa_hook_result_t device_info_changed_hook_cb(pa_core *c, pa_device_manage
     pa_assert(conn);
     pa_assert(u);
 
-    device_direction = pa_device_manager_get_device_direction(conn->device);
+    device_direction = pa_tz_device_get_direction(conn->device);
 
     pa_log_info("[CONN] device_info_changed_hook_cb is called. conn(%p), changed_info(%d), device(%p), direction(0x%x)",
                 conn, conn->changed_info, conn->device, device_direction);
 
     if (conn->changed_info == DM_DEVICE_CHANGED_INFO_IO_DIRECTION)
-        if (pa_streq(pa_device_manager_get_device_type(conn->device), DEVICE_TYPE_BT)) {
+        if (pa_streq(pa_tz_device_get_type(conn->device), DEVICE_TYPE_BT)) {
             /* In case of the bluetooth, we do not maintain a ref. count of the bluetooth devices.
              * Because bluetooth framework supports only one device simultaneously for audio profile. */
             ptr_in = &cached_connected_devices[convert_device_type_str(DEVICE_TYPE_BT)][CACHED_DEVICE_DIRECTION_IN];
index e9f168b..a356637 100644 (file)
@@ -2902,7 +2902,7 @@ static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_ou
     return PA_HOOK_OK;
 }
 
-static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *role, stream_type_t stream_type, const char *cur_device_type, dm_device **next_device) {
+static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *role, stream_type_t stream_type, const char *cur_device_type, pa_tz_device **next_device) {
     stream_info *si = NULL;
     pa_idxset *devices = NULL;
     uint32_t idx = 0;
@@ -2910,7 +2910,7 @@ static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_t
     bool ret_next = false;
     pa_usec_t creation_time = 0;
     pa_usec_t latest_creation_time = 0;
-    dm_device* latest_device = NULL;
+    pa_tz_device* latest_device = NULL;
 
     pa_assert(m);
     pa_assert(m->stream_infos);
@@ -2952,7 +2952,7 @@ static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_t
     } else if (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
         PA_IDXSET_FOREACH(device_type, devices, idx) {
             if ((*next_device = pa_device_manager_get_device(m->dm, device_type))) {
-                creation_time = pa_device_manager_get_device_creation_time(*next_device);
+                creation_time = pa_tz_device_get_creation_time(*next_device);
                 if (!latest_device || (latest_creation_time <= creation_time)) {
                     latest_device = *next_device;
                     latest_creation_time = creation_time;
@@ -3051,19 +3051,19 @@ static void process_stream_as_device_change_for_auto_route(pa_stream_manager *m,
 
 /* The state of a device using internal audio codec is handled here.
  * Regarding the state of an external device, those is handled in device-manager.c */
-static void set_device_state_if_using_internal_codec(dm_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
+static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
     bool use_internal_codec = false;
 
     pa_assert(device);
 
-    if ((use_internal_codec = pa_device_manager_is_device_use_internal_codec(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), DEVICE_ROLE_NORMAL)))
-        pa_device_manager_set_device_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
+    if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device)))
+        pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
 
     return;
 }
 
 static void update_sink_or_source_as_device_change(stream_route_type_t stream_route_type, pa_idxset *streams,
-                                                   stream_type_t stream_type, dm_device *device, bool is_connected, pa_stream_manager *m) {
+                                                   stream_type_t stream_type, pa_tz_device *device, bool is_connected, pa_stream_manager *m) {
     #define MAX_CACHED_LEN 128
     typedef struct _cached_device_list {
         const char *device_type;
@@ -3075,8 +3075,8 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
     const char *device_type = NULL;
     const char *cur_device_type = NULL;
     const char *new_device_type = NULL;
-    dm_device *next_device = NULL;
-    dm_device *_device = NULL;
+    pa_tz_device *next_device = NULL;
+    pa_tz_device *_device = NULL;
     stream_route_type_t route_type;
     pa_sink *sink = NULL;
     pa_sink *next_sink = NULL;
@@ -3100,15 +3100,15 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
         pa_log_error("[SM][UPDATE_SINK_SOURCE] could not get null_sink(%p) or null_source(%p)", null_sink, null_source);
         return;
     }
-    device_type = pa_device_manager_get_device_type(device);
+    device_type = pa_tz_device_get_type(device);
 
     if (stream_route_type == STREAM_ROUTE_TYPE_AUTO || stream_route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
         pa_log_debug("[SM][UPDATE_SINK_SOURCE][AUTO] route_type(%d), deivce_type(%s), is_connected(%d))",
                      stream_route_type, device_type, is_connected);
         if (stream_type == STREAM_SINK_INPUT)
-            sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+            sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
         else
-            source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+            source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL);
 
         PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: core->source_outputs/core->sink_inputs */
             if (!get_route_type(s, stream_type, false, &route_type) && (route_type == stream_route_type)) {
@@ -3155,8 +3155,8 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                     if (sink && (sink == ((pa_sink_input*)s)->sink)) {
                         find_next_device_for_auto_route(m, route_type, role, stream_type, device_type, &next_device);
                         if (next_device) {
-                            if ((next_sink = pa_device_manager_get_sink(next_device, DEVICE_ROLE_NORMAL))) {
-                                new_device_type = pa_device_manager_get_device_type(next_device);
+                            if ((next_sink = pa_tz_device_get_sink(next_device, DEVICE_ROLE_NORMAL))) {
+                                new_device_type = pa_tz_device_get_type(next_device);
                                 /* update activated device */
                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
                                 set_device_state_if_using_internal_codec(next_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
@@ -3180,8 +3180,8 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                     } else if (source && (source == ((pa_source_output*)s)->source)) {
                         find_next_device_for_auto_route(m, route_type, role, stream_type, device_type, &next_device);
                         if (next_device) {
-                            if ((next_source = pa_device_manager_get_source(next_device, DEVICE_ROLE_NORMAL))) {
-                                new_device_type = pa_device_manager_get_device_type(next_device);
+                            if ((next_source = pa_tz_device_get_source(next_device, DEVICE_ROLE_NORMAL))) {
+                                new_device_type = pa_tz_device_get_type(next_device);
                                 /* update activated device */
                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
                                 set_device_state_if_using_internal_codec(next_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
@@ -3325,29 +3325,29 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_
     pa_assert(data);
     pa_assert(m);
 
-    device_direction = pa_device_manager_get_device_direction(data->device);
-    device_type = pa_device_manager_get_device_type(data->device);
-    device_id = pa_device_manager_get_device_id(data->device);
-    use_internal_codec = pa_device_manager_is_device_use_internal_codec(data->device, device_direction, DEVICE_ROLE_NORMAL);
+    device_direction = pa_tz_device_get_direction(data->device);
+    device_type = pa_tz_device_get_type(data->device);
+    device_id = pa_tz_device_get_id(data->device);
+    use_internal_codec = pa_tz_device_is_use_internal_codec(data->device);
 
     pa_log_info("[SM][CONN] device_connection_changed_hook_cb is called. evend_id(%u), is_connected(%d), device(%p, %s, %u), direction(0x%x), use_internal_codec(%d)",
                 data->event_id, data->is_connected, data->device, device_type, device_id, device_direction, use_internal_codec);
 
     /* mute all the streams belong to this device, those will be un-muted in event_fully_handled_hook_cb */
     if (!data->is_connected && (device_direction & DM_DEVICE_DIRECTION_OUT))
-        if ((sink = pa_device_manager_get_sink(data->device, DEVICE_ROLE_NORMAL)))
+        if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL)))
             mute_sink_inputs_as_device_disconnection(m, data->event_id, true, sink->inputs);
 
     /* Update streams belong to this external device that have MAUAL_EXT route type */
     if (!use_internal_codec && (device_direction & DM_DEVICE_DIRECTION_IN)) {
-        if ((source = pa_device_manager_get_source(data->device, DEVICE_ROLE_NORMAL)))
+        if ((source = pa_tz_device_get_source(data->device, DEVICE_ROLE_NORMAL)))
             update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_MANUAL_EXT, source->outputs,
                                                    STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
         else
             pa_log_error("[SM][CONN] could not get source");
     }
     if (!use_internal_codec && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
-        if ((sink = pa_device_manager_get_sink(data->device, DEVICE_ROLE_NORMAL)))
+        if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL)))
             update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_MANUAL_EXT, sink->inputs,
                                                    STREAM_SINK_INPUT, data->device, data->is_connected, m);
         else
index 5db7fa9..9e6c8df 100644 (file)
 #include <pulsecore/protocol-dbus.h>
 #endif
 
+#include "subscribe-observer.h"
 #include "communicator.h"
 #include "device-manager.h"
-#include "subscribe-observer.h"
+#include "tizen-device.h"
 
 #define SHARED_SUBSCRIBE_OBSERVER "tizen-subscribe-observer"
 
index 4102e3a..6210963 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef foosubscribeobserverfoo
 #define foosubscribeobserverfoo
 
+#include <pulsecore/core.h>
+
 typedef struct pa_subscribe_observer pa_subscribe_observer;
 
 pa_subscribe_observer* pa_subscribe_observer_get(pa_core *c);
diff --git a/src/tizen-device-def.c b/src/tizen-device-def.c
new file mode 100644 (file)
index 0000000..f0f5b82
--- /dev/null
@@ -0,0 +1,262 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <string.h>
+#include <pulsecore/core-util.h>
+#include "tizen-device-def.h"
+
+#define DEVICE_DIRECTION_STR_NONE           "none"
+#define DEVICE_DIRECTION_STR_OUT            "out"
+#define DEVICE_DIRECTION_STR_IN             "in"
+#define DEVICE_DIRECTION_STR_BOTH           "both"
+
+static inline bool pa_safe_streq2(const char *a, const char *b) {
+    if (a == NULL || b == NULL)
+        return a == b;
+    else if (a == NULL || b != NULL)
+        return false;
+    else if (a != NULL || b == NULL)
+        return false;
+    return pa_streq(a, b);
+}
+
+bool device_profile_is_equal(const char *device_profile1, const char *device_profile2) {
+    if (!device_profile1 && !device_profile2)
+        return true;
+    else if (!device_profile1 || !device_profile2)
+        return false;
+    else if (pa_streq(device_profile1, device_profile2))
+        return true;
+    else
+        return false;
+}
+
+bool device_type_is_equal(const char *device_type1, const char *device_profile1, const char *device_type2, const char *device_profile2) {
+    pa_assert(device_type1);
+    pa_assert(device_type2);
+
+    if (pa_streq(device_type1, device_type2))
+        return device_profile_is_equal(device_profile1, device_profile2);
+    else
+        return false;
+}
+
+bool device_type_is_builtin(const char *device_type) {
+    if (!device_type)
+        return false;
+    else if (pa_streq(device_type, DEVICE_TYPE_SPEAKER))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_MIC))
+        return true;
+    else
+        return false;
+}
+
+bool device_type_is_valid(const char *device_type) {
+    if (!device_type)
+        return false;
+    else if (pa_streq(device_type, DEVICE_TYPE_SPEAKER))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_MIC))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_AUDIO_JACK))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_BT))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_HDMI))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_FORWARDING))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO))
+        return true;
+    else
+        return false;
+}
+
+bool device_type_is_use_external_card(const char *device_type, const char *profile) {
+    if (!device_type)
+        return false;
+    else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO))
+        return true;
+    else if ((pa_streq(device_type, DEVICE_TYPE_BT)) &&
+            profile && pa_streq(profile, DEVICE_PROFILE_BT_A2DP))
+        return true;
+    else
+        return false;
+}
+
+bool device_type_is_multi_profile(const char *device_type) {
+    if (!device_type)
+        return false;
+    else if (pa_streq(device_type, DEVICE_TYPE_BT))
+        return true;
+    else
+        return false;
+}
+
+bool device_type_is_avail_multi_device(const char *device_type) {
+    if (!device_type)
+        return false;
+    else if (pa_streq(device_type, DEVICE_TYPE_BT))
+        return true;
+    else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO))
+        return true;
+    else
+        return false;
+}
+
+bool device_type_is_need_detect(const char *type, const char *profile) {
+    if (!type)
+        return false;
+    else if (pa_streq(type, DEVICE_TYPE_AUDIO_JACK))
+        return true;
+    else if (pa_streq(type, DEVICE_TYPE_HDMI))
+        return true;
+    else if (pa_streq(type, DEVICE_TYPE_FORWARDING))
+        return true;
+    else if (device_type_is_equal(type, profile, DEVICE_TYPE_BT ,DEVICE_PROFILE_BT_SCO))
+        return true;
+    else
+        return false;
+}
+
+/* Some type have static(fixed) direction,
+ * and other type(ex.audio-jack)'s direction varies with detected type,
+ * and the other types(ex. bt-a2dp, usb-audio)'s direction is decided with
+ * sink/source */
+dm_device_direction_t device_type_get_static_direction(const char *type, const char *profile) {
+    if (!type)
+        return DM_DEVICE_DIRECTION_NONE;
+    else if (pa_streq(type, DEVICE_TYPE_SPEAKER))
+        return DM_DEVICE_DIRECTION_OUT;
+    else if (pa_streq(type, DEVICE_TYPE_RECEIVER))
+        return DM_DEVICE_DIRECTION_OUT;
+    else if (pa_streq(type, DEVICE_TYPE_MIC))
+        return DM_DEVICE_DIRECTION_IN;
+    else if (device_type_is_equal(type, profile, DEVICE_TYPE_BT ,DEVICE_PROFILE_BT_SCO))
+        return DM_DEVICE_DIRECTION_BOTH;
+    else if (pa_streq(type, DEVICE_TYPE_HDMI))
+        return DM_DEVICE_DIRECTION_OUT;
+    else if (pa_streq(type, DEVICE_TYPE_FORWARDING))
+        return DM_DEVICE_DIRECTION_BOTH;
+    else
+        return DM_DEVICE_DIRECTION_NONE;
+}
+
+/* Check whether 'direction' is valid for 'device_type'
+ * This is static device-type availability, not for runtime checking */
+bool device_type_is_valid_direction(const char *device_type, const char *device_profile, dm_device_direction_t direction) {
+    if (!device_type || direction == DM_DEVICE_DIRECTION_NONE)
+        return false;
+
+    if (pa_streq(device_type, DEVICE_TYPE_SPEAKER))
+        return direction == DM_DEVICE_DIRECTION_OUT;
+    else if (pa_streq(device_type, DEVICE_TYPE_RECEIVER))
+        return direction == DM_DEVICE_DIRECTION_OUT;
+    else if (pa_streq(device_type, DEVICE_TYPE_MIC))
+        return direction == DM_DEVICE_DIRECTION_IN;
+    else if (pa_streq(device_type, DEVICE_TYPE_AUDIO_JACK))
+        return direction == DM_DEVICE_DIRECTION_OUT || direction == DM_DEVICE_DIRECTION_BOTH;
+    else if (pa_streq(device_type, DEVICE_TYPE_BT) && pa_safe_streq2(device_profile, DEVICE_PROFILE_BT_SCO))
+        return direction == DM_DEVICE_DIRECTION_BOTH;
+    else if (pa_streq(device_type, DEVICE_TYPE_BT) && pa_safe_streq2(device_profile, DEVICE_PROFILE_BT_A2DP))
+        return direction == DM_DEVICE_DIRECTION_OUT || direction == DM_DEVICE_DIRECTION_IN;
+    else if (pa_streq(device_type, DEVICE_TYPE_HDMI))
+        return direction == DM_DEVICE_DIRECTION_OUT;
+    else if (pa_streq(device_type, DEVICE_TYPE_FORWARDING))
+        return direction == DM_DEVICE_DIRECTION_BOTH;
+    else if (pa_streq(device_type, DEVICE_TYPE_USB_AUDIO))
+        return direction == DM_DEVICE_DIRECTION_BOTH || direction == DM_DEVICE_DIRECTION_OUT || direction == DM_DEVICE_DIRECTION_IN;
+    else
+        return false;
+}
+
+const char* device_direction_to_string(dm_device_direction_t direction) {
+    if (direction <= DM_DEVICE_DIRECTION_NONE || direction > DM_DEVICE_DIRECTION_BOTH) {
+        return NULL;
+    }
+
+    if (direction == DM_DEVICE_DIRECTION_NONE)
+        return DEVICE_DIRECTION_STR_NONE;
+    else if (direction == DM_DEVICE_DIRECTION_OUT)
+        return DEVICE_DIRECTION_STR_OUT;
+    else if (direction == DM_DEVICE_DIRECTION_IN)
+        return DEVICE_DIRECTION_STR_IN;
+    else if (direction == DM_DEVICE_DIRECTION_BOTH)
+        return DEVICE_DIRECTION_STR_BOTH;
+    else
+        return NULL;
+}
+
+bool device_role_is_valid(const char *device_role) {
+    if (!device_role)
+        return false;
+    else if (pa_streq(device_role, DEVICE_ROLE_NORMAL))
+        return true;
+    else if (pa_streq(device_role, DEVICE_ROLE_CALL_VOICE))
+        return true;
+    else if (pa_streq(device_role, DEVICE_ROLE_CALL_VIDEO))
+        return true;
+    else if (pa_streq(device_role, DEVICE_ROLE_VOIP))
+        return true;
+    else if (pa_streq(device_role, DEVICE_ROLE_LOW_LATENCY))
+        return true;
+    else if (pa_streq(device_role, DEVICE_ROLE_HIGH_LATENCY))
+        return true;
+    else if (pa_streq(device_role, DEVICE_ROLE_UHQA))
+        return true;
+    else
+        return false;
+}
+
+dm_device_direction_t device_direction_to_int(const char *device_direction) {
+    if (!device_direction) {
+        return -1;
+    }
+
+    if (pa_streq(device_direction, DEVICE_DIRECTION_STR_NONE)) {
+        return DM_DEVICE_DIRECTION_NONE;
+    } else if (pa_streq(device_direction, DEVICE_DIRECTION_STR_OUT)) {
+        return DM_DEVICE_DIRECTION_OUT;
+    } else if (pa_streq(device_direction, DEVICE_DIRECTION_STR_IN)) {
+        return DM_DEVICE_DIRECTION_IN;
+    } else if (pa_streq(device_direction, DEVICE_DIRECTION_STR_BOTH)) {
+        return DM_DEVICE_DIRECTION_BOTH;
+    } else {
+        return -1;
+    }
+}
+
+int get_profile_priority(const char *device_profile) {
+    if (!device_profile) {
+        return 0;
+    } else if (pa_streq(device_profile,  DEVICE_PROFILE_BT_A2DP)) {
+        return 1;
+    } else if (pa_streq(device_profile,  DEVICE_PROFILE_BT_SCO)) {
+        return 2;
+    } else {
+        return -1;
+    }
+}
+
+int compare_profile_priority(const char *device_profile1,  const char *device_profile2) {
+    int priority1, priority2;
+
+    priority1 = get_profile_priority(device_profile1);
+    priority2 = get_profile_priority(device_profile2);
+
+    if (priority1 > priority2) {
+        return 1;
+    } else if (priority1 == priority2) {
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
diff --git a/src/tizen-device-def.h b/src/tizen-device-def.h
new file mode 100644 (file)
index 0000000..e4efdd7
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef footizendevicedeffoo
+#define footizendevicedeffoo
+
+#include <pulsecore/hashmap.h>
+#include <pulsecore/core.h>
+
+#define DEVICE_TYPE_SPEAKER                 "builtin-speaker"
+#define DEVICE_TYPE_RECEIVER                "builtin-receiver"
+#define DEVICE_TYPE_MIC                     "builtin-mic"
+#define DEVICE_TYPE_AUDIO_JACK              "audio-jack"
+#define DEVICE_TYPE_BT                      "bt"
+#define DEVICE_TYPE_HDMI                    "hdmi"
+#define DEVICE_TYPE_FORWARDING              "forwarding"
+#define DEVICE_TYPE_USB_AUDIO               "usb-audio"
+#define DEVICE_TYPE_NONE                    "none"
+
+#define PROFILE_NUM_MAX                     2
+#define DEVICE_PROFILE_BT_SCO               "sco"
+#define DEVICE_PROFILE_BT_A2DP              "a2dp"
+
+#define DEVICE_ROLE_NORMAL                  "normal"
+#define DEVICE_ROLE_CALL_VOICE              "call-voice"
+#define DEVICE_ROLE_CALL_VIDEO              "call-video"
+#define DEVICE_ROLE_VOIP                    "voip"
+#define DEVICE_ROLE_LOW_LATENCY             "low-latency"
+#define DEVICE_ROLE_HIGH_LATENCY            "high-latency"
+#define DEVICE_ROLE_UHQA                    "uhqa"
+
+typedef enum dm_device_direction_type {
+    DM_DEVICE_DIRECTION_NONE,
+    DM_DEVICE_DIRECTION_IN = 0x1,
+    DM_DEVICE_DIRECTION_OUT = 0x2,
+    DM_DEVICE_DIRECTION_BOTH = DM_DEVICE_DIRECTION_IN | DM_DEVICE_DIRECTION_OUT
+} dm_device_direction_t;
+
+typedef enum dm_device_changed_into_type {
+    DM_DEVICE_CHANGED_INFO_STATE,
+    DM_DEVICE_CHANGED_INFO_IO_DIRECTION
+} dm_device_changed_info_t;
+
+typedef enum dm_device_state_type {
+    DM_DEVICE_STATE_DEACTIVATED = 0,
+    DM_DEVICE_STATE_ACTIVATED
+} dm_device_state_t;
+
+typedef enum dm_device_bt_sco_status_type {
+    DM_DEVICE_BT_SCO_STATUS_DISCONNECTED = 0,
+    DM_DEVICE_BT_SCO_STATUS_CONNECTED,
+    DM_DEVICE_BT_SCO_STATUS_OPENED
+} dm_device_bt_sco_status_t;
+
+/* A macro to ease iteration through all entries */
+#define PA_HASHMAP_FOREACH_KEY(e, h, state, key) \
+    for ((state) = NULL, (e) = pa_hashmap_iterate((h), &(state), (const void**)&(key)); (e); (e) = pa_hashmap_iterate((h), &(state), (const void**)&(key)))
+
+bool device_type_is_builtin(const char *device_type);
+bool device_type_is_use_external_card(const char *device_type, const char *device_profile);
+bool device_type_is_valid(const char *device_type);
+bool device_type_is_valid_direction(const char *device_type, const char *device_profile, dm_device_direction_t direction);
+bool device_type_is_multi_profile(const char *device_type);
+bool device_type_is_avail_multi_device(const char *device_type);
+bool device_type_is_need_detect(const char *type, const char *profile);
+dm_device_direction_t device_type_get_static_direction(const char *type, const char *profile);
+const char* device_direction_to_string(dm_device_direction_t direction);
+bool device_role_is_valid(const char *device_role);
+dm_device_direction_t device_direction_to_int(const char *device_direction);
+bool device_profile_is_equal(const char *device_profile1, const char *device_profile2);
+bool device_type_is_equal(const char *device_type1, const char *device_profile1, const char *device_type2, const char *device_profile2);
+
+#endif
diff --git a/src/tizen-device.c b/src/tizen-device.c
new file mode 100644 (file)
index 0000000..9f73f79
--- /dev/null
@@ -0,0 +1,1365 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <pulse/proplist.h>
+#include <pulse/util.h>
+#include <pulse/rtclock.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/strbuf.h>
+
+#include "tizen-device.h"
+
+#define DBUS_SERVICE_HFP_AGENT "org.bluez.ag_agent"
+#define DBUS_OBJECT_HFP_AGENT "/org/bluez/hfp_agent"
+#define DBUS_INTERFACE_HFP_AGENT "Org.Hfp.App.Interface"
+
+#define BT_CVSD_CODEC_ID 1 // narrow-band
+#define BT_MSBC_CODEC_ID 2 // wide-band
+
+#define COMPOUND_STATE(d) (((pa_tz_profile*)d)->playback_state | ((pa_tz_profile*)d)->capture_state)
+
+int device_id_max_g = 1;
+uint32_t event_id_max_g = 1;
+
+static uint32_t _new_event_id() {
+    return event_id_max_g++;
+}
+
+static char* get_playback_list_str(pa_hashmap *playback_devices) {
+    pa_sink *sink = NULL;
+    void *state = NULL;
+    const char *role;
+    pa_strbuf *buf;
+
+    if (!playback_devices || !pa_hashmap_size(playback_devices))
+        return NULL;
+
+    buf = pa_strbuf_new();
+    pa_strbuf_printf(buf, "    Playback device list\n");
+    PA_HASHMAP_FOREACH_KEY(sink, playback_devices, state, role)
+        pa_strbuf_printf(buf, "        %-13s -> %s\n", role, sink->name);
+
+    return pa_strbuf_tostring_free(buf);
+}
+
+static char* get_capture_list_str(pa_hashmap *capture_devices) {
+    pa_source *source = NULL;
+    void *state = NULL;
+    const char *role;
+    pa_strbuf *buf;
+
+    if (!capture_devices || !pa_hashmap_size(capture_devices))
+        return NULL;
+
+    buf = pa_strbuf_new();
+    pa_strbuf_printf(buf, "    Capture device list\n");
+    PA_HASHMAP_FOREACH_KEY(source, capture_devices, state, role)
+        pa_strbuf_printf(buf, "        %-13s -> %s\n", role, source->name);
+
+    return pa_strbuf_tostring_free(buf);
+}
+
+/* Returned string must be freed */
+static char* get_device_profile_info_str(pa_tz_profile *profile) {
+    pa_strbuf *buf;
+    char *playback_str, *capture_str;
+    if (!profile)
+        return NULL;
+
+    buf = pa_strbuf_new();
+    pa_strbuf_printf(buf, "    Profile      : %s\n", pa_strna(profile->profile));
+    pa_strbuf_printf(buf, "    Direction    : %s\n", device_direction_to_string(profile->direction));
+    pa_strbuf_printf(buf, "    Is activated : %s\n", pa_yes_no(COMPOUND_STATE(profile) == DM_DEVICE_STATE_ACTIVATED));
+    pa_strbuf_printf(buf, "    Internal     : %s\n", pa_yes_no(profile->use_internal_codec));
+    if (profile->profile && pa_streq(profile->profile, DEVICE_PROFILE_BT_SCO))
+        pa_strbuf_printf(buf, "    SCO opened   : %s\n", pa_yes_no(profile->sco_opened));
+    playback_str = get_playback_list_str(profile->playback_devices);
+    capture_str = get_capture_list_str(profile->capture_devices);
+
+    if (playback_str)
+        pa_strbuf_puts(buf, playback_str);
+    if (capture_str)
+        pa_strbuf_puts(buf, capture_str);
+
+    pa_xfree(playback_str);
+    pa_xfree(capture_str);
+
+    return pa_strbuf_tostring_free(buf);
+}
+
+static char* _device_get_info_str(pa_tz_device *device) {
+    pa_strbuf *buf;
+    char *profile_info;
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+
+    if (!device)
+        return NULL;
+
+    buf = pa_strbuf_new();
+    pa_strbuf_printf(buf, "[Device #%u]\n", device->id);
+    pa_strbuf_printf(buf, "  ID             : %u\n", device->id);
+    pa_strbuf_printf(buf, "  Type           : %s\n", device->type);
+    pa_strbuf_printf(buf, "  Name           : %s\n", device->name);
+    if (device_type_is_multi_profile(device->type))
+        pa_strbuf_printf(buf, "  System ID      : %s\n", device->system_id);
+    pa_strbuf_printf(buf, "  Active Profile : %u\n", device->active_profile);
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
+        pa_strbuf_printf(buf, "  (Profile #%d)\n", profile_idx);
+        profile_info = get_device_profile_info_str(profile);
+        if (profile_info)
+            pa_strbuf_puts(buf, profile_info);
+        pa_xfree(profile_info);
+    }
+
+    return pa_strbuf_tostring_free(buf);
+}
+
+
+void pa_tz_device_dump_info(pa_tz_device *device, pa_log_level_t log_level) {
+    char *info;
+
+    if (!device)
+        return;
+
+    if ((info = _device_get_info_str(device))) {
+        pa_logl(log_level, "%s", info);
+        pa_xfree(info);
+    }
+}
+
+static void notify_device_connection_changed(pa_tz_device *device, bool connected) {
+    pa_device_manager_hook_data_for_conn_changed hook_data;
+    uint32_t event_id;
+
+    event_id = _new_event_id();
+
+    hook_data.event_id = event_id;
+    hook_data.is_connected = connected;
+    hook_data.device = device;
+
+    pa_log_info("Fire hook for device connection changed, device(%u) %s",
+            device->id, connected ? "connected" : "disconnected");
+    pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), &hook_data);
+}
+
+static void notify_device_info_changed(pa_tz_device *device, dm_device_changed_info_t changed_type) {
+    pa_device_manager_hook_data_for_info_changed hook_data;
+    uint32_t event_id;
+
+    event_id = _new_event_id();
+
+    hook_data.event_id = event_id;
+    hook_data.changed_info = changed_type;
+    hook_data.device = device;
+
+    pa_log_info("Fire hook for device info changed, device(%u) %s changed",
+            device->id, changed_type == DM_DEVICE_CHANGED_INFO_STATE ? "state" : "direction");
+    pa_hook_fire(pa_communicator_hook(device->comm, PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED), &hook_data);
+}
+
+/* pa_tz_device_new_data */
+void pa_tz_device_new_data_init(pa_tz_device_new_data *data, pa_idxset *list,
+        pa_communicator *comm, pa_dbus_connection *conn) {
+    pa_assert(data);
+    pa_assert(list);
+    pa_assert(comm);
+
+    data->list = list;
+    data->comm = comm;
+    data->dbus_conn = conn;
+
+    data->type = NULL;
+    data->name = NULL;
+    data->system_id = NULL;
+    data->direction = DM_DEVICE_DIRECTION_NONE;
+
+    data->playback_pcms= pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    data->capture_pcms = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
+    data->n_profile = 0;
+}
+
+void pa_tz_device_new_data_set_type(pa_tz_device_new_data *data, const char *type) {
+    pa_assert(data);
+
+    data->type = pa_xstrdup(type);
+}
+
+void pa_tz_device_new_data_set_name(pa_tz_device_new_data *data, const char *name) {
+    pa_assert(data);
+
+    data->name = pa_xstrdup(name);
+}
+
+void pa_tz_device_new_data_set_direction(pa_tz_device_new_data *data, dm_device_direction_t direction) {
+    pa_assert(data);
+
+    data->direction = direction;
+}
+/* only for external? */
+void pa_tz_device_new_data_set_system_id(pa_tz_device_new_data *data, const char *system_id) {
+    pa_assert(data);
+
+    data->system_id = pa_xstrdup(system_id);
+}
+
+void pa_tz_device_new_data_set_use_internal_codec(pa_tz_device_new_data *data, bool use_internal_codec) {
+    pa_assert(data);
+
+    data->use_internal_codec = use_internal_codec;
+}
+
+void pa_tz_device_new_data_add_sink(pa_tz_device_new_data *data, const char *role, pa_sink *sink) {
+    pa_assert(data);
+
+    pa_hashmap_put(data->playback_pcms, (void*)role, sink);
+}
+
+void pa_tz_device_new_data_add_source(pa_tz_device_new_data *data, const char *role, pa_source *source) {
+    pa_assert(data);
+
+    pa_hashmap_put(data->playback_pcms, (void*)role, source);
+}
+/* after set_type, only for multi profile type, and check direction, profile */
+void pa_tz_device_new_data_add_profile(pa_tz_device_new_data *data, pa_tz_profile_new_data *profile_data, bool as_active) {
+    uint32_t profile_idx;
+    pa_assert(data);
+
+    profile_idx = data->n_profile;
+    data->profile_data[profile_idx] = profile_data;
+    if (as_active)
+        data->active_profile = profile_idx;
+
+    data->n_profile++;
+}
+
+void pa_tz_device_new_data_done(pa_tz_device_new_data *data) {
+    pa_assert(data);
+
+    pa_xfree(data->type);
+    pa_xfree(data->name);
+}
+
+static int _check_valid_device_new_data(pa_tz_device_new_data *data) {
+    bool is_multi_profile;
+    pa_assert(data);
+
+    if (data->type == NULL) {
+        pa_log_error("new data type is null");
+        return -1;
+    }
+
+    is_multi_profile = device_type_is_multi_profile(data->type);
+
+    if (is_multi_profile == false && data->direction == DM_DEVICE_DIRECTION_NONE) {
+        pa_log_error("new data direction is none");
+        return -1;
+    }
+
+    if (is_multi_profile == true && data->n_profile == 0) {
+        pa_log_error("multi profile type, but there is no profile");
+        return -1;
+    }
+    if (is_multi_profile == false && data->n_profile > 0) {
+        pa_log_error("not multi profile type, but there are profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+static pa_tz_profile* profile_new(char *profile_str, dm_device_direction_t direction,
+        pa_hashmap *playbacks, pa_hashmap *captures, bool use_internal_codec, pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_log_info("New profile(%s) direction(%s), for device(%u)",
+            pa_strempty(profile_str), device_direction_to_string(direction), device->id);
+
+    profile = pa_xmalloc(sizeof(pa_tz_profile));
+
+    profile->profile = pa_xstrdup(profile_str);
+    profile->playback_devices = playbacks;
+    profile->capture_devices = captures;
+    profile->direction = direction;
+    profile->playback_state = DM_DEVICE_STATE_DEACTIVATED;
+    profile->capture_state = DM_DEVICE_STATE_DEACTIVATED;
+    profile->device = device;
+    profile->creation_time = pa_rtclock_now();
+    profile->use_internal_codec = use_internal_codec;
+    profile->sco_opened = false;
+
+    return profile;
+}
+
+static void profile_free(pa_tz_profile *profile) {
+    if (!profile)
+        return;
+
+    pa_log_info("Free profile(%s) for device(%u)",
+            pa_strempty(profile->profile), profile->device->id);
+
+    pa_xfree(profile->profile);
+
+    if (profile->playback_devices)
+        pa_hashmap_free(profile->playback_devices);
+    if (profile->capture_devices)
+        pa_hashmap_free(profile->capture_devices);
+
+    pa_xfree(profile);
+}
+
+static int profile_add_sink(pa_tz_profile *profile, const char *role, pa_sink *sink) {
+    pa_assert(profile);
+
+    if (pa_hashmap_put(profile->playback_devices, (void*)role, sink) < 0) {
+        pa_log_error("Failed to add sink : put sink failed");
+        return -1;
+    }
+    return 0;
+}
+
+static int profile_add_source(pa_tz_profile *profile, const char *role, pa_source *source) {
+    pa_assert(profile);
+
+    if (pa_hashmap_put(profile->playback_devices, (void*)role, source) < 0) {
+        pa_log_error("Failed to add source : put source failed");
+        return -1;
+    }
+    return 0;
+}
+
+static pa_sink* profile_get_sink(pa_tz_profile *profile, const char *role) {
+    pa_sink *sink;
+    pa_assert(profile);
+
+    if ((sink = pa_hashmap_get(profile->playback_devices, role)) == NULL) {
+        pa_log_warn("Failed to get sink for %s", role);
+        return NULL;
+    }
+
+    return sink;
+}
+
+static pa_source* profile_get_source(pa_tz_profile *profile, const char *role) {
+    pa_source *source;
+    pa_assert(profile);
+
+    if ((source = pa_hashmap_get(profile->playback_devices, role)) == NULL) {
+        pa_log_warn("Failed to get source for %s", role);
+        return NULL;
+    }
+
+    return source;
+}
+
+static void profile_set_state(pa_tz_profile *profile, dm_device_direction_t direction, dm_device_state_t state) {
+    dm_device_state_t prev_state, new_state;
+    pa_assert(profile);
+
+    prev_state = COMPOUND_STATE(profile);
+    pa_log_debug("previous playback_state : %d, capture_state : %d => state %d", profile->playback_state, profile->capture_state, prev_state);
+    if (direction & DM_DEVICE_DIRECTION_IN)
+        profile->capture_state = state;
+    if (direction & DM_DEVICE_DIRECTION_OUT)
+        profile->playback_state = state;
+    new_state = COMPOUND_STATE(profile);
+    pa_log_debug("new playback_state : %d, capture_state : %d => state %d", profile->playback_state, profile->capture_state, new_state);
+
+    if (prev_state != new_state) {
+        notify_device_info_changed(profile->device, DM_DEVICE_CHANGED_INFO_STATE);
+        pa_tz_device_dump_info(profile->device, PA_LOG_DEBUG);
+    }
+}
+
+static dm_device_state_t profile_get_state(pa_tz_profile *profile, dm_device_direction_t direction) {
+    pa_assert(profile);
+
+    if (direction == DM_DEVICE_DIRECTION_BOTH)
+        return COMPOUND_STATE(profile);
+    else if (direction == DM_DEVICE_DIRECTION_OUT)
+        return profile->playback_state;
+    else if (direction == DM_DEVICE_DIRECTION_IN)
+        return profile->capture_state;
+    else
+        return DM_DEVICE_STATE_DEACTIVATED;
+}
+
+static int profile_remove_sink_with_role(pa_tz_profile *profile, const char *role) {
+    pa_sink *sink;
+    pa_assert(profile);
+
+    sink = pa_hashmap_remove(profile->playback_devices, role);
+    return sink ? 0 : -1;
+}
+
+static int profile_remove_source_with_role(pa_tz_profile *profile, const char *role) {
+    pa_source *source;
+    pa_assert(profile);
+
+    source = pa_hashmap_remove(profile->capture_devices, role);
+    return source ? 0 : -1;
+}
+
+static int profile_remove_sink(pa_tz_profile *profile, pa_sink *sink) {
+    pa_sink *_sink;
+    void *state;
+    char *role;
+
+    pa_assert(profile);
+
+    PA_HASHMAP_FOREACH_KEY(_sink, profile->playback_devices, state, role) {
+        if (sink == _sink)
+            return profile_remove_sink_with_role(profile, role);
+    }
+
+    return -1;
+}
+
+static int profile_remove_source(pa_tz_profile *profile, pa_source *source) {
+    pa_source *_source;
+    void *state;
+    char *role;
+
+    pa_assert(profile);
+
+    PA_HASHMAP_FOREACH_KEY(_source, profile->capture_devices, state, role) {
+        if (source == _source)
+            return profile_remove_source_with_role(profile, role);
+    }
+
+    return -1;
+}
+
+/* pa_tz_device */
+pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) {
+    pa_tz_device *device;
+    pa_sink *sink;
+    pa_source *source;
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+
+    pa_assert(data);
+
+    if (_check_valid_device_new_data(data) < 0) {
+        pa_log_error("Invalid device_new_data");
+        return NULL;
+    }
+
+    device = pa_xmalloc(sizeof(pa_tz_device));
+    device->list = data->list;
+    device->comm = data->comm;
+    device->dbus_conn = data->dbus_conn;
+
+    device->id = device_id_max_g++;
+    device->type = pa_xstrdup(data->type);
+    if (data->name)
+        device->name = pa_xstrdup(data->name);
+    else
+        device->name = pa_xstrdup(data->type);
+    device->system_id = pa_xstrdup(data->system_id);
+    device->active_profile = 0;
+
+    pa_log_info("New device type(%s) id(%u) name(%s) system_id(%s)",
+            device->type, device->id, device->name, pa_strempty(device->system_id));
+
+    device->profiles = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+
+    /* If multi profile type, get from data->profile_data */
+    if (device_type_is_multi_profile(data->type)) {
+        pa_tz_profile_new_data *pdata;
+        for (int i = 0; i < data->n_profile; i++) {
+            pdata = data->profile_data[i];
+            profile = profile_new(pdata->profile, pdata->direction,
+                    pdata->playback_pcms, pdata->capture_pcms, pdata->use_internal_codec, device);
+            pa_idxset_put(device->profiles, profile, NULL);
+        }
+        device->active_profile = data->active_profile;
+    } else {
+        profile = profile_new(NULL, data->direction,
+                data->playback_pcms, data->capture_pcms, data->use_internal_codec, device);
+        pa_idxset_put(device->profiles, profile, NULL);
+    }
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
+        if (device_type_is_use_external_card(device->type, profile->profile)) {
+            if ((sink = profile_get_sink(profile, DEVICE_ROLE_NORMAL)))
+                sink->device_item = device;
+            if ((source = profile_get_source(profile, DEVICE_ROLE_NORMAL)))
+                source->device_item = device;
+        }
+    }
+
+    pa_idxset_put(device->list, device, NULL);
+    notify_device_connection_changed(device, true);
+
+    pa_tz_device_dump_info(device, PA_LOG_INFO);
+
+    return device;
+}
+
+static uint32_t _get_profile_idx(pa_tz_device *device, const char *profile_str) {
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+
+    pa_assert(device);
+    pa_assert(device->profiles);
+
+    if (profile_str == NULL || pa_streq(profile_str, "")) {
+        pa_idxset_first(device->profiles, &profile_idx);
+        return profile_idx;
+    }
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
+        if (device_profile_is_equal(profile->profile, profile_str))
+            return profile_idx;
+    }
+
+    return PA_INVALID_INDEX;
+}
+
+static pa_tz_profile* _get_profile(pa_tz_device *device, const char *profile_str) {
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+
+    pa_assert(device);
+    pa_assert(device->profiles);
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
+        if (device_profile_is_equal(profile->profile, profile_str))
+            return profile;
+    }
+
+    return NULL;
+}
+
+static pa_tz_profile* _get_profile_by_idx(pa_tz_device *device, uint32_t profile_idx) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    profile = pa_idxset_get_by_index(device->profiles, profile_idx);
+    if (profile == NULL)
+        pa_log_error("No profile(%u) in device(%u)", profile_idx, device->id);
+
+    return profile;
+}
+
+
+static pa_tz_profile* _get_active_profile(pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    profile = _get_profile_by_idx(device, device->active_profile);
+    if (profile == NULL)
+        pa_log_error("Failed to find active profile(%u)", device->active_profile);
+
+    return profile;
+}
+
+/* if noti_always is true, always noti this change without checking index
+ * if profile is null, set first profile as active */
+int _set_active_profile(pa_tz_device *device, const char *profile, bool noti_always) {
+    uint32_t profile_idx, prev_active_idx;
+
+    pa_assert(device);
+
+    pa_log_info("Set active profile, device(%u) profile(%s)",
+            device->id, pa_strempty(profile));
+
+    prev_active_idx = device->active_profile;
+    profile_idx = _get_profile_idx(device, profile);
+    if (profile_idx == PA_INVALID_INDEX) {
+        pa_log_error("index for profile(%s) is invalid", pa_strempty(profile));
+        return -1;
+    }
+    device->active_profile = profile_idx;
+    pa_log_info("new active profile index %u", profile_idx);
+
+    /* Compare index only when check_idx is true */
+    if (noti_always || prev_active_idx != device->active_profile)
+        notify_device_info_changed(device, DM_DEVICE_CHANGED_INFO_IO_DIRECTION);
+
+    return 0;
+}
+
+/* only for multi profile type */
+int pa_tz_device_add_profile(pa_tz_device *device, pa_tz_profile_new_data *pdata, bool as_active) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(device->profiles);
+
+    pa_log_info("device add profile, device(%u) profile(%s) as_active(%s)",
+            device->id, pa_strempty(pdata->profile), pa_yes_no(as_active));
+
+    if (device_type_is_multi_profile(device->type) == false) {
+        pa_log_error("Failed to add profile : not multi profile type");
+        return -1;
+    }
+    if (pa_idxset_size(device->profiles) >= PROFILE_NUM_MAX) {
+        pa_log_error("Failed to add profile : Too many profiles");
+        return -1;
+    }
+
+    profile = profile_new(pdata->profile, pdata->direction,
+            pdata->playback_pcms, pdata->capture_pcms, pdata->use_internal_codec, device);
+    pa_idxset_put(device->profiles, profile, NULL);
+
+    if (as_active)
+        _set_active_profile(device, pdata->profile, true);
+    pa_tz_device_dump_info(device, PA_LOG_INFO);
+
+    return 0;
+}
+
+int pa_tz_device_remove_profile(pa_tz_device *device, const char *profile_str) {
+    pa_tz_profile *profile;
+    uint32_t profile_idx, remove_idx;
+    bool found = false;
+    unsigned profile_num;
+
+    pa_assert(device);
+    pa_assert(device->profiles);
+
+    pa_log_info("device remove profile, device(%u) profile(%s)",
+            device->id, pa_strempty(profile_str));
+
+    if (device_type_is_multi_profile(device->type) == false) {
+        pa_log_error("Failed to add profile : not multi profile type");
+        return -1;
+    }
+
+    if ((profile_num = pa_tz_device_get_profile_num(device)) <= 1) {
+        pa_log_error("This device have too small profiles %u, Should be freed", profile_num);
+        return -1;
+    }
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx) {
+        if (pa_safe_streq(profile->profile, profile_str)) {
+            pa_log_info("found matching profile to remove");
+            found = true;
+            remove_idx = profile_idx;
+        }
+    }
+
+    if (found) {
+        pa_idxset_remove_by_index(device->profiles, remove_idx);
+        /* change active profile if removed one was active */
+        if (device->active_profile == remove_idx)
+            _set_active_profile(device, NULL, true);
+        pa_tz_device_dump_info(device, PA_LOG_INFO);
+        return 0;
+    } else {
+        pa_log_warn("no matching profile to remove");
+        return -1;
+    }
+}
+
+/* only for single profile type */
+int pa_tz_device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(device_role_is_valid(role));
+    pa_assert(sink);
+
+    pa_log_info("device add sink, device(%u) role(%s) sink(%s)",
+            device->id, role, sink->name);
+
+    if (pa_tz_device_get_profile_num(device) > 1) {
+        pa_log_error("Failed to add sink : Too many profiles");
+        return -1;
+    }
+
+    profile = pa_idxset_first(device->profiles, NULL);
+
+    if (profile_add_sink(profile, role, sink) < 0) {
+        pa_log_error("Failed to add sink : Can't add to profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_add_source(pa_tz_device *device, const char *role, pa_source *source) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(device_role_is_valid(role));
+    pa_assert(source);
+
+    pa_log_info("device add source, device(%u) role(%s) source(%s)",
+            device->id, role, source->name);
+
+    if (pa_tz_device_get_profile_num(device) > 1) {
+        pa_log_warn("Failed to add source : Too many profiles");
+        return -1;
+    }
+
+    profile = pa_idxset_first(device->profiles, NULL);
+
+    if (profile_add_source(profile, role, source) < 0) {
+        pa_log_error("Failed to add source : Can't add to profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_remove_sink(pa_tz_device *device, pa_sink *sink) {
+    pa_tz_profile *profile;
+    int removed = 0;
+    uint32_t profile_idx;
+
+    pa_assert(device);
+    pa_assert(sink);
+
+    pa_log_info("device remove sink, device(%u) sink(%s)",
+            device->id, sink->name);
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
+        removed &= profile_remove_sink(profile, sink);
+
+    return removed;
+}
+
+int pa_tz_device_remove_source(pa_tz_device *device, pa_source *source) {
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+    int removed = 0;
+
+    pa_assert(device);
+    pa_assert(source);
+
+    pa_log_info("device remove source, device(%u) source(%s)",
+            device->id, source->name);
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
+        removed &= profile_remove_source(profile, source);
+
+    return removed;
+}
+
+int pa_tz_device_remove_sink_with_role(pa_tz_device *device, const char *role) {
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+    int removed = 0;
+
+    pa_assert(device);
+    pa_assert(device_role_is_valid(role));
+
+    pa_log_info("device remove sink with role, device(%u) role(%s)",
+            device->id, role);
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
+        removed &= profile_remove_sink_with_role(profile, role);
+
+    return removed;
+}
+
+int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role) {
+    pa_tz_profile *profile;
+    uint32_t profile_idx;
+    int removed = 0;
+
+    pa_assert(device);
+    pa_assert(device_role_is_valid(role));
+
+    pa_log_info("device remove source with role, device(%u) role(%s)",
+            device->id, role);
+
+    PA_IDXSET_FOREACH(profile, device->profiles, profile_idx)
+        removed &= profile_remove_source_with_role(profile, role);
+
+    return removed;
+}
+
+/* only for multi profile */
+int pa_tz_device_profile_add_sink(pa_tz_device *device, const char *profile_str, const char *role, pa_sink *sink) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    pa_log_info("device profile add sink, device(%u) profile(%s) role(%s) sink(%s)",
+            device->id, pa_strempty(profile_str), role, sink->name);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return -1;
+    }
+
+    if (profile_add_sink(profile, role, sink) < 0) {
+        pa_log_error("Can't add to profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_profile_add_source(pa_tz_device *device, const char *profile_str, const char *role, pa_source *source) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    pa_log_info("device profile add source, device(%u) profile(%s) role(%s) source(%s)",
+            device->id, pa_strempty(profile_str), role, source->name);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return -1;
+    }
+
+    if (profile_add_source(profile, role, source) < 0) {
+        pa_log_error("Can't add to profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_profile_remove_sink(pa_tz_device *device, const char *profile_str, pa_sink *sink) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    pa_log_info("device profile remove sink, device(%u) profile(%s) sink(%s)",
+            device->id, pa_strempty(profile_str), sink->name);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return -1;
+    }
+
+    if (profile_remove_sink(profile, sink) < 0) {
+        pa_log_error("Can't remove from profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_profile_remove_source(pa_tz_device *device, const char *profile_str, pa_source *source) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    pa_log_info("device profile remove source, device(%u) profile(%s) source(%s)",
+            device->id, pa_strempty(profile_str), source->name);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return -1;
+    }
+
+    if (profile_remove_source(profile, source) < 0) {
+        pa_log_error("Can't remove from profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_profile_remove_sink_with_role(pa_tz_device *device, const char *profile_str, const char *role) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(device_role_is_valid(role));
+
+    pa_log_info("device profile remove sink with role, device(%u) profile(%s) role(%s)",
+            device->id, pa_strempty(profile_str), role);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return -1;
+    }
+
+    if (profile_remove_sink_with_role(profile, role) < 0) {
+        pa_log_error("Can't remove from profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_tz_device_profile_remove_source_with_role(pa_tz_device *device, const char *profile_str, const char *role) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(device_role_is_valid(role));
+
+    pa_log_info("device profile remove source with role, device(%u) profile(%s) role(%s)",
+            device->id, pa_strempty(profile_str), role);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return -1;
+    }
+
+    if (profile_remove_source_with_role(profile, role) < 0) {
+        pa_log_error("Can't remove from profile");
+        return -1;
+    }
+
+    return 0;
+}
+
+pa_sink* pa_tz_device_profile_get_sink(pa_tz_device *device, const char *profile_str, const char *role) {
+    pa_sink *sink;
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    pa_log_info("device profile get sink, device(%u) profile(%s) role(%s)",
+            device->id, pa_strempty(profile_str), role);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return NULL;
+    }
+
+    if ((sink = profile_get_sink(profile, role)) == NULL) {
+        pa_log_error("Can't get sink from profile");
+        return NULL;
+    }
+
+    return sink;
+}
+
+pa_source* pa_tz_device_profile_get_source(pa_tz_device *device, const char *profile_str, const char *role) {
+    pa_source *source;
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+
+    pa_log_info("device profile get source, device(%u) profile(%s) role(%s)",
+            device->id, pa_strempty(profile_str), role);
+
+    if ((profile = _get_profile(device, profile_str)) == NULL) {
+        pa_log_error("Can't get profile %s", profile_str);
+        return NULL;
+    }
+
+    if ((source = profile_get_source(profile, role)) == NULL) {
+        pa_log_error("Can't get source from profile");
+        return NULL;
+    }
+
+    return source;
+}
+
+void pa_tz_device_free(pa_tz_device *device) {
+    pa_assert(device);
+
+    pa_log_info("Free device type(%s) id(%u) name(%s) system_id(%s)",
+            device->type, device->id, device->name, device->system_id);
+
+    pa_tz_device_dump_info(device, PA_LOG_INFO);
+
+    pa_idxset_remove_by_data(device->list, device, NULL);
+    notify_device_connection_changed(device, false);
+
+    pa_xfree(device->type);
+    pa_xfree(device->name);
+    pa_xfree(device->system_id);
+
+    pa_idxset_free(device->profiles, (pa_free_cb_t)profile_free);
+
+    pa_xfree(device);
+}
+
+/* pa_tz_profile_new_data */
+void pa_tz_profile_new_data_init(pa_tz_profile_new_data *profile_data) {
+    pa_assert(profile_data);
+
+    profile_data->profile = NULL;
+    profile_data->direction = DM_DEVICE_DIRECTION_NONE;
+
+    profile_data->playback_pcms= pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    profile_data->capture_pcms = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+}
+
+void pa_tz_profile_new_data_set_direction(pa_tz_profile_new_data *profile_data, dm_device_direction_t direction) {
+    pa_assert(profile_data);
+
+    profile_data->direction = direction;
+}
+
+void pa_tz_profile_new_data_set_profile(pa_tz_profile_new_data *profile_data, const char *profile) {
+    pa_assert(profile_data);
+
+    profile_data->profile = pa_xstrdup(profile);
+}
+
+void pa_tz_profile_new_data_set_use_internal_codec(pa_tz_profile_new_data *profile_data, bool use_internal_codec) {
+    pa_assert(profile_data);
+    profile_data->use_internal_codec = use_internal_codec;
+}
+
+void pa_tz_profile_new_data_add_sink(pa_tz_profile_new_data *profile_data, const char *role, pa_sink *sink) {
+    pa_assert(profile_data);
+
+    pa_hashmap_put(profile_data->playback_pcms, (void*)role, sink);
+}
+
+void pa_tz_profile_new_data_add_source(pa_tz_profile_new_data *profile_data, const char *role, pa_source *source) {
+    pa_assert(profile_data);
+
+    pa_hashmap_put(profile_data->capture_pcms, (void*)role, source);
+}
+
+void pa_tz_profile_new_data_done(pa_tz_profile_new_data *profile_data) {
+    pa_assert(profile_data);
+
+    pa_xfree(profile_data->profile);
+}
+
+/* exported api */
+pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role) {
+    pa_tz_profile *profile;
+    pa_sink *sink;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    pa_log_info("device get sink, device(%u) role(%s), active-profile(%s)",
+            device->id, role, pa_strempty(profile->profile));
+
+    if ((sink = profile_get_sink(profile, role)) == NULL) {
+        pa_log_error("Failed to get sink from profile");
+        return NULL;
+    }
+
+    return sink;
+}
+
+pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role) {
+    pa_tz_profile *profile;
+    pa_source *source;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    pa_log_info("device get source, device(%u) role(%s), active-profile(%s)",
+            device->id, role, pa_strempty(profile->profile));
+
+    if ((source = profile_get_source(profile, role)) == NULL) {
+        pa_log_error("Failed to get source from profile");
+        return NULL;
+    }
+
+    return source;
+}
+
+void pa_tz_device_set_state(pa_tz_device *device, dm_device_direction_t direction, dm_device_state_t state) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    pa_log_info("device set state, device(%u) type(%s) active-profile(%s) direction(%s) -> %d",
+            device->id, device->type, pa_strempty(profile->profile), device_direction_to_string(direction), state);
+    profile_set_state(profile, direction, state);
+}
+
+dm_device_state_t pa_tz_device_get_state(pa_tz_device *device, dm_device_direction_t direction) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    return profile_get_state(profile, direction);
+}
+
+uint32_t pa_tz_device_get_id(pa_tz_device *device) {
+    pa_assert(device);
+
+    return device->id;
+}
+
+char* pa_tz_device_get_type(pa_tz_device *device) {
+    pa_assert(device);
+
+    return device->type;
+}
+
+char* pa_tz_device_get_name(pa_tz_device *device) {
+    pa_assert(device);
+
+    return device->name;
+}
+
+char* pa_tz_device_get_system_id(pa_tz_device *device) {
+    pa_assert(device);
+
+    return device->system_id;
+}
+
+char* pa_tz_device_get_profile(pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    return profile->profile;
+}
+
+dm_device_direction_t pa_tz_device_get_direction(pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    return profile->direction;
+}
+
+pa_usec_t pa_tz_device_get_creation_time(pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    return profile->creation_time;
+}
+
+bool pa_tz_device_is_use_internal_codec(pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(profile = _get_active_profile(device));
+
+    return profile->use_internal_codec;
+}
+
+unsigned pa_tz_device_get_profile_num(pa_tz_device *device) {
+    pa_assert(device);
+    pa_assert(device->profiles);
+
+    return pa_idxset_size(device->profiles);
+}
+
+bool pa_tz_device_have_profile(pa_tz_device *device, const char *profile) {
+    pa_assert(device);
+
+    if (_get_profile(device, profile) == NULL)
+        return false;
+    else
+        return true;
+}
+
+static int method_call_bt_sco(pa_dbus_connection *conn, bool onoff) {
+    DBusMessage *msg, *reply;
+    DBusError err;
+    const char *method;
+
+    pa_assert(conn);
+
+    method = onoff ? "Play" : "Stop";
+    if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, method))) {
+        pa_log_error("dbus method call failed");
+        return -1;
+    }
+
+    dbus_error_init(&err);
+    if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
+        pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, method, err.message);
+        dbus_error_free(&err);
+        return -1;
+    }
+
+    dbus_message_unref(reply);
+    return 0;
+}
+
+static int method_call_bt_sco_get_property(pa_dbus_connection *conn, bool *is_wide_band, bool *nrec) {
+    DBusMessage *msg, *reply;
+    DBusMessageIter reply_iter, reply_iter_entry;
+    DBusError err;
+    unsigned int codec;
+    const char *property;
+
+    pa_assert(conn);
+
+    if (!is_wide_band && !nrec) {
+        return -1;
+    }
+
+    if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_HFP_AGENT, DBUS_OBJECT_HFP_AGENT, DBUS_INTERFACE_HFP_AGENT, "GetProperties"))) {
+        pa_log_error("dbus method call failed");
+        return -1;
+    }
+
+    dbus_error_init(&err);
+    if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(conn), msg, -1, &err))) {
+        pa_log_error("Failed to method call %s.%s, %s", DBUS_INTERFACE_HFP_AGENT, "GetProperties", err.message);
+        dbus_error_free(&err);
+        return -1;
+    }
+
+    dbus_message_iter_init(reply,  &reply_iter);
+
+    if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+        pa_log_error("Cannot get reply argument");
+        return -1;
+    }
+
+    dbus_message_iter_recurse(&reply_iter,  &reply_iter_entry);
+
+    while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) {
+        DBusMessageIter dict_entry, dict_entry_val;
+        dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
+        dbus_message_iter_get_basic(&dict_entry, &property);
+        pa_log_debug("String received = %s", property);
+        if (property) {
+            if (pa_streq("codec", property) && is_wide_band) {
+                dbus_message_iter_next(&dict_entry);
+                dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
+                if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_UINT32)
+                    continue;
+                dbus_message_iter_get_basic(&dict_entry_val, &codec);
+                pa_log_debug("Codec = [%d]", codec);
+                *is_wide_band = (codec == BT_MSBC_CODEC_ID) ? true : false;
+            } else if (pa_streq("nrec", property) && nrec) {
+                dbus_message_iter_next(&dict_entry);
+                dbus_message_iter_recurse(&dict_entry, &dict_entry_val);
+                if (dbus_message_iter_get_arg_type(&dict_entry_val) != DBUS_TYPE_BOOLEAN)
+                    continue;
+                dbus_message_iter_get_basic(&dict_entry_val, nrec);
+                pa_log_debug("nrec= [%d]", *nrec);
+            }
+        }
+        dbus_message_iter_next(&reply_iter_entry);
+    }
+
+
+    dbus_message_unref(reply);
+    return 0;
+}
+
+/* only for bt device, which have sco profile */
+int pa_tz_device_sco_open(pa_tz_device *device) {
+    pa_tz_profile *profile;
+
+    pa_assert(device);
+    pa_assert(device->dbus_conn);
+
+    pa_log_info("BT SCO Open for device(%u)", device->id);
+    if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
+        pa_log_error("Not BT device");
+        return -1;
+    }
+    if ((profile = _get_profile(device, DEVICE_PROFILE_BT_SCO)) == NULL) {
+        pa_log_error("No BT SCO profile");
+        return -1;
+    }
+
+    if (profile->sco_opened) {
+        pa_log_warn("SCO already opened");
+        return -1;
+    }
+
+    if (method_call_bt_sco(device->dbus_conn, true) < 0) {
+        pa_log_error("Failed to bt sco on");
+        return -1;
+    }
+
+    profile->sco_opened = true;
+    _set_active_profile(device, DEVICE_PROFILE_BT_SCO, false);
+    pa_tz_device_dump_info(profile->device, PA_LOG_DEBUG);
+    pa_log_info("BT SCO Open - SUCCESS");
+
+    return 0;
+}
+
+/* only for bt device, which have sco profile */
+int pa_tz_device_sco_close(pa_tz_device *device) {
+    pa_tz_profile *profile;
+    pa_assert(device);
+
+    pa_log_info("BT SCO Close for device(%u)", device->id);
+
+    if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
+        pa_log_error("Not BT device");
+        return -1;
+    }
+    if ((profile = _get_profile(device, DEVICE_PROFILE_BT_SCO)) == NULL) {
+        pa_log_error("No BT SCO profile");
+        return -1;
+    }
+
+    if (profile->sco_opened == false) {
+        pa_log_warn("SCO not opened");
+        return -1;
+    }
+
+    if (method_call_bt_sco(device->dbus_conn, false) < 0) {
+        pa_log_error("Failed to bt sco on");
+        return -1;
+    }
+
+    profile->sco_opened = false;
+    if (pa_tz_device_have_profile(device, DEVICE_PROFILE_BT_A2DP))
+        _set_active_profile(device, DEVICE_PROFILE_BT_A2DP, false);
+    pa_tz_device_dump_info(profile->device, PA_LOG_DEBUG);
+    pa_log_info("BT SCO Close - Success");
+
+    return 0;
+}
+
+/* only for bt device, which have sco profile */
+int pa_tz_device_sco_get_property(pa_tz_device *device, bool *is_wide_band, bool *nrec) {
+    pa_assert(device);
+
+    pa_log_info("BT SCO get property for device(%u)", device->id);
+    if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
+        pa_log_error("Not BT device");
+        return -1;
+    }
+    if ((_get_profile(device, DEVICE_PROFILE_BT_SCO)) == NULL) {
+        pa_log_error("No BT SCO profile");
+        return -1;
+    }
+
+    if (method_call_bt_sco_get_property(device->dbus_conn, is_wide_band, nrec) < 0) {
+        pa_log_error("Failed to get BT SCO Property");
+        return -1;
+    }
+
+    pa_log_info("BT SCO Get Property - Success, is wide band : %s, nrec : %s", pa_yes_no(is_wide_band), pa_yes_no(nrec));
+
+    return 0;
+}
+
+/* only for bt device */
+int pa_tz_device_sco_get_status(pa_tz_device *device, dm_device_bt_sco_status_t *status) {
+    pa_tz_profile *profile;
+    pa_assert(device);
+
+    pa_log_info("BT SCO get status for device(%u)", device->id);
+    if (pa_streq(device->type, DEVICE_TYPE_BT) == false) {
+        pa_log_error("Not BT device");
+        return -1;
+    }
+    if (status == NULL) {
+        pa_log_error("invalid parameter");
+        return -1;
+    }
+
+    if ((profile = _get_profile(device, DEVICE_PROFILE_BT_SCO))) {
+        if (profile->sco_opened == false)
+            *status = DM_DEVICE_BT_SCO_STATUS_CONNECTED;
+        else
+            *status = DM_DEVICE_BT_SCO_STATUS_OPENED;
+    } else {
+        *status = DM_DEVICE_BT_SCO_STATUS_DISCONNECTED;
+    }
+
+    pa_log_debug("BT SCO Get Status, %d", *status);
+    return 0;
+}
+
diff --git a/src/tizen-device.h b/src/tizen-device.h
new file mode 100644 (file)
index 0000000..9cd4f75
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef footizendevicefoo
+#define footizendevicefoo
+
+#include <pulsecore/core.h>
+#include "tizen-device-def.h"
+#include "communicator.h"
+#ifdef HAVE_DBUS
+#include <pulsecore/dbus-shared.h>
+#include <pulsecore/dbus-util.h>
+#endif
+
+typedef struct pa_tz_device pa_tz_device;
+typedef struct pa_tz_profile pa_tz_profile;
+typedef struct pa_tz_device_new_data pa_tz_device_new_data;
+typedef struct pa_tz_profile_new_data pa_tz_profile_new_data;
+
+/* structures for represent device items which can be connected/disconnected */
+/*
+    Before beginning, There are two structure(pa_tz_device, pa_tz_profile)
+    for represent device by following reasons.
+    When bt-a2dp and bt-sco are on physically same device ,it is of course same device.
+    So those physically same device item are represended by pa_tz_device,
+    and each profile is represented by pa_tz_profile.
+*/
+
+/*
+    Structure to represent physicall device,
+    which can have multiple profiles (ex. bt-a2dp and sco).
+    If this is created or freed, device connected/disconnected
+    hook(for internal)/callback(for apps) will be called.
+*/
+struct pa_tz_device {
+    char *type;
+    char *name;
+    /* Decimal ID which is unique in device list
+     * This will be exported up to sound_manager_get_device_id */
+    uint32_t id;
+    /* String ID which will be used internally
+     * In multi-Device case(bt, usb), this will be used to classify
+     * each physicall device */
+    char *system_id;
+
+    /* Even though there are several profiles in device,
+     * only one profile can be activated.
+     * This indicate current activat profile */
+    uint32_t active_profile;
+    /* Have only one item except bt device */
+    /* pa_tz_profile* profiles[PROFILE_NUM_MAX]; */
+    pa_idxset *profiles;
+
+    /* Devices are contained in this list */
+    pa_idxset *list;
+
+    pa_communicator *comm;
+    pa_dbus_connection *dbus_conn;
+};
+
+struct pa_tz_device_new_data {
+    char *type;
+    char *name;
+    /* for multi-device type(bt, usb) */
+    char *system_id;
+
+    /* for solo profile type */
+    dm_device_direction_t direction;
+    bool use_internal_codec;
+    pa_hashmap *playback_pcms;
+    pa_hashmap *capture_pcms;
+
+    /* for multi profile type */
+    pa_tz_profile_new_data* profile_data[PROFILE_NUM_MAX];
+    uint32_t n_profile;
+    uint32_t active_profile;
+
+    pa_idxset *list;
+    pa_communicator *comm;
+    pa_dbus_connection *dbus_conn;
+};
+
+struct pa_tz_profile_new_data {
+    char *profile;
+    dm_device_direction_t direction;
+
+    pa_hashmap *playback_pcms;
+    pa_hashmap *capture_pcms;
+
+    bool use_internal_codec;
+};
+
+/*
+    Structure to represent each device profile (subtype).
+    Even if both-way device(earjack, sco..) ,one device_profile.
+*/
+struct pa_tz_profile {
+    /* This can be null except bt device */
+    char *profile;
+    dm_device_direction_t direction;
+
+    /* Set by stream-manager
+     * If this is changed, will be notifacted */
+    dm_device_state_t playback_state;
+    dm_device_state_t capture_state;
+
+    /* Can get proper sink/source in hashmaps with key(=device_role) */
+    pa_hashmap *playback_devices;
+    pa_hashmap *capture_devices;
+
+    /* device belongs to */
+    pa_tz_device *device;
+
+    /* creation time */
+    pa_usec_t creation_time;
+
+    /* Will be true, if this profile uses internal codec(card),
+     * false, if this profile uses external card(bt-a2dp, usb */
+    bool use_internal_codec;
+    /* If this is sco profile, this can be used to */
+    bool sco_opened;
+};
+
+typedef struct _hook_call_data_for_conn_changed {
+    uint32_t event_id;
+    bool is_connected;
+    pa_tz_device *device;
+} pa_device_manager_hook_data_for_conn_changed;
+
+typedef struct _hook_call_data_for_info_changed {
+    uint32_t event_id;
+    dm_device_changed_info_t changed_info;
+    pa_tz_device *device;
+} pa_device_manager_hook_data_for_info_changed;
+
+/*** For device manager ***/
+void pa_tz_device_dump_info(pa_tz_device *device, pa_log_level_t log_level);
+void pa_tz_device_new_data_init(pa_tz_device_new_data *data, pa_idxset *list, pa_communicator *comm, pa_dbus_connection *conn);
+void pa_tz_device_new_data_set_type(pa_tz_device_new_data *data, const char *type);
+void pa_tz_device_new_data_set_name(pa_tz_device_new_data *data, const char *name);
+void pa_tz_device_new_data_set_direction(pa_tz_device_new_data *data, dm_device_direction_t direction);
+/* deivce which is multi-device type should have system_id */
+void pa_tz_device_new_data_set_system_id(pa_tz_device_new_data *data, const char *system_id);
+void pa_tz_device_new_data_set_use_internal_codec(pa_tz_device_new_data *data, bool use_internal_codec);
+void pa_tz_device_new_data_add_sink(pa_tz_device_new_data *data, const char *role, pa_sink *sink);
+void pa_tz_device_new_data_add_source(pa_tz_device_new_data *data, const char *role, pa_source *source);
+void pa_tz_device_new_data_done(pa_tz_device_new_data *data);
+/* For multi profile device */
+void pa_tz_device_new_data_add_profile(pa_tz_device_new_data *data, pa_tz_profile_new_data *profile_data, bool as_active);
+
+/* Create tizen device instance,
+ * device connected hook will be fired */
+pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data);
+/* Destroy tizen device instance,
+ * device disconnected hook will be fired */
+void pa_tz_device_free(pa_tz_device *device);
+/* Can be used add/remove sink/source in runtime */
+int pa_tz_device_add_sink(pa_tz_device *device, const char *role, pa_sink *sink);
+int pa_tz_device_add_source(pa_tz_device *device, const char *role, pa_source *source);
+int pa_tz_device_remove_sink(pa_tz_device *device, pa_sink *sink);
+int pa_tz_device_remove_source(pa_tz_device *device, pa_source *source);
+int pa_tz_device_remove_sink_with_role(pa_tz_device *device, const char *role);
+int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role);
+
+/* For multi profile device */
+int pa_tz_device_add_profile(pa_tz_device *device, pa_tz_profile_new_data *pdata, bool as_active);
+int pa_tz_device_remove_profile(pa_tz_device *device, const char *profile);
+int pa_tz_device_profile_add_sink(pa_tz_device *device, const char *profile, const char *role, pa_sink *sink);
+int pa_tz_device_profile_add_source(pa_tz_device *device, const char *profile, const char *role, pa_source *source);
+int pa_tz_device_profile_remove_sink(pa_tz_device *device, const char *profile, pa_sink *sink);
+int pa_tz_device_profile_remove_source(pa_tz_device *device, const char *profile, pa_source *source);
+int pa_tz_device_profile_remove_sink_with_role(pa_tz_device *device, const char *profile, const char *role);
+int pa_tz_device_profile_remove_source_with_role(pa_tz_device *device, const char *profile, const char *role);
+pa_sink* pa_tz_device_profile_get_sink(pa_tz_device *device, const char *profile, const char *role);
+pa_source* pa_tz_device_profile_get_source(pa_tz_device *device, const char *profile, const char *role);
+
+/* This APIs can be used with pa_tz_device_new_data_add_profile or
+ * pa_tz_device_add_profile */
+void pa_tz_profile_new_data_init(pa_tz_profile_new_data *profile_data);
+void pa_tz_profile_new_data_set_direction(pa_tz_profile_new_data *profile_data, dm_device_direction_t direction);
+void pa_tz_profile_new_data_set_profile(pa_tz_profile_new_data *profile_data, const char *profile);
+void pa_tz_profile_new_data_set_use_internal_codec(pa_tz_profile_new_data *profile_data, bool use_internal_codec);
+void pa_tz_profile_new_data_add_sink(pa_tz_profile_new_data *profile_data, const char *role, pa_sink *sink);
+void pa_tz_profile_new_data_add_source(pa_tz_profile_new_data *profile_data, const char *role, pa_source *source);
+void pa_tz_profile_new_data_done(pa_tz_profile_new_data *profile_data);
+
+/* Exported API for other modules */
+pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role);
+pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role);
+void pa_tz_device_set_state(pa_tz_device *device, dm_device_direction_t direction, dm_device_state_t state);
+dm_device_state_t pa_tz_device_get_state(pa_tz_device *device, dm_device_direction_t direction);
+uint32_t pa_tz_device_get_id(pa_tz_device *device);
+char* pa_tz_device_get_type(pa_tz_device *device);
+char* pa_tz_device_get_name(pa_tz_device *device);
+char* pa_tz_device_get_system_id(pa_tz_device *device);
+char* pa_tz_device_get_profile(pa_tz_device *device);
+dm_device_direction_t pa_tz_device_get_direction(pa_tz_device *device);
+pa_usec_t pa_tz_device_get_creation_time(pa_tz_device *device);
+bool pa_tz_device_is_use_internal_codec(pa_tz_device *device);
+unsigned pa_tz_device_get_profile_num(pa_tz_device *device);
+bool pa_tz_device_have_profile(pa_tz_device *device, const char *profile);
+
+/* Only for BT device
+ * Check device type and check also sco profile
+ * with pa_tz_device_have_profile */
+int pa_tz_device_sco_open(pa_tz_device *device);
+int pa_tz_device_sco_close(pa_tz_device *device);
+int pa_tz_device_sco_get_property(pa_tz_device *device, bool *is_wide_band, bool *nrec);
+int pa_tz_device_sco_get_status(pa_tz_device *device, dm_device_bt_sco_status_t *status);
+
+#endif