change stream type and modify HFP version and feature for DA
[platform/core/connectivity/bluetooth-agent.git] / hf-agent / bluetooth-hf-agent.c
old mode 100755 (executable)
new mode 100644 (file)
index e66ed10..0283016
 #include "bluetooth-hf-agent.h"
 #include "bluetooth-agent-profile.h"
 
+#include <audio_io.h>
+
+#define HFP_SCO_DATA_BUFFER_SIZE       48
+#define HFP_FHUB_SAMPLE_RATE           8000
+
 #define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3
 #define CALL_ALIAS_APP_ID "org.tizen.call-ui"
 
@@ -79,6 +84,7 @@ int clcc_async_retry_count = 0;
 #define CLCC_RETRY_TIMER 100   /* 100 msec */
 
 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
+#define PBAP_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb"
 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
 
 /*Below Inrospection data is exposed to bluez from agent*/
@@ -149,6 +155,10 @@ static const gchar hf_agent_introspection_xml[] =
 "               <method name='IsInbandRingtoneSupported'>"
 "                      <arg type='b' name='status' direction='out'/>"
 "               </method>"
+"               <method name='AudioMuteOn'>"
+"               </method>"
+"               <method name='AudioMuteOff'>"
+"               </method>"
 " </interface>"
 "</node>";
 
@@ -309,7 +319,7 @@ done:
                i++;
        }
        if (message)
-               INFO("%s Buffer = %s, Length = %d ", message, s, strlen(s));
+               INFO("%s Buffer = %s, Length = %zd ", message, s, strlen(s));
        else
                INFO("%s", s);
 }
@@ -461,7 +471,7 @@ static gboolean __clcc_async_timer_func(gpointer data)
 
 static void __hf_agent_method(GDBusConnection *connection,
                            const gchar *sender,
-                           const gchar *object_path,
+                           const gchar *path,
                            const gchar *interface_name,
                            const gchar *method_name,
                            GVariant *parameters,
@@ -702,6 +712,14 @@ static void __hf_agent_method(GDBusConnection *connection,
                                "Supported" : "NotSupported");
                g_dbus_method_invocation_return_value(context,
                                g_variant_new("(b)", is_supported));
+       } else if (g_strcmp0(method_name, "AudioMuteOn") == 0) {
+               DBG("Going to MUTE audio");
+               bt_hf_info.is_audio_input_mute = TRUE;
+               g_dbus_method_invocation_return_value(context, NULL);
+       } else if (g_strcmp0(method_name, "AudioMuteOff") == 0) {
+               DBG("Going to UNMUTE audio");
+               bt_hf_info.is_audio_input_mute = FALSE;
+               g_dbus_method_invocation_return_value(context, NULL);
        }
 
        INFO("-");
@@ -1041,6 +1059,11 @@ gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
                                pending_flag ? "TRUE" : "FALSE");
 
        bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
+       if (!cmd) {
+               ERR("failed to allocate cmd");
+               return FALSE;
+       }
+
        cmd->id = ++g_id;
        memcpy(cmd->at_cmd, at, count);
        cmd->count = count;
@@ -1189,18 +1212,24 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        "CallStarted", NULL);
                        bt_hf_info->is_dialing = FALSE;
                        bt_hf_info->call_active = TRUE;
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_STARTED;
                } else if (bt_hf_info->call_active) {
                        __bt_hf_agent_emit_signal(conn,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallEnded", NULL);
                        bt_hf_info->call_active = FALSE;
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_ENDED;
 
                        if (bt_hf_info->ciev_call_setup_status == 0) {
                                __bt_hf_agent_emit_signal(gdbus_conn,
                                                BT_HF_AGENT_OBJECT_PATH,
                                                BT_HF_SERVICE_INTERFACE,
                                                "CallIdle", NULL);
+                               if (TIZEN_MODEL_NAME_DA)
+                                       bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
                        }
                }
 
@@ -1213,6 +1242,8 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallTerminated",
                                        NULL);
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_TERMINATED;
                } else if (!bt_hf_info->is_dialing && value > 0) {
                        bt_hf_info->is_dialing = TRUE;
                }
@@ -1222,6 +1253,8 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallSetupIncoming", NULL);
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_INCOMING;
                        if (__bt_hf_agent_launch_call_app()  == FALSE)
                                DBG("call app launching failed");
                } else if (bt_hf_info->ciev_call_setup_status == 2) {
@@ -1229,17 +1262,23 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallSetupDialing", NULL);
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING;
                } else if (bt_hf_info->ciev_call_setup_status == 3) {
                        __bt_hf_agent_emit_signal(gdbus_conn,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallSetupAlerting", NULL);
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING;
                } else  if (bt_hf_info->ciev_call_status == 0 &&
                                                bt_hf_info->ciev_call_setup_status == 0) {
                        __bt_hf_agent_emit_signal(gdbus_conn,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                                "CallIdle", NULL);
+                       if (TIZEN_MODEL_NAME_DA)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
                }
        } else if (!strcmp(name, "\"callheld\"")) {
                if (value == 0) { /* No calls held*/
@@ -2017,7 +2056,7 @@ bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info
        cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
        if (cmd) {
                bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
-               DBG("NEXT[%d] Found %s, context = 0x%x, pending = %d", cmd->id,
+               DBG("NEXT[%d] Found %s, context = 0x%p, pending = %d", cmd->id,
                                cmd->at_cmd, cmd->context, cmd->pending);
                        return cmd;
        }
@@ -2298,7 +2337,7 @@ static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
        g_io_channel_flush(io_chan, NULL);
 
        if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
-               INFO("[HF AT CMD] Send only without queue <<<<<: Buffer = %s, Length = %d ",
+               INFO("[HF AT CMD] Send only without queue <<<<<: Buffer = %s, Length = %zd ",
                                        "ATDXXXXXXX", count);
                snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
        } else {
@@ -2333,14 +2372,14 @@ static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
        g_io_channel_flush(io_chan, NULL);
 
        if (count > 2 && data[2] == 'D') /* ATDXXXXX */
-               INFO("[HF AT CMD] Send only <<<<<: Buffer = %s, Length = %d ",
+               INFO("[HF AT CMD] Send only <<<<<: Buffer = %s, Length = %zd ",
                                        "ATDXXXXXXX", count);
        else
                __bt_hf_agent_print_at_buffer("[HF AT CMD] Send only <<<<<:",
                                        data);
 
        send_flag++;
-       DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<",
+       DBG("Ref %d(after) on Send only buffer size =[%zd] - Send <<<<<",
                                                send_flag, count);
        return TRUE;
 }
@@ -2416,7 +2455,7 @@ static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
                if (p.revents & POLLIN) {
                        rd_size = read(fd, resp_buf, toread);
                        resp_buf[rd_size] = '\0';
-                       DBG_SECURE("size = %d, Buffer=[%s]", rd_size, resp_buf);
+                       DBG_SECURE("size = %zd, Buffer=[%s]", rd_size, resp_buf);
                        recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
                        recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
                        recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
@@ -2510,6 +2549,197 @@ static guint __bt_hf_get_hold_mpty_features(gchar *features)
        return result;
 }
 
+/* for FHUB's HFP HF role */
+#include <sound_manager.h>
+sound_stream_info_h g_stream_info_write_h = NULL;
+
+static void __release_audio_in(bt_hf_agent_info_t *bt_hf_info)
+{
+       INFO("+");
+
+       if (bt_hf_info->audio_input != NULL) {
+               audio_in_unprepare((audio_in_h)bt_hf_info->audio_input);
+               audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
+               bt_hf_info->audio_input = NULL;
+       }
+
+       INFO("-");
+}
+
+static void __release_audio_out(bt_hf_agent_info_t *bt_hf_info)
+{
+       INFO("+");
+
+       if (bt_hf_info->audio_output != NULL) {
+               /* Skip audio drain */
+               //audio_out_drain((audio_out_h)bt_hf_info->audio_output);
+               audio_out_unprepare((audio_out_h)bt_hf_info->audio_output);
+               audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
+               bt_hf_info->audio_output = NULL;
+       }
+
+       INFO("-");
+}
+
+static int __initialize_audio_in(bt_hf_agent_info_t *bt_hf_info)
+{
+       int ret = 0;
+
+       INFO("+");
+       if (bt_hf_info->audio_input != NULL) {
+               __release_audio_in(bt_hf_info);
+       }
+
+       //init capturing
+       ret = audio_in_create(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
+                                       AUDIO_SAMPLE_TYPE_S16_LE, (audio_in_h *)&bt_hf_info->audio_input);
+       if (ret == AUDIO_IO_ERROR_NONE) {
+               if (!(audio_in_prepare((audio_in_h)bt_hf_info->audio_input))) {
+                       DBG("voice capturing is ready!\n");
+                       bt_hf_info->is_audio_input_mute = FALSE;
+               } else {
+                       ERR("audio_in_prepare failed, err(0x%x)\n", ret);
+                       audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
+                       ret = -18;
+               }
+       } else {
+               ERR("audio_in_create failed.\n");
+               ret = -17;
+       }
+
+       INFO("-");
+       return ret;
+}
+
+static int __initialize_audio_out(bt_hf_agent_info_t *bt_hf_info)
+{
+       int ret = 0;
+       INFO("+");
+
+       if (bt_hf_info->audio_output != NULL) {
+               __release_audio_out(bt_hf_info);
+       }
+
+       //init playback
+       ret = audio_out_create_new(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
+                                       AUDIO_SAMPLE_TYPE_S16_LE, (audio_out_h *)&bt_hf_info->audio_output);
+       if (ret == AUDIO_IO_ERROR_NONE) {
+               INFO("after audio_out_create!!!");
+
+               /* set sound stream info */
+               if (g_stream_info_write_h) {
+                       if (!(ret = audio_out_set_sound_stream_info(bt_hf_info->audio_output, g_stream_info_write_h))) {
+                               INFO("after audio_out_set_sound_stream_info");
+                       } else {
+                               ERR("fail to audio_out_set_sound_stream_info(), ret(0x%x)\n", ret);
+                       }
+               } else {
+                       ERR("no stream info!!!!");
+               }
+
+               /* prepare */
+               if (!(ret = audio_out_prepare((audio_out_h)bt_hf_info->audio_output))) {
+                       DBG("voice playback is ready!\n");
+               } else {
+                       ERR("audio_out_prepare failed, err(0x%x)\n", ret);
+                       audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
+                       bt_hf_info->audio_output = NULL;
+               }
+       } else {
+               ERR("audio_out_create failed. \n");
+       }
+
+       INFO("-");
+       return ret;
+}
+
+static gboolean __bt_hf_agent_sco_event_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+{
+       bt_hf_agent_info_t *bt_hf_info = user_data;
+       GDBusConnection *conn;
+       int sco_skt = g_io_channel_unix_get_fd(chan);
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       if (cond & (G_IO_HUP | G_IO_ERR)) {
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               close(bt_hf_info->cli_sco_fd);
+               bt_hf_info->cli_sco_fd = -1;
+               g_io_channel_unref(chan);
+               DBG("Emit AudioDisconnected Signal");
+
+               sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
+
+               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
+               bt_hf_info->is_first_audio_out = TRUE;
+
+               __release_audio_out(bt_hf_info);
+               __release_audio_in(bt_hf_info);
+
+               conn = __bt_hf_get_gdbus_connection();
+               if (!conn) {
+                       ERR("Unable to get connection");
+                       return FALSE;
+               }
+               __bt_hf_agent_emit_signal(conn,
+                               BT_HF_AGENT_OBJECT_PATH,
+                               BT_HF_SERVICE_INTERFACE,
+                               "AudioDisconnected", NULL);
+
+               return FALSE;
+       }
+
+       if (cond & G_IO_IN) {
+               gchar buf_rx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
+               int read;
+
+               read = recv(sco_skt, buf_rx, HFP_SCO_DATA_BUFFER_SIZE, MSG_DONTWAIT);
+               if (read > 0) {
+                       if (bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING ||
+                               bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING ||
+                               bt_hf_info->call_active) {
+
+                               if (bt_hf_info->is_first_audio_out) {
+                                       __initialize_audio_out(bt_hf_info);
+                                       bt_hf_info->is_first_audio_out = FALSE;
+                               }
+                               if (bt_hf_info->audio_output) {
+                                       audio_out_write(bt_hf_info->audio_output, buf_rx, read);
+                               } else {
+                                       ERR("can't write audio");
+                               }
+                       }
+               }
+       }
+       if (cond & G_IO_OUT) {
+               gchar buf_tx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
+               int size;
+
+               if (bt_hf_info->is_first_audio_in) {
+                       __initialize_audio_in(bt_hf_info);
+                       bt_hf_info->is_first_audio_in = FALSE;
+                       return  TRUE;
+               }
+
+               size = audio_in_read(bt_hf_info->audio_input, (void *)buf_tx, HFP_SCO_DATA_BUFFER_SIZE);
+               if (size > 0) {
+                       if (bt_hf_info->call_active) {
+
+                               if (bt_hf_info->is_audio_input_mute) {
+                                       memset(buf_tx, 0x0, size);
+                               }
+
+                               if (send(sco_skt, buf_tx, size, MSG_DONTWAIT) < 0) {
+                                       ERR("Write failed, error = %d[%s]", errno, strerror(errno));
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+
 static gboolean __bt_hf_agent_sco_disconnect_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
 {
        bt_hf_agent_info_t *bt_hf_info = user_data;
@@ -2576,8 +2806,17 @@ static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond,
        g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
        g_io_channel_set_buffered(sco_io, FALSE);
 
-       g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                       __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
+       if (TIZEN_MODEL_NAME_DA) {
+               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
+               bt_hf_info->is_first_audio_out = TRUE;
+               bt_hf_info->is_first_audio_in = TRUE;
+               //__initialize_audio_in(bt_hf_info);
+
+               g_io_add_watch(sco_io, G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                               __bt_hf_agent_sco_event_cb, bt_hf_info);
+       } else
+               g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                               __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
 
        if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
                ERR("HFP is not yet connected");
@@ -2784,14 +3023,22 @@ static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info
        gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
        gboolean ret;
        char *buf_ptr;
-       guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
-                       BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
-                       BT_HF_FEATURE_CLI_PRESENTATION |
-                       BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
-                       BT_HF_FEATURE_ENHANCED_CALL_STATUS;
-
-       if (TIZEN_PROFILE_WEARABLE)
-               feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       guint feature;
+
+       if (TIZEN_MODEL_NAME_DA)
+               feature = BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ESCO_S4;
+       else {
+               feature = BT_HF_FEATURE_EC_ANDOR_NR |
+                               BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
+                               BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ENHANCED_CALL_STATUS;
+
+               if (TIZEN_PROFILE_WEARABLE)
+                       feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       }
 
        snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
        ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
@@ -3057,6 +3304,100 @@ done:
        return FALSE;
 }
 
+static void __unprepare_stream_info(void)
+{
+       int ret;
+
+       if (!g_stream_info_write_h) {
+               ERR("no stream to destroy");
+               return;
+       }
+
+       ret = sound_manager_destroy_stream_information(g_stream_info_write_h);
+       if (ret != SOUND_MANAGER_ERROR_NONE) {
+               ERR("Failed to destroy stream information");
+               return;
+       }
+
+       g_stream_info_write_h = NULL;
+}
+
+void stream_focus_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
+                       sound_stream_focus_change_reason_e reason, int sound_behavior, const char *extra_info, void *user_data)
+{
+       return;
+}
+
+static gboolean __prepare_stream_info(void)
+{
+       int ret;
+       sound_device_list_h g_device_list = NULL;
+       sound_device_h device = NULL;
+       sound_device_type_e selected_type = SOUND_DEVICE_BUILTIN_SPEAKER;
+       sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER;
+
+       if (TIZEN_MODEL_NAME_FHUB) {
+               char *processor = NULL;
+
+               system_info_get_platform_string("tizen.org/system/platform.processor", &processor);
+               if (processor) {
+                       if (!strcasecmp(processor, "SDP1601")) {
+                               DBG("set specific sound type");
+                               selected_type = SOUND_DEVICE_BUILTIN_RECEIVER;
+                               type = SOUND_DEVICE_BUILTIN_RECEIVER;
+                       }
+                       free(processor);
+               }
+       }
+
+       if (g_stream_info_write_h) {
+               ERR("there is already created one %p", g_stream_info_write_h);
+               __unprepare_stream_info();
+       }
+
+       ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOIP, stream_focus_cb, NULL, &g_stream_info_write_h);
+       if (ret != SOUND_MANAGER_ERROR_NONE) {
+               ERR("Failed to create stream information");
+               return FALSE;
+       }
+       INFO("created stream info %p", g_stream_info_write_h);
+
+       ret = sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_OUT_MASK, &g_device_list);
+       if (ret != SOUND_MANAGER_ERROR_NONE) {
+               ERR("fail to get current device list, ret(0x%x)\n", ret);
+               return FALSE;
+       }
+
+       // find voip device
+       while (!sound_manager_get_next_device(g_device_list, &device)) {
+               if ((ret = sound_manager_get_device_type(device, &type))) {
+                       ERR("fail to get type of device, ret(0x%x)\n", ret);
+                       break;
+               }
+
+               if (selected_type == type) {
+                       DBG("try to set route for device\n");
+                       ret = sound_manager_add_device_for_stream_routing(g_stream_info_write_h, device);
+                       if (ret == SOUND_MANAGER_ERROR_NONE) {
+                               ret = sound_manager_apply_stream_routing(g_stream_info_write_h);
+                               if (ret != SOUND_MANAGER_ERROR_NONE)
+                                       ERR("failed to sound_manager_apply_stream_routing(), ret(0x%x)\n", ret);
+                       } else {
+                               ERR("failed to sound_manager_add_device_for_stream_routing(), ret(0x%x)\n", ret);
+                       }
+                       break;
+               }
+       }
+
+       ret = sound_manager_free_device_list(g_device_list);
+       if (ret != SOUND_MANAGER_ERROR_NONE)
+               ERR("fail to free device list, ret[0x%x]\n", ret);
+       else
+               g_device_list = NULL;
+
+       return TRUE;
+}
+
 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
 {
        GIOFlags flags;
@@ -3088,6 +3429,9 @@ static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
        __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
                                                address.remote_bdaddr.b);
 
+       if (TIZEN_MODEL_NAME_DA)
+               __prepare_stream_info();
+
        g_idle_add(__bt_agent_request_service_level_conn, NULL);
 
        return TRUE;
@@ -3103,6 +3447,9 @@ static gboolean __bt_hf_agent_release(void)
        int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
        GDBusConnection *conn;
 
+       if (TIZEN_MODEL_NAME_DA)
+               __unprepare_stream_info();
+
        if (clcc_timer) {
                g_source_remove(clcc_timer);
                clcc_timer = 0;
@@ -3200,11 +3547,18 @@ static int __bt_hf_register_profile(const char *uuid, uint16_t version,
        g_variant_builder_add(builder, "{sv}",
                        "features", g_variant_new("q", features));
 
-       ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
-                               g_variant_new("(osa{sv})", path,
-                                       HFP_HF_UUID, builder),
-                               G_DBUS_CALL_FLAGS_NONE, -1,
-                               NULL, &error);
+       if (TIZEN_MODEL_NAME_DA)
+               ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
+                                       g_variant_new("(osa{sv})", object,
+                                               uuid, builder),
+                                       G_DBUS_CALL_FLAGS_NONE, -1,
+                                       NULL, &error);
+       else
+               ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
+                                       g_variant_new("(osa{sv})", path,
+                                               HFP_HF_UUID, builder),
+                                       G_DBUS_CALL_FLAGS_NONE, -1,
+                                       NULL, &error);
 
        g_variant_builder_unref(builder);
 
@@ -3241,7 +3595,15 @@ static void __bt_hf_agent_register(void)
        ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
                                                                features);
        if (ret)
-               ERR("Error in register");
+               ERR("Error in hf register");
+
+       if (TIZEN_MODEL_NAME_DA) {
+               ret = __bt_hf_register_profile(PBAP_PCE_UUID, 0x0101,
+                                       "Phone Book Access Client",
+                                       BT_PBAP_CLIENT_OBJECT_PATH, 0);
+               if (ret)
+                       ERR("Error in pce register");
+       }
 
        g_free(path);
        g_free(name);
@@ -3478,6 +3840,7 @@ static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
 {
        int ret;
+       int prev_cmd_len = 0;
        char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
 
        if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
@@ -3501,7 +3864,12 @@ static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
                }
 
                /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
-               snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
+               prev_cmd_len = snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
+
+               if (prev_cmd_len < 0) {
+                       ERR("Encoding error occured in snprintf");
+                       return BT_HF_AGENT_ERROR_INTERNAL;
+               }
 
                if (!ret)
                        return BT_HF_AGENT_ERROR_INTERNAL;
@@ -3766,17 +4134,28 @@ static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
 
 static uint32_t __bt_hf_agent_get_hf_features(void)
 {
-       uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
-                       BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
-                       BT_HF_FEATURE_CLI_PRESENTATION |
-                       BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
-                       BT_HF_FEATURE_ENHANCED_CALL_STATUS |
-                       BT_HF_FEATURE_CODEC_NEGOTIATION;
+       uint32_t hf_features;
 
-       if (TIZEN_PROFILE_WEARABLE)
-               hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       if (TIZEN_MODEL_NAME_DA)
+               hf_features = BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ESCO_S4;
+       else {
+               hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
+                               BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
+                               BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ENHANCED_CALL_STATUS |
+                               BT_HF_FEATURE_CODEC_NEGOTIATION;
+
+               if (TIZEN_PROFILE_WEARABLE)
+                       hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       }
 
-       hf_ver = HFP_VERSION_1_6;
+       if (TIZEN_MODEL_NAME_DA)
+               hf_ver = HFP_VERSION_1_7;
+       else
+               hf_ver = HFP_VERSION_1_6;
 
        return hf_features;
 }
@@ -3793,7 +4172,13 @@ int main(void)
        g_type_init();
 #endif
        hf_features = __bt_hf_agent_get_hf_features();
-       bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
+       if (TIZEN_MODEL_NAME_DA)
+               bt_hf_info.feature = (uint16_t) hf_features & 0xFFFF;
+       else
+               bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
+
+       bt_hf_info.audio_input = NULL;
+       bt_hf_info.audio_output = NULL;
 
        memset(&sa, 0, sizeof(sa));
        sa.sa_flags = SA_NOCLDSTOP;