From: Wootak Jung Date: Thu, 6 Sep 2018 06:16:31 +0000 (+0900) Subject: Update HF agent codes for wearable X-Git-Tag: accepted/tizen/5.0/unified/20181102.015434^0 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fconnectivity%2Fbluetooth-agent.git;a=commitdiff_plain;h=47a5846ec6117917b693b1682adaf11d689a96cb Update HF agent codes for wearable Change-Id: Ibed6e269eab908c436d0eb8ab5a0b208d762fac0 --- diff --git a/hf-agent/bluetooth-hf-agent.c b/hf-agent/bluetooth-hf-agent.c index 8c2857c..e66ed10 100755 --- a/hf-agent/bluetooth-hf-agent.c +++ b/hf-agent/bluetooth-hf-agent.c @@ -43,7 +43,7 @@ #include "bluetooth-agent-profile.h" #define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3 -#define CALL_APP_ID "org.tizen.call-ui" +#define CALL_ALIAS_APP_ID "org.tizen.call-ui" #define MAX_WAITING_DELAY 8 #define READ_TX_POWER_MIN -30 @@ -64,13 +64,20 @@ static GMainLoop *gmain_loop = NULL; static char *g_obj_path; -static GDBusConnection *gdbus_conn; -static GDBusProxy *service_gproxy; +static GDBusConnection *gdbus_conn = NULL; +static GDBusProxy *profile_gproxy = NULL; static guint interface_added_sig_id; static guint interface_removed_sig_id; int g_id = 0; uint16_t hf_ver; +guint clcc_timer = 0; +int clcc_retry_count = 0; +guint clcc_async_timer = 0; +int clcc_async_retry_count = 0; +#define CLCC_RETRY_COUNT 10 +#define CLCC_RETRY_TIMER 100 /* 100 msec */ + #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb" #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0" @@ -103,6 +110,8 @@ static const gchar hf_agent_introspection_xml[] = " " " " " " +" " +" " " " " " " " @@ -129,16 +138,21 @@ static const gchar hf_agent_introspection_xml[] = " " " " " " +" " +" " " " " " " " " " " " " " +" " +" " +" " " " ""; -static bt_hf_agent_info_t bt_hf_info; +static bt_hf_agent_info_t bt_hf_info = {0,}; static gboolean is_hf_connected = FALSE; static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD; static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED; @@ -158,6 +172,10 @@ typedef struct { char *number; } hf_call_list_info_t; +#define BT_HF_SIG_NUM 3 +static struct sigaction bt_hf_sigoldact[BT_HF_SIG_NUM]; +static int bt_hf_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM }; + static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error); static gboolean __bt_hf_agent_emit_property_changed( @@ -191,6 +209,7 @@ static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info); static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info); static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path); static gboolean __bt_hf_agent_connection_release(void); +static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info); struct indicator { gchar descr[BT_HF_INDICATOR_DESCR_SIZE]; @@ -211,6 +230,8 @@ static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd); static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status); +static gboolean bt_hf_agent_sco_connect(void); + static gboolean bt_hf_agent_sco_disconnect(void); static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf); @@ -221,7 +242,13 @@ static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd); static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf); -void __bt_hf_agent_print_at_buffer(char *message, const char *buf) +static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level, + const gchar *msg, gpointer user_data) +{ + ERR_C("%s", msg); +} + +static void __bt_hf_agent_print_at_buffer(char *message, const char *buf) { int i = 0; @@ -327,6 +354,9 @@ static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error) case BT_HF_AGENT_ERROR_NO_MEMORY: return g_error_new(BT_HF_AGENT_ERROR, error, BT_ERROR_NO_MEMORY); + case BT_HF_AGENT_ERROR_NO_DATA: + return g_error_new(BT_HF_AGENT_ERROR, error, + BT_ERROR_NO_DATA); case BT_HF_AGENT_ERROR_I_O_ERROR: return g_error_new(BT_HF_AGENT_ERROR, error, BT_ERROR_I_O_ERROR); @@ -371,6 +401,64 @@ static void __bt_hf_unlock_display() ERR("deviced error!"); } +static gboolean __clcc_timer_func(gpointer data) +{ + GVariant *call_var; + GError *err; + + DBG("+"); + + if (bt_hf_info.state != BT_HF_STATE_CONNECTED) { + DBG("NOT CONNECTED"); + err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_NOT_CONNECTED); + g_dbus_method_invocation_return_gerror((GDBusMethodInvocation *) data, err); + g_error_free(err); + clcc_timer = 0; + return FALSE; + } + + if (send_flag && clcc_retry_count > 0) { + clcc_retry_count--; + DBG("Still pending. try later (remained [%d] times)", clcc_retry_count); + return TRUE; + } + + clcc_timer = 0; + + call_var = bt_hf_agent_request_call_list(); + if (!call_var) { + INFO("NOT AVAILABLE"); + err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_NOT_AVAILABLE); + g_dbus_method_invocation_return_gerror((GDBusMethodInvocation *) data, err); + g_error_free(err); + return FALSE; + } + + INFO("return call list info"); + g_dbus_method_invocation_return_value((GDBusMethodInvocation *) data, call_var); + return FALSE; +} + +static gboolean __clcc_async_timer_func(gpointer data) +{ + DBG("+"); + + if (send_flag && clcc_async_retry_count > 0) { + clcc_async_retry_count--; + ERR("Still pending. try later (remained [%d] times)", clcc_async_retry_count); + return TRUE; + } + + clcc_async_timer = 0; + + __bt_hf_agent_handle_call_list(&bt_hf_info); + g_dbus_method_invocation_return_value((GDBusMethodInvocation*)data, NULL); + + INFO("update_call_list succeeded"); + + return FALSE; +} + static void __hf_agent_method(GDBusConnection *connection, const gchar *sender, const gchar *object_path, @@ -466,6 +554,14 @@ static void __hf_agent_method(GDBusConnection *connection, if (ret) goto fail; + } else if (g_strcmp0(method_name, "ScoConnect") == 0) { + DBG("Going to call ScoConnect"); + if (!bt_hf_agent_sco_connect()) { + ret = BT_HF_AGENT_ERROR_INTERNAL; + goto fail; + } + + g_dbus_method_invocation_return_value(context, NULL); } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) { DBG("Going to call ScoDisconnect"); if (!bt_hf_agent_sco_disconnect()) { @@ -501,9 +597,10 @@ static void __hf_agent_method(GDBusConnection *connection, g_variant_get(parameters, "(&s)", &cmd); DBG("Going to call SendAtCmd\n"); - ret = bt_hf_agent_send_at_cmd(context, cmd); + ret = bt_hf_agent_send_at_cmd(NULL, cmd); if (ret) goto fail; + g_dbus_method_invocation_return_value(context, NULL); } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) { DBG("Going to call ReleaseAndAccept"); @@ -539,13 +636,45 @@ static void __hf_agent_method(GDBusConnection *connection, } else if (g_strcmp0(method_name, "RequestCallList") == 0) { GVariant *call_var; - DBG("Going to call RequestCallList"); - call_var = bt_hf_agent_request_call_list(); - if (!call_var) { + INFO("Going to call RequestCallList (send_flag[%d])", send_flag); + + if (send_flag) { + INFO("Send_flag is true. Try to send CLCC later"); + clcc_retry_count = CLCC_RETRY_COUNT; + clcc_timer = g_timeout_add(CLCC_RETRY_TIMER, __clcc_timer_func, context); + } else { + call_var = bt_hf_agent_request_call_list(); + if (!call_var) { + ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE; + goto fail; + } + g_dbus_method_invocation_return_value(context, call_var); + } + } else if (g_strcmp0(method_name, "RequestCallListAsync") == 0) { + INFO("Going to call RequestCallListAsync (send_flag[%d])", send_flag); + + if (clcc_async_timer > 0) { ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE; goto fail; } - g_dbus_method_invocation_return_value(context, call_var); + if (bt_hf_info.state != BT_HF_STATE_CONNECTED) { + ret = BT_HF_AGENT_ERROR_NOT_CONNECTED; + goto fail; + } + if (bt_hf_info.ciev_call_status == 0 && + bt_hf_info.ciev_call_setup_status == 0) { + ret = BT_HF_AGENT_ERROR_NO_DATA; + goto fail; + } + + if (send_flag) { + INFO("Send_flag is true. Try to send CLCC later"); + clcc_async_retry_count = CLCC_RETRY_COUNT; + clcc_async_timer = g_timeout_add(CLCC_RETRY_TIMER, __clcc_async_timer_func, context); + } else { + __bt_hf_agent_handle_call_list(&bt_hf_info); + g_dbus_method_invocation_return_value(context, NULL); + } } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) { DBG("Going to call GetAudioConnected"); g_dbus_method_invocation_return_value(context, @@ -556,7 +685,25 @@ static void __hf_agent_method(GDBusConnection *connection, g_dbus_method_invocation_return_value(context, g_variant_new("(b)", is_hf_connected)); + } else if (g_strcmp0(method_name, "IsInbandRingtoneSupported") == 0) { + gboolean is_supported = FALSE; + + if (is_hf_connected == FALSE) { + ret = BT_HF_AGENT_ERROR_NOT_CONNECTED; + goto fail; + } + + if (bt_hf_info.inband_ringtone_support) + is_supported = TRUE; + else + is_supported = FALSE; + + INFO("IsInbandRingtoneSupported : %s", is_supported ? + "Supported" : "NotSupported"); + g_dbus_method_invocation_return_value(context, + g_variant_new("(b)", is_supported)); } + INFO("-"); return; @@ -684,8 +831,7 @@ static gboolean __bt_hf_register_profile_methods(void) return TRUE; } -static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service, - const gchar *path, const gchar *interface) +static GDBusProxy *__bt_hf_gdbus_init_profile_proxy(void) { DBG("+"); @@ -701,8 +847,8 @@ static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service, proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL, - service, path, - interface, NULL, &err); + BLUEZ_SERVICE_NAME, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err); if (!proxy) { if (err) { @@ -712,16 +858,48 @@ static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service, return NULL; } + profile_gproxy = proxy; + DBG("-"); return proxy; } +static GDBusProxy *__bt_hf_gdbus_get_profile_proxy(void) +{ + return (profile_gproxy) ? profile_gproxy : + __bt_hf_gdbus_init_profile_proxy(); +} + static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service, const gchar *path, const gchar *interface) { - return (service_gproxy) ? service_gproxy : - __bt_hf_gdbus_init_service_proxy(service, - path, interface); + DBG("+"); + + GDBusProxy *proxy; + GError *err = NULL; + GDBusConnection *conn; + + conn = __bt_hf_get_gdbus_connection(); + if (!conn) { + ERR("Unable to get connection"); + return NULL; + } + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, NULL, + service, path, + interface, NULL, &err); + + if (!proxy) { + if (err) { + ERR("Unable to create proxy: %s", err->message); + g_clear_error(&err); + } + return NULL; + } + + DBG("-"); + return proxy; } static char __bt_hf_agent_get_tx_power(char *address) @@ -750,11 +928,14 @@ static char __bt_hf_agent_get_tx_power(char *address) error->code, error->message); g_clear_error(&error); } + g_object_unref(proxy); return result; } g_variant_get(ret, "(y)", &result); DBG("TX power level = %d", result); g_variant_unref(ret); + g_object_unref(proxy); + return result; } @@ -786,10 +967,12 @@ static int __bt_hf_agent_gdbus_method_send(const char *service, g_clear_error(&error); } + g_object_unref(proxy); return BT_HF_AGENT_ERROR_INTERNAL; } g_variant_unref(ret); + g_object_unref(proxy); return BT_HF_AGENT_ERROR_NONE; } @@ -850,7 +1033,7 @@ static gboolean __bt_hf_monitor_timer_cb(gpointer data) gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at, int count, gboolean pending_flag) { - int i, len; + int i, len, timer_id; if (bt_hf_info.slc == FALSE) return FALSE; @@ -868,17 +1051,22 @@ gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at, len = g_slist_length(bt_hf_info.cmd_send_queue); for (i = 0; i < len; ++i) { cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i); - DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id); + if (cmd) + DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id); } /* We need to have base timeout + tolerance value to process other request */ if (strstr(at, "ATD") || strstr(at, "BLDN")) { /* Android 15 seconds timeout in case of ATD timeout in flight mode */ - cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len, + timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len, __bt_hf_monitor_timer_cb, cmd); + if (cmd) + cmd->timer_id = timer_id; } else { - cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len, + timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len, __bt_hf_monitor_timer_cb, cmd); + if (cmd) + cmd->timer_id = timer_id; } return TRUE; } @@ -923,7 +1111,7 @@ static gboolean __bt_hf_agent_emit_property_changed( ret = g_dbus_connection_emit_signal(connection, NULL, path, interface, "PropertyChanged", - g_variant_new("s(v)", name, property), + g_variant_new("(sv)", name, property), &error); if (!ret) { if (error != NULL) { @@ -941,6 +1129,36 @@ static gboolean __bt_hf_agent_emit_property_changed( Below methods exposed to Bluez */ +static gboolean __bt_hf_agent_launch_call_app(void) +{ + bundle *b; + bool is_running; + + DBG("+"); + app_manager_is_running(CALL_ALIAS_APP_ID, &is_running); + if (is_running) { + DBG("Call app is already started"); + return TRUE; + } + + b = bundle_create(); + if (NULL == b) { + ERR("bundle_create() Failed"); + return FALSE; + } + + bundle_add(b, "launch-type", "BT_LAUNCH"); + + bundle_add(b, "carrier-type", "BT"); + DBG("For 3G, carrier-type: BT has been added"); + aul_launch_app_async(CALL_ALIAS_APP_ID, b); + bundle_free(b); + + INFO("-aul_launch_app_async -"); + + return TRUE; +} + static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info, guint index, gint value) { @@ -977,27 +1195,52 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info, BT_HF_SERVICE_INTERFACE, "CallEnded", NULL); bt_hf_info->call_active = FALSE; + + 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); + } } } else if (!strcmp(name, "\"callsetup\"")) { bt_hf_info->ciev_call_setup_status = value; if (value == 0 && bt_hf_info->is_dialing) { + bt_hf_info->is_dialing = FALSE; __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "CallTerminated", NULL); - bt_hf_info->is_dialing = FALSE; - } else if (!bt_hf_info->is_dialing && value > 0) + } else if (!bt_hf_info->is_dialing && value > 0) { bt_hf_info->is_dialing = TRUE; + } - if (bt_hf_info->ciev_call_status == 0 && - bt_hf_info->ciev_call_setup_status == 0) + if (bt_hf_info->ciev_call_setup_status == 1) { __bt_hf_agent_emit_signal(gdbus_conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, - "CallEnded", NULL); - + "CallSetupIncoming", NULL); + if (__bt_hf_agent_launch_call_app() == FALSE) + DBG("call app launching failed"); + } else if (bt_hf_info->ciev_call_setup_status == 2) { + __bt_hf_agent_emit_signal(gdbus_conn, + BT_HF_AGENT_OBJECT_PATH, + BT_HF_SERVICE_INTERFACE, + "CallSetupDialing", NULL); + } 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); + } 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); + } } else if (!strcmp(name, "\"callheld\"")) { if (value == 0) { /* No calls held*/ __bt_hf_agent_emit_signal(conn, @@ -1011,72 +1254,47 @@ 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, "CallsSwapped", NULL); - bt_hf_info->is_dialing = FALSE; } else { /*Call on hold, no active call*/ __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "CallOnHold", NULL); - bt_hf_info->is_dialing = FALSE; } - } else if (!strcmp(name, "\"service\"")) + } else if (!strcmp(name, "\"service\"")) { + if (value < 0 || value > 1) + ERR("Out of range"); + else __bt_hf_agent_emit_property_changed(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "RegistrationStatus", - g_variant_new("(q)", value)); - else if (!strcmp(name, "\"signal\"")) + g_variant_new("q", value)); + } else if (!strcmp(name, "\"signal\"")) { + if (value < 0 || value > 5) + ERR("Out of range"); + else __bt_hf_agent_emit_property_changed(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "SignalStrength", - g_variant_new("(q)", value)); - else if (!strcmp(name, "\"roam\"")) + g_variant_new("q", value)); + } else if (!strcmp(name, "\"roam\"")) { + if (value < 0 || value > 1) + ERR("Out of range"); + else __bt_hf_agent_emit_property_changed(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "RoamingStatus", - g_variant_new("(q)", value)); - else if (!strcmp(name, "\"battchg\"")) + g_variant_new("q", value)); + } else if (!strcmp(name, "\"battchg\"")) { + if (value < 0 || value > 5) + ERR("Out of range"); + else __bt_hf_agent_emit_property_changed(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "BatteryCharge", - g_variant_new("(q)", value)); -} - - -static gboolean __bt_hf_agent_launch_call_app(const char *launch_type, - const char *number) -{ - bundle *b; - bool is_running; - - DBG("+"); - app_manager_is_running(CALL_APP_ID, &is_running); - if (is_running) - return FALSE; - - DBG_SECURE("Launch type = %s, number(%s)", launch_type, number); - - b = bundle_create(); - if (NULL == b) { - ERR("bundle_create() Failed"); - return FALSE; + g_variant_new("q", value)); } - - bundle_add(b, "launch-type", launch_type); - - if (strlen(number) != 0) - bundle_add(b, "number", number); - - bundle_add(b, "carrier-type", "BT"); - DBG("For 3G, carrier-type: BT has been added"); - - aul_launch_app(CALL_APP_ID, b); - bundle_free(b); - - DBG("-"); - - return TRUE; } static void __bt_hf_agent_handle_voice_activation(gint value) @@ -1114,13 +1332,55 @@ static void __bt_hf_agent_handle_speaker_gain(gint value) return; } +static int __bt_hf_agent_handle_clip(bt_hf_agent_info_t *bt_hf_info, + const gchar *buf) +{ + GDBusConnection *conn; + gchar *clip; + gchar number[BT_HF_CALLER_NUM_SIZE]; + gchar *sep; + char fmt_str[BT_HF_FMT_STR_SIZE]; + int len = strlen(buf); + + DBG("__bt_hf_agent_handle_clip +"); + if (len > BT_HF_CALLER_NUM_SIZE + 10) { + ERR("buf len %d is too long", len); + return 1; + } + + if ((clip = strstr(buf, "\r\n+CLIP"))) { + snprintf(fmt_str, sizeof(fmt_str), "\r\n+CLIP: \"%%%ds", (int)(sizeof(number) - 1)); + if (sscanf(clip, fmt_str, number) == 1) { + sep = strchr(number, '"'); + sep[0] = '\0'; + + clip = number; + + conn = __bt_hf_get_gdbus_connection(); + if (!conn) { + ERR("Unable to get connection"); + return 1; + } + + __bt_hf_agent_emit_signal(conn, + BT_HF_AGENT_OBJECT_PATH, + BT_HF_SERVICE_INTERFACE, "Ring", + g_variant_new("(s)", clip)); + } else { + ERR_SECURE("CLIP '%s' is Call Incoming", buf); + return 1; + } + } + DBG("__bt_hf_agent_handle_clip -"); + return 0; +} + static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info, const gchar *buf) { GDBusConnection *conn; gchar *ccwa; - gchar *number; - gchar *ptr; + gchar number[BT_HF_CALLER_NUM_SIZE]; gchar *sep; char fmt_str[BT_HF_FMT_STR_SIZE]; int len = strlen(buf); @@ -1133,9 +1393,8 @@ static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info, if ((ccwa = strstr(buf, "\r\n+CCWA"))) { snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds", - BT_HF_CALLER_NUM_SIZE - 1); - if ((ptr = strstr(ccwa, "\"")) != NULL) { - number = ptr + 1; + (int)(sizeof(number) - 1)); + if (sscanf(ccwa, fmt_str, number) == 1) { sep = strchr(number, '"'); sep[0] = '\0'; @@ -1160,6 +1419,19 @@ static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info, return 0; } +static void __bt_hf_agent_handle_bsir(bt_hf_agent_info_t *bt_hf_info, + gint value) +{ + INFO("new value : %d", value); + + if (value == 1) + bt_hf_info->inband_ringtone_support = TRUE; + else + bt_hf_info->inband_ringtone_support = FALSE; + + return; +} + static GSList *__bt_hf_prepare_call_list(const char *buf) { GSList *call_list = NULL; @@ -1167,7 +1439,6 @@ static GSList *__bt_hf_prepare_call_list(const char *buf) char *ptr = NULL; char *temp = NULL; char *sp; - char *stop; char delim_sep[] = "\r\n"; char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,}; @@ -1185,18 +1456,13 @@ static GSList *__bt_hf_prepare_call_list(const char *buf) call_info = g_new0(hf_call_list_info_t, 1); - /* str format : "+CLCC: %1d,%1d, %1d, %1d, %1d" */ - if ((ptr = strchr(str, ':')) != NULL) { - call_info->idx = strtol(ptr + 1, &stop, 10); - call_info->dir = strtol(stop + 1, &stop, 10); - call_info->status = strtol(stop + 1, &stop, 10); - call_info->mode = strtol(stop + 1, &stop, 10); - call_info->multi_party = strtol(stop + 1, &stop, 10); - - DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n", - call_info->idx, call_info->dir, call_info->status, - call_info->mode, call_info->multi_party); - } + sscanf(str, "+CLCC: %1d,%1d, %1d, %1d, %1d", + &call_info->idx, &call_info->dir, + &call_info->status, &call_info->mode, + &call_info->multi_party); + DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n", + call_info->idx, call_info->dir, call_info->status, + call_info->mode, call_info->multi_party); ptr = strstr(str, "\""); if (ptr) { @@ -1263,12 +1529,9 @@ static void __bt_hf_free_call_list(GSList *call_list) DBG("-"); } -static void __bt_hf_launch_call_using_call_list(GSList *call_list, - bt_hf_agent_info_t *bt_hf_info) +static void __bt_hf_launch_call_using_call_list(GSList *call_list) { guint len; - const char *launch_type_str; - hf_call_list_info_t *call_info; DBG("+"); if (call_list == NULL) @@ -1276,26 +1539,9 @@ static void __bt_hf_launch_call_using_call_list(GSList *call_list, len = g_slist_length(call_list); - while (len--) { - call_info = g_slist_nth_data(call_list, len); - - /* Launch based on below conditions - * DC - Active call which is initiated from H - * MR - Alerting call which is initiated from H - * MT - Incoming call */ - if (call_info->status == BT_HF_CALL_STAT_ACTIVE) { - launch_type_str = "DC"; - } else { - if (call_info->dir == BT_HF_CALL_DIR_INCOMING) - launch_type_str = "MT"; - else - launch_type_str = "MR"; - } + if (len > 0 && __bt_hf_agent_launch_call_app() == FALSE) + DBG("call app launching failed"); - if (__bt_hf_agent_launch_call_app(launch_type_str, - call_info->number) == FALSE) - DBG("call app launching failed"); - } DBG("-"); } @@ -1317,14 +1563,16 @@ static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list) while (call_count--) { call_info = g_slist_nth_data(call_list, call_count); - INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d", - call_info->idx, call_info->dir, call_info->status, - call_info->mode, call_info->multi_party); - caller = call_info->number; - - g_variant_builder_add(builder, "(siiii)", - caller, call_info->dir, call_info->status, - call_info->multi_party, call_info->idx); + if (call_info) { + INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d", + call_info->idx, call_info->dir, call_info->status, + call_info->mode, call_info->multi_party); + caller = call_info->number; + + g_variant_builder_add(builder, "(siiii)", + caller, call_info->dir, call_info->status, + call_info->multi_party, call_info->idx); + } } var_data = g_variant_new("(ia(siiii))", g_slist_length(call_list), builder); @@ -1349,19 +1597,17 @@ static void __bt_hf_agent_send_call_status_info(GSList *call_list) GDBusConnection *conn; GVariant *var_data; - var_data = __bt_hf_agent_get_call_status_info(call_list); conn = __bt_hf_get_gdbus_connection(); if (!conn) { ERR("Unable to get connection"); - return; - } - - if (conn) + } else { + var_data = __bt_hf_agent_get_call_status_info(call_list); __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, "CallStatusUpdate", var_data); + } } static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info) @@ -1381,31 +1627,6 @@ static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info) __bt_hf_unlock_display(); } -static void __bt_hf_agent_request_call_list_info(bt_hf_agent_info_t *bt_hf_info, - guint index) -{ - char *name; - struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1); - if (ind == NULL) { - ERR("Indicator is NULL"); - return; - } - name = ind->descr; - DBG("name : %s", name); - - if ((strcmp(name, "\"callsetup\"") != 0) && - (strcmp(name, "\"call\"") != 0) && - (strcmp(name, "\"callheld\"") != 0)) - return; - - __bt_hf_lock_display(0); - - __bt_hf_agent_handle_call_list(bt_hf_info); - - __bt_hf_unlock_display(); - -} - static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only) { gchar buf[BT_HF_DATA_BUF_SIZE]; @@ -1472,33 +1693,36 @@ static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info, { gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0}; gboolean ret; + int retval; if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) { INFO("Codec id doesn't match, so send available codec again"); ret = __bt_hf_send_available_codec(bt_hf_info, 1); - if (!ret) + if (FALSE == ret) ERR("Failed to send avalable codec"); return; } /* HF should be ready accpet SCO connection before sending theresponse for "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */ - ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id); + retval = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id); + if (retval) { + ERR("_hf_agent_codec_setup : Failed [%d]", retval); + } snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id); bt_hf_info->context = NULL; - ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf)); - if (!ret) - ERR("Failed to select the Codec"); + if (FALSE == ret) { + ERR("__bt_hf_send_only : FALSE"); + } } static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf) { - gchar *indicator; + gchar indicator[BT_HF_INDICATOR_DESCR_SIZE + 4]; gchar *sep; - gchar *ptr; gint value; guint index; char fmt_str[BT_HF_FMT_STR_SIZE]; @@ -1507,21 +1731,13 @@ static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n", BT_HF_INDICATOR_DESCR_SIZE + 4 - 1); - if ((ptr = strchr(buf, ':')) != NULL) { - indicator = ptr + 1; + if (sscanf(buf, fmt_str, indicator) == 1) { sep = strchr(indicator, ','); sep[0] = '\0'; sep += 1; index = atoi(indicator); value = atoi(sep); __bt_hf_agent_handle_ind_change(bt_hf_info, index, value); - - if (bt_hf_info->ciev_call_status == 0 && - bt_hf_info->ciev_call_setup_status == 0) - INFO("No active call"); - else - /* Request CLCC based on indicator change for call/callsetup/callHeld */ - __bt_hf_agent_request_call_list_info(bt_hf_info, index); } DBG("--------- __bt_hf_agent_handler_ciev ------------"); return 0; @@ -1558,6 +1774,7 @@ static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf) { DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++"); + __bt_hf_agent_handle_clip(bt_hf_info, buf); DBG("---------__bt_hf_agent_handler_clip --------"); return 0; @@ -1567,12 +1784,8 @@ static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char { DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++"); gint value; - gchar *ptr; - gchar *stop; - if ((ptr = strstr(buf, "BVRA:")) != NULL) { - value = strtol(ptr + 5, &stop, 10); + if (sscanf(buf, "\r\n+BVRA:%1d\r\n", &value) == 1) __bt_hf_agent_handle_voice_activation(value); - } DBG("---------__bt_hf_agent_handler_bvra --------"); return 0; @@ -1581,13 +1794,9 @@ static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf) { guint codec_id; - gchar *ptr; - gchar *stop; DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-"); - if ((ptr = strstr(buf, "BCS:")) != NULL) { - codec_id = strtol(ptr + 4, &stop, 10); + if (sscanf(buf, "\r\n+BCS:%3d\r\n", &codec_id)) __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id); - } DBG("---------__bt_hf_agent_handler_bcs --------"); return 0; @@ -1596,13 +1805,14 @@ static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf) { gint value; - gchar *ptr; - gchar *stop; + int ret = 0; DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++"); - if ((ptr = strstr(buf, "VGS:")) != NULL) { - value = strtol(ptr + 4, &stop, 10); + if (buf[6] == ':') + ret = sscanf(buf, "\r\n+VGS:%2d\r\n", &value); + else if (buf[6] == '=') + ret = sscanf(buf, "\r\n+VGS=%2d\r\n", &value); + if (ret) __bt_hf_agent_handle_speaker_gain(value); - } DBG("---------__bt_hf_agent_handler_vgs --------"); @@ -1623,23 +1833,13 @@ static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info, const char *buf) { gint app_id = 0; - char *msg = NULL; + char msg[BT_HF_DATA_BUF_SIZE]; char fmt_str[BT_HF_CMD_BUF_SIZE]; - char *ptr = NULL; - char *save_ptr = NULL; - char *stop = NULL; DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++"); snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n", (int)(sizeof(msg) - 1)); - ptr = strstr(buf, "XSAT:"); - if (ptr) - app_id = strtol(ptr + 5, &stop, 10); - - if (stop) - msg = strtok_r(stop + 1, "\\", &save_ptr); - - if (app_id > 0 && msg) { + if (sscanf(buf, fmt_str, &app_id, msg)) { if (app_id == 2 && strstr(msg, "READTXPOWER")) { char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, }; char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr); @@ -1655,6 +1855,17 @@ static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info, return 0; } +static int __bt_hf_agent_handler_bsir(bt_hf_agent_info_t *bt_hf_info, const char *buf) +{ + DBG("+++++++++ __bt_hf_agent_handler_bsir +++++++++"); + gint value; + if (sscanf(buf, "\r\n+BSIR:%1d\r\n", &value) == 1) + __bt_hf_agent_handle_bsir(bt_hf_info, value); + + DBG("---------__bt_hf_agent_handler_bsir --------"); + return 0; +} + static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info, const char *buf) { @@ -1672,7 +1883,7 @@ static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info, __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, - "CallTerminated", + "FailedToDial", NULL); } @@ -1706,7 +1917,7 @@ static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info, __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, - "CallTerminated", + "FailedToDial", NULL); } __bt_hf_clear_prev_sent_cmd(); @@ -1729,7 +1940,7 @@ static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info, __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, - "CallTerminated", + "FailedToDial", NULL); } @@ -1753,7 +1964,7 @@ static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char if (call_list == NULL) goto done; - __bt_hf_launch_call_using_call_list(call_list, bt_hf_info); + __bt_hf_launch_call_using_call_list(call_list); __bt_hf_agent_send_call_status_info(call_list); @@ -1765,20 +1976,21 @@ done: return 0; } -static struct hf_event hf_event_callbacks[] = { +static bt_hf_event hf_event_callbacks[] = { { "\r\n+CIEV:", __bt_hf_agent_handler_ciev }, { "\r\nRING", __bt_hf_agent_handler_ring }, { "\r\n+CLIP:", __bt_hf_agent_handler_clip }, { "\r\n+BVRA:", __bt_hf_agent_handler_bvra }, { "\r\n+BCS:", __bt_hf_agent_handler_bcs }, - { "\r\n+VGS:", __bt_hf_agent_handler_vgs }, + { "\r\n+VGS", __bt_hf_agent_handler_vgs }, { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa }, { "\r\n+XSAT:", __bt_hf_agent_handler_xsat }, {"\r\n+CLCC:", __bt_hf_agent_handler_clcc }, + {"\r\n+BSIR:", __bt_hf_agent_handler_bsir }, { 0 } }; -static struct hf_event hf_event_resp_callbacks[] = { +static bt_hf_event hf_event_resp_callbacks[] = { { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error }, { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok }, { "ERROR", __bt_hf_agent_handler_response_err }, @@ -1794,7 +2006,8 @@ bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info len = g_slist_length(bt_hf_info->cmd_send_queue); for (i = 0; i < len; ++i) { cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i); - DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id); + if (cmd) + DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id); } len = g_slist_length(bt_hf_info->cmd_send_queue); DBG("Context queue length = %d", len); @@ -1816,7 +2029,7 @@ bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf) { - struct hf_event *ev; + bt_hf_event *ev; int ret = -EINVAL; bt_hf_agent_send_at_info *cmd = NULL; @@ -1919,15 +2132,15 @@ static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf) ERR("Invalid AT command signature..\n"); return 0; } - pos_end = strstr(pos_end, "\r\n"); - cmd_length = (pos_end - pos_start) + 2; + pos_end = strstr(pos_end, "\r\n"); + cmd_length = (pos_end - pos_start) + 2; INFO("CLCC balance Cmd Length = %d\n", cmd_length); memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length); cmd_buf[cmd_buf_len + cmd_length] = '\0'; if (strstr(cmd_buf, "\r\nOK\r\n")) { pos_end = strstr(datap, "\r\nOK\r\n"); - cmd_length = (pos_end - pos_start); + cmd_length = (pos_end - pos_start); memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length); cmd_buf[cmd_buf_len + cmd_length] = '\0'; INFO("New CLCC balance Cmd Length = %d", cmd_length); @@ -1963,9 +2176,11 @@ static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf) ERR("Invalid AT command end signature..\n"); break; } - cmd_length = (pos_end - pos_start) + 2; + cmd_length = (pos_end - pos_start) + 2; DBG("Cmd Length = %d\n", cmd_length); + if (cmd_length > BT_HF_DATA_BUF_SIZE - 1) + return FALSE; memcpy(cmd_buf, pos_start, cmd_length); cmd_buf[cmd_length] = '\0'; @@ -2125,8 +2340,8 @@ static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data, data); send_flag++; - DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s", - send_flag, count, data); + DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<", + send_flag, count); return TRUE; } @@ -2251,16 +2466,18 @@ static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices) GSList *runner = indices; gchar *cur = values - 1; - gchar *stop; DBG("Indicator string = %s", values); __bt_hf_agent_print_at_buffer("Indicator values :", values); while (cur != NULL) { cur += 1; - val = strtol(cur, &stop, 10); + sscanf(cur, "%1d", &val); cur = strchr(cur, ','); ind = g_slist_nth_data(runner, 0); - ind->value = val; + if (ind != NULL) + ind->value = val; runner = g_slist_next(runner); + if (runner == NULL) + break; } return indices; } @@ -2293,7 +2510,7 @@ static guint __bt_hf_get_hold_mpty_features(gchar *features) return result; } -static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data) +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; GDBusConnection *conn; @@ -2305,6 +2522,7 @@ static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, g 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"); @@ -2326,21 +2544,6 @@ static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, g return TRUE; } -static gboolean __bt_agent_query_and_update_call_list(gpointer data) -{ - DBG("+"); - bt_hf_agent_info_t *bt_hf_info = data; - - if (bt_hf_info->cli_sco_fd >= 0) - __bt_hf_agent_handle_call_list(bt_hf_info); - else - INFO("SCO Audio is already disconnected"); - - DBG("-"); - - return FALSE; -} - static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data) { bt_hf_agent_info_t *bt_hf_info = user_data; @@ -2374,7 +2577,10 @@ static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, 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_conn_cb, bt_hf_info); + __bt_hf_agent_sco_disconnect_cb, bt_hf_info); + + if (bt_hf_info->state != BT_HF_STATE_CONNECTED) + ERR("HFP is not yet connected"); /* S-Voice app requires the AudioConnected signal earlier */ DBG("Emit AudioConnected Signal"); @@ -2397,12 +2603,12 @@ static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, * In the case of outgoing call we need to lauch the callapp. */ - g_idle_add(__bt_agent_query_and_update_call_list, bt_hf_info); + __bt_hf_agent_launch_call_app(); return TRUE; } -void _bt_convert_addr_string_to_type_rev(unsigned char *addr, +static void __bt_convert_addr_string_to_type_rev(unsigned char *addr, const char *address) { int i; @@ -2411,7 +2617,7 @@ void _bt_convert_addr_string_to_type_rev(unsigned char *addr, ret_if(address == NULL); ret_if(addr == NULL); - for (i = 0; i < 6; i++) { + for (i = 0; i < BT_ADDRESS_LENGTH_MAX; i++) { addr[5 - i] = strtol(address, &ptr, 16); if (ptr[0] != '\0') { if (ptr[0] != ':') @@ -2429,9 +2635,6 @@ static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info) bdaddr_t bd_addr = {{0},}; int sco_skt; - if (bt_hf_info->state != BT_HF_STATE_CONNECTED) - return FALSE; - /* Create socket */ sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); if (sco_skt < 0) { @@ -2445,7 +2648,7 @@ static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info) DBG("Bind to address %s", bt_hf_info->remote_addr); - _bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr); + __bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr); memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t)); if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) { @@ -2581,11 +2784,9 @@ 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; - char *stop; guint feature = BT_HF_FEATURE_EC_ANDOR_NR | BT_HF_FEATURE_CALL_WAITING_AND_3WAY | BT_HF_FEATURE_CLI_PRESENTATION | - BT_HF_FEATURE_VOICE_RECOGNITION | BT_HF_FEATURE_REMOTE_VOLUME_CONTROL | BT_HF_FEATURE_ENHANCED_CALL_STATUS; @@ -2602,11 +2803,7 @@ static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info if (buf_ptr == NULL) return FALSE; - buf_ptr = strstr(buf_ptr, "BRSF:"); - bt_hf_info->ag_features = strtol(buf_ptr + 5, &stop, 10); - - - if (!ret || !bt_hf_info->ag_features) + if (!ret || sscanf(buf_ptr, "\r\n+BRSF:%5d", &bt_hf_info->ag_features) != 1) return FALSE; INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features); @@ -2653,8 +2850,26 @@ static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info } else bt_hf_info->hold_multiparty_features = 0; + if (bt_hf_info->ag_features & BT_AG_FEATURE_INBAND_RINGTONE) + bt_hf_info->inband_ringtone_support = TRUE; + else + bt_hf_info->inband_ringtone_support = FALSE; + INFO("Service layer connection successfully established...!"); + bt_hf_info->slc = TRUE; + send_flag = FALSE; + g_id = 0; + memset(global_buff, 0, sizeof(global_buff)); + return TRUE; +} + +static void __bt_establish_initialization(bt_hf_agent_info_t *bt_hf_info) +{ + gchar buf[BT_HF_DATA_BUF_SIZE]; + gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0}; + gboolean ret; + __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf, sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1); __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf, @@ -2682,45 +2897,66 @@ static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info else ERR("BT_HF_XSAT sending failed"); - /* send Bluetooth Samsung Support Feature cmd */ - ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf, - sizeof(BT_HF_BSSF) - 1); - if (ret) - INFO("SLC completed with all commands"); - else - ERR("BT_HF_BSSF sending failed"); + if (TIZEN_PROFILE_WEARABLE) { + /* send Bluetooth Samsung Support Feature cmd */ + ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf, + sizeof(BT_HF_BSSF) - 1); + + /* If we got a 'OK' reply, peer AG is samsung device. + * Otherwise, non-samsung device */ + if (ret && strstr(buf, "OK")) + bt_hf_info->is_companion_dev = TRUE; + else + bt_hf_info->is_companion_dev = FALSE; - bt_hf_info->slc = TRUE; - send_flag = FALSE; - g_id = 0; - memset(global_buff, 0, sizeof(global_buff)); - return TRUE; + if (ret) + INFO("SLC completed with [%s] device", + bt_hf_info->is_companion_dev ? "SS Companion" : "Other"); + else + ERR("BT_HF_BSSF sending failed"); + } } static void __bt_hf_agent_sigterm_handler(int signo) { - ERR_C("***** Signal handler came with signal %d *****", signo); GDBusConnection *conn; + int i; + + ERR_C("***** Signal handler came with signal %d *****", signo); conn = __bt_hf_get_gdbus_connection(); if (!conn) { - ERR("Unable to get connection"); - return; + ERR("Unable to get G-DBus connection"); + goto done; } + INFO("Getting gdbus connection done"); __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH, BT_HF_SERVICE_INTERFACE, - "CallEnded", NULL); - DBG("CallEnded Signal done"); + "CallIdle", NULL); + INFO("CallEnded Signal done"); + + g_dbus_connection_flush(conn, NULL, NULL, NULL); + INFO("Flush g_dbus_connection"); + +done: if (gmain_loop) { g_main_loop_quit(gmain_loop); - DBG("Exiting"); + INFO("Exiting"); gmain_loop = NULL; } else { INFO_C("Terminating HF agent"); exit(0); } + + if (signo == SIGTERM) + return; + + for (i = 0; i < BT_HF_SIG_NUM; i++) + sigaction(bt_hf_sig_to_handle[i], &(bt_hf_sigoldact[i]), NULL); + + raise(signo); } static void __bt_convert_addr_type_to_rev_string(char *address, @@ -2752,6 +2988,8 @@ static gboolean __bt_agent_request_service_level_conn(gpointer data) DBG("+"); memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE); + __bt_hf_agent_sco_accept(&bt_hf_info); + if (!__bt_establish_service_level_conn(&bt_hf_info)) { ERR("Service Level Connection is fail"); @@ -2782,8 +3020,6 @@ static gboolean __bt_agent_request_service_level_conn(gpointer data) bt_hf_info.state = BT_HF_STATE_CONNECTED; - __bt_hf_agent_sco_accept(&bt_hf_info); - __bt_hf_agent_start_watch(&bt_hf_info); remote_addr = bt_hf_info.remote_addr; @@ -2813,8 +3049,8 @@ static gboolean __bt_agent_request_service_level_conn(gpointer data) "Connected", g_variant_new("(s)", remote_addr)); - /* Request the call list and launch call app if required */ - __bt_hf_agent_handle_call_list(&bt_hf_info); + /* Establish the initialization */ + __bt_establish_initialization(&bt_hf_info); done: DBG("-"); @@ -2867,6 +3103,11 @@ static gboolean __bt_hf_agent_release(void) int bt_device_state = VCONFKEY_BT_DEVICE_NONE; GDBusConnection *conn; + if (clcc_timer) { + g_source_remove(clcc_timer); + clcc_timer = 0; + } + if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) { ERR("hf is already disconnected"); return FALSE; @@ -2941,8 +3182,7 @@ static int __bt_hf_register_profile(const char *uuid, uint16_t version, GVariantBuilder *builder; gchar *path = NULL; - proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, - "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE); + proxy = __bt_hf_gdbus_get_profile_proxy(); if (proxy == NULL) return BT_HF_AGENT_ERROR_INTERNAL; @@ -3066,6 +3306,78 @@ static void __bt_hf_agent_filter_cb(GDBusConnection *connection, DBG("-"); } +static int __bt_hf_agent_get_adapter_path(GDBusConnection *conn, char *path) +{ + GError *err = NULL; + GDBusProxy *manager_proxy = NULL; + GVariant *result = NULL; + char *adapter_path = NULL; + + if (conn == NULL) + return BT_HF_AGENT_ERROR_INTERNAL; + + manager_proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, NULL, + BLUEZ_SERVICE_NAME, + "/", + BT_MANAGER_INTERFACE, + NULL, &err); + + if (!manager_proxy) { + ERR("Unable to create proxy: %s", err->message); + goto fail; + } + + result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err); + if (!result) { + if (err != NULL) + ERR("Fail to get DefaultAdapter (Error: %s)", err->message); + else + ERR("Fail to get DefaultAdapter"); + + goto fail; + } + + if (g_strcmp0(g_variant_get_type_string(result), "(o)")) { + ERR("Incorrect result\n"); + goto fail; + } + + g_variant_get(result, "(&o)", &adapter_path); + + if (adapter_path == NULL || + strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) { + ERR("Adapter path is inproper\n"); + goto fail; + } + + if (path) + g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX); + + if (g_obj_path == NULL) { + g_obj_path = g_strdup(adapter_path); + INFO("Update g_obj_path [%s]", adapter_path); + } + + g_variant_unref(result); + g_object_unref(manager_proxy); + + return 0; + +fail: + g_clear_error(&err); + + if (result) + g_variant_unref(result); + + if (manager_proxy) + g_object_unref(manager_proxy); + + return BT_HF_AGENT_ERROR_INTERNAL; + +} + static void __bt_hf_agent_dbus_init(void) { GDBusConnection *conn; @@ -3082,6 +3394,10 @@ static void __bt_hf_agent_dbus_init(void) return; } + if (!__bt_hf_agent_get_adapter_path(gdbus_conn , NULL)) { + __bt_hf_agent_register(); + } + interface_added_sig_id = g_dbus_connection_signal_subscribe(conn, NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0, __bt_hf_agent_filter_cb, NULL, NULL); @@ -3091,15 +3407,13 @@ static void __bt_hf_agent_dbus_init(void) __bt_hf_agent_filter_cb, NULL, NULL); DBG("-"); - return; } static void __bt_hf_agent_dbus_deinit(void) { - - if (service_gproxy) { - g_object_unref(service_gproxy); - service_gproxy = NULL; + if (profile_gproxy) { + g_object_unref(profile_gproxy); + profile_gproxy = NULL; } if (gdbus_conn) { @@ -3117,7 +3431,6 @@ static void __bt_hf_agent_dbus_deinit(void) g_object_unref(gdbus_conn); gdbus_conn = NULL; } - return; } static int _hf_agent_answer_call(GDBusMethodInvocation *context) @@ -3298,6 +3611,88 @@ static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd) return BT_HF_AGENT_ERROR_NONE; } +static gboolean bt_hf_agent_sco_connect(void) +{ + struct sockaddr_sco addr; + bdaddr_t bd_addr = {{0},}; + int sk; + GIOChannel *sco_io; + GDBusConnection *conn; + + DBG("+"); + + if (bt_hf_info.state != BT_HF_STATE_CONNECTED) { + ERR("HF RFCOMM not Connected"); + return FALSE; + } + + if (bt_hf_info.cli_sco_fd > 0) { + ERR("SCO Already connected.."); + return FALSE; + } + + /* Create socket */ + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); + if (sk < 0) { + ERR("Can't create SCO socket"); + return FALSE; + } + + /* Bind to local address */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t)); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + ERR("Can't bind socket"); + goto error; + } + + /* Connect to remote device */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + __bt_convert_addr_string_to_type_rev(addr.sco_bdaddr.b, bt_hf_info.remote_addr); + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + ERR("Can't connect"); + goto error; + } + + DBG("SCO Connected"); + + bt_hf_info.cli_sco_fd = sk; + + sco_io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(sco_io, TRUE); + g_io_channel_set_encoding(sco_io, NULL, NULL); + 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); + + DBG("Emit AudioConnected Signal - Outgoing SCo connection"); + sco_audio_connected = BT_HF_AUDIO_CONNECTED; + + 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, + "AudioConnected", NULL); + + DBG("-"); + return TRUE; + +error: + close(sk); + DBG("-"); + return FALSE; +} + static gboolean bt_hf_agent_sco_disconnect(void) { DBG("+"); @@ -3356,12 +3751,6 @@ static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd) if (bt_hf_info.state != BT_HF_STATE_CONNECTED) return BT_HF_AGENT_ERROR_NOT_CONNECTED; - /* Should not send cmds if DUT has sent a command and waiting for response */ - if (prev_cmd[0] != 0) { - INFO("DUT is waiting a respond for previous TX cmd. Skip sending."); - return BT_HF_AGENT_ERROR_INTERNAL; - } - strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2); strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf)); @@ -3380,7 +3769,6 @@ 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_VOICE_RECOGNITION | BT_HF_FEATURE_REMOTE_VOLUME_CONTROL | BT_HF_FEATURE_ENHANCED_CALL_STATUS | BT_HF_FEATURE_CODEC_NEGOTIATION; @@ -3395,22 +3783,27 @@ static uint32_t __bt_hf_agent_get_hf_features(void) int main(void) { + int i; struct sigaction sa; uint32_t hf_features; INFO_C("### Starting Bluetooth HF agent"); +#if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36 + g_type_init(); +#endif hf_features = __bt_hf_agent_get_hf_features(); bt_hf_info.feature = (uint16_t) hf_features & 0x3F; memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = __bt_hf_agent_sigterm_handler; - sigaction(SIGTERM, &sa, NULL); - /* Temporarily, block the below signal for debugging */ -// sigaction(SIGSEGV, &sa, NULL); -// sigaction(SIGABRT, &sa, NULL); + for (i = 0; i < BT_HF_SIG_NUM; i++) + sigaction(bt_hf_sig_to_handle[i], &sa, &(bt_hf_sigoldact[i])); + + g_log_set_default_handler(__on_log_glib, NULL); + gmain_loop = g_main_loop_new(NULL, FALSE); if (gmain_loop == NULL) { @@ -3419,6 +3812,7 @@ int main(void) } __bt_hf_agent_dbus_init(); + g_main_loop_run(gmain_loop); __bt_hf_agent_dbus_deinit(); diff --git a/hf-agent/bluetooth-hf-agent.h b/hf-agent/bluetooth-hf-agent.h index a86a7f1..d544bae 100644 --- a/hf-agent/bluetooth-hf-agent.h +++ b/hf-agent/bluetooth-hf-agent.h @@ -27,6 +27,15 @@ #ifdef __cplusplus extern "C" { #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include #undef LOG_TAG #define LOG_TAG "BLUETOOTH_HF_AGENT" @@ -50,24 +59,24 @@ extern "C" { #define ERR_C(fmt, arg...) \ SLOGI_IF(TRUE, LOG_COLOR_RED" "fmt" "LOG_COLOR_RESET, ##arg) - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define retv_if(expr, val) \ + do { \ + if (expr) { \ + ERR("(%s) return", #expr); \ + return (val); \ + } \ + } while (0) #define BTPROTO_SCO 2 - #define BT_HF_DATA_BUF_SIZE 1024 #define BT_HF_CMD_BUF_SIZE 32 #define BT_HF_INDICATOR_DESCR_SIZE 20 #define BT_HF_CALLER_NUM_SIZE 64 /* size of number + type */ #define BT_HF_FMT_STR_SIZE 32 +#define BT_ADDRESS_LENGTH_MAX 6 +#define BT_ADAPTER_OBJECT_PATH_MAX 50 +#define AT_CMD_BUFF_SIZE 500 +#define BT_MAX_TEL_NUM_STR 100 #define BT_HF_AGENT_ERROR (__bt_hf_agent_error_quark()) @@ -80,12 +89,105 @@ extern "C" { #define BT_ERROR_ALREADY_EXIST "AlreadyExists" #define BT_ERROR_ALREADY_CONNECTED "Already Connected" #define BT_ERROR_NO_MEMORY "No memory" +#define BT_ERROR_NO_DATA "No data" #define BT_ERROR_I_O_ERROR "I/O error" #define BT_ERROR_OPERATION_NOT_AVAILABLE "Operation currently not available" #define BT_ERROR_OPERATION_NOT_ALLOWED "Operation not allowed" #define BT_ERROR_OPERATION_NOT_SUPPORTED "Operation not supported" #define BT_ERROR_INVALID_FILE_DESCRIPTOR "Invalid File Descriptor" +#define BT_HF_OK_RESPONSE "\r\nOK\r\n" +#define BT_HF_ERROR_RESPONSE "ERROR" +#define BT_HF_SEC_ERROR_RESPONSE "SERR" + +/* dbus interfaces */ +#define BT_HF_SERVICE_NAME "org.bluez.hf_agent" +#define BT_HF_AGENT_OBJECT_PATH "/org/bluez/handsfree_agent" +#define BT_HF_SERVICE_INTERFACE "org.tizen.HfApp" +#define BT_HF_BLUEZ_OBJECT_PATH "/org/tizen/handsfree" +#define BT_HF_BLUEZ_INTERFACE "org.bluez.HandsfreeAgent" +#define BLUEZ_SERVICE_NAME "org.bluez" +#define BLUEZ_HF_INTERFACE_NAME "org.bluez.HandsfreeGateway" +#define BLUEZ_PROFILE_MGMT_INTERFACE "org.bluez.ProfileManager1" +#define BT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager" +#define BT_ADAPTER_INTERFACE "org.bluez.Adapter1" + +#define BT_INTERFACES_ADDED "InterfacesAdded" +#define BT_INTERFACES_REMOVED "InterfacesRemoved" + +/* Handsfree features */ +#define BT_HF_FEATURE_EC_ANDOR_NR 0x0001 +#define BT_HF_FEATURE_CALL_WAITING_AND_3WAY 0x0002 +#define BT_HF_FEATURE_CLI_PRESENTATION 0x0004 +#define BT_HF_FEATURE_VOICE_RECOGNITION 0x0008 +#define BT_HF_FEATURE_REMOTE_VOLUME_CONTROL 0x0010 +#define BT_HF_FEATURE_ENHANCED_CALL_STATUS 0x0020 +#define BT_HF_FEATURE_ENHANCED_CALL_CONTROL 0x0040 +#define BT_HF_FEATURE_CODEC_NEGOTIATION 0x0080 + +/* Audio Gateway features */ +#define BT_AG_FEATURE_3WAY 0x1 +#define BT_AG_FEATURE_NREC 0x0002 +#define BT_AG_FEATURE_VOICE_RECOGNITION 0x0004 +#define BT_AG_FEATURE_INBAND_RINGTONE 0x0008 +#define BT_AG_FEATURE_VOICE_TAG 0x0010 +#define BT_AG_FEATURE_REJECT_CALL 0x0020 +#define BT_AG_FEATURE_ENHANCED_CALL_STATUS 0x0040 +#define BT_AG_FEATURE_ENHANCED_CALL_CONTROL 0x0080 +#define BT_AG_FEATURE_EXTENDED_RES_CODE 0x100 +#define BT_AG_FEATURE_CODEC_NEGOTIATION 0x0200 + +/* SCO Codec types */ +#define BT_HF_CODEC_ID_CVSD 1 +#define BT_HF_CODEC_ID_MSBC 2 + +/* AT commands */ +#define BT_HF_FEATURES "AT+BRSF=%d\r" /* = 0x7F = All features supported */ +#define BT_HF_INDICATORS_SUPP "AT+CIND=?\r" +#define BT_HF_INDICATORS_VAL "AT+CIND?\r" +#define BT_HF_INDICATORS_ENABLE "AT+CMER=3,0,0,1\r" +#define BT_HF_HOLD_MPTY_SUPP "AT+CHLD=?\r" +#define BT_HF_CALLER_IDENT_ENABLE "AT+CLIP=1\r" +#define BT_HF_CARRIER_FORMAT "AT+COPS=3,0\r" +#define BT_HF_EXTENDED_RESULT_CODE "AT+CMEE=1\r" +#define BT_HF_INDICATORS_ACTIVATION "AT+BIA=" +#define BT_HF_ANSWER_CALL "ATA\r" +#define BT_HF_END_CALL "AT+CHUP\r" +#define BT_HF_REDIAL "AT+BLDN\r" +#define BT_HF_DIAL_NO "ATD%.100s;\r" +#define BT_HF_VOICE_RECOGNITION "AT+BVRA=%d\r" +#define BT_HF_XSAT "AT+XSAT=00,TY,WA\r" +#define BT_HF_BSSF "AT+BSSF=8\r" +#define BT_HF_CALLLIST "AT+CLCC\r" +#define BT_HF_AVAILABLE_CODEC "AT+BAC=%d,%d\r" +#define BT_HF_CODEC_SELECT "AT+BCS=%d\r" +#define BT_HF_SPEAKER_GAIN "AT+VGS=%d\r" +#define BT_HF_DTMF "AT+VTS=%s\r" +#define BT_HF_NREC "AT+NREC=0\r" +#define BT_HF_CALLWAIT_NOTI_ENABLE "AT+CCWA=1\r" +#define BT_HF_RELEASE_ALL "AT+CHLD=0\r" +#define BT_HF_RELEASE_AND_ACCEPT "AT+CHLD=1\r" +#define BT_HF_ACCEPT_AND_HOLD "AT+CHLD=2\r" +#define BT_HF_JOIN_CALL "AT+CHLD=3\r" + +#define BT_HF_MAX_SPEAKER_GAIN 15 +#define BT_HF_MIN_SPEAKER_GAIN 0 + +/* Hold and multipary services on AG */ +#define BT_HF_CHLD_0 0x01 /* Releases all held calls or sets User Busy for a waiting call */ +#define BT_HF_CHLD_1 0x02 /* Releases all active calls and accept others */ +#define BT_HF_CHLD_1x 0x04 /* Releases specified active call only () */ +#define BT_HF_CHLD_2 0x08 /* Places all active calls on hold and accepts others */ +#define BT_HF_CHLD_2x 0x10 /* Place all calls on hold EXCEPT the call indicated by */ +#define BT_HF_CHLD_3 0x20 /* Adds a held call to the conversation */ +#define BT_HF_CHLD_4 0x40 /* Explicit Call Transfer */ + +enum hfp_version { + HFP_VERSION_1_5 = 0x0105, + HFP_VERSION_1_6 = 0x0106, + HFP_VERSION_LATEST = HFP_VERSION_1_6, +}; + typedef enum { BT_HF_AGENT_ERROR_NONE, BT_HF_AGENT_ERROR_INTERNAL, @@ -97,6 +199,7 @@ typedef enum { BT_HF_AGENT_ERROR_ALREADY_EXIST, BT_HF_AGENT_ERROR_ALREADY_CONNECTED, BT_HF_AGENT_ERROR_NO_MEMORY, + BT_HF_AGENT_ERROR_NO_DATA, BT_HF_AGENT_ERROR_I_O_ERROR, BT_HF_AGENT_ERROR_APPLICATION, BT_HF_AGENT_ERROR_NOT_ALLOWED, @@ -133,11 +236,20 @@ typedef enum { } bt_ag_cme_error_t; typedef enum { + BT_HF_STATE_DISCONNECTED, + BT_HF_STATE_CONNECTED +} bt_hf_state_t; + +typedef enum { + BT_HF_AUDIO_DISCONNECTED, + BT_HF_AUDIO_CONNECTED +} bt_hf_sco_state_t; + +typedef enum { BT_HF_CALL_DIR_OUTGOING, BT_HF_CALL_DIR_INCOMING, } bt_hf_call_direction_t; -/* Call status as per spec */ typedef enum { BT_HF_CALL_STAT_ACTIVE, BT_HF_CALL_STAT_HELD, @@ -147,137 +259,6 @@ typedef enum { BT_HF_CALL_STAT_WAITING, } bt_hf_call_status_t; -enum hfp_version { - HFP_VERSION_1_5 = 0x0105, - HFP_VERSION_1_6 = 0x0106, - HFP_VERSION_LATEST = HFP_VERSION_1_6, -}; - -/*Handsfree supported features*/ -#define BT_HF_FEATURE_EC_ANDOR_NR 0x0001 -#define BT_HF_FEATURE_CALL_WAITING_AND_3WAY 0x0002 -#define BT_HF_FEATURE_CLI_PRESENTATION 0x0004 -#define BT_HF_FEATURE_VOICE_RECOGNITION 0x0008 -#define BT_HF_FEATURE_REMOTE_VOLUME_CONTROL 0x0010 -#define BT_HF_FEATURE_ENHANCED_CALL_STATUS 0x0020 -#define BT_HF_FEATURE_ENHANCED_CALL_CONTROL 0x0040 -#define BT_HF_FEATURE_CODEC_NEGOTIATION 0x0080 - -/*AG suported feature*/ -#define BT_AG_FEATURE_3WAY 0x1 -#define BT_AG_FEATURE_NREC 0x0002 -#define BT_AG_FEATURE_EXTENDED_RES_CODE 0x100 -#define BT_AG_FEATURE_CODEC_NEGOTIATION 0x0200 - -#define BT_HF_CODEC_ID_CVSD 1 -#define BT_HF_CODEC_ID_MSBC 2 - -#define BT_HF_AUDIO_DISCONNECTED 0 -#define BT_HF_AUDIO_CONNECTED 1 - -#define BT_MAX_TEL_NUM_STR 100 - -#define BT_HF_FEATURES "AT+BRSF=%d\r" /* = 0x7F = All features supported */ -#define BT_HF_INDICATORS_SUPP "AT+CIND=?\r" -#define BT_HF_INDICATORS_VAL "AT+CIND?\r" -#define BT_HF_INDICATORS_ENABLE "AT+CMER=3,0,0,1\r" -#define BT_HF_HOLD_MPTY_SUPP "AT+CHLD=?\r" -#define BT_HF_CALLER_IDENT_ENABLE "AT+CLIP=1\r" -#define BT_HF_CARRIER_FORMAT "AT+COPS=3,0\r" -#define BT_HF_EXTENDED_RESULT_CODE "AT+CMEE=1\r" -#define BT_HF_INDICATORS_ACTIVATION "AT+BIA=" -#define BT_HF_ANSWER_CALL "ATA\r" -#define BT_HF_END_CALL "AT+CHUP\r" -#define BT_HF_REDIAL "AT+BLDN\r" -#define BT_HF_DIAL_NO "ATD%.100s;\r" -#define BT_HF_VOICE_RECOGNITION "AT+BVRA=%d\r" -#define BT_HF_XSAT "AT+XSAT=00,TY,WA\r" -#define BT_HF_BSSF "AT+BSSF=8\r" -#define BT_HF_CALLLIST "AT+CLCC\r" -#define BT_HF_AVAILABLE_CODEC "AT+BAC=%d,%d\r" -#define BT_HF_CODEC_SELECT "AT+BCS=%d\r" -#define BT_HF_SPEAKER_GAIN "AT+VGS=%d\r" -#define BT_HF_DTMF "AT+VTS=%s\r" -#define BT_HF_NREC "AT+NREC=0\r" -#define BT_HF_CALLWAIT_NOTI_ENABLE "AT+CCWA=1\r" -#define BT_HF_RELEASE_ALL "AT+CHLD=0\r" -#define BT_HF_RELEASE_AND_ACCEPT "AT+CHLD=1\r" -#define BT_HF_ACCEPT_AND_HOLD "AT+CHLD=2\r" -#define BT_HF_JOIN_CALL "AT+CHLD=3\r" - -#define BT_MAX_EVENT_STR_LENGTH 50 -#define BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS 200 - -#define BT_HF_MAX_SPEAKER_GAIN 15 -#define BT_HF_MIN_SPEAKER_GAIN 0 - - -typedef enum { - BT_AGENT_EVENT_HANDSFREE_CONNECT = 0x1100, - BT_AGENT_EVENT_HANDSFREE_DISCONNECT = 0x1200, -} bt_hfp_agent_event_type_t; - -/* Hold and multipary AG features. - * Comments below are copied from hands-free spec for reference */ -/* Releases all held calls or sets User Determined User Busy (UDUB) - * for a waiting call */ -#define BT_HF_CHLD_0 0x01 -/* Releases all active calls (if any exist) and accepts the other - * (held or waiting) call */ -#define BT_HF_CHLD_1 0x02 -/* Releases specified active call only */ -#define BT_HF_CHLD_1x 0x04 -/* Places all active calls (if any exist) on hold and accepts the other - * (held or waiting) call */ -#define BT_HF_CHLD_2 0x08 -/* Request private consultation mode with specified call (Place all - * calls on hold EXCEPT the call ) */ -#define BT_HF_CHLD_2x 0x10 -/* Adds a held call to the conversation */ -#define BT_HF_CHLD_3 0x20 -/* Connects the two calls and disconnects the subscriber from both calls - * (Explicit Call Transfer). Support for this value and its associated - * functionality is optional for the HF. */ -#define BT_HF_CHLD_4 0x40 - -#define BT_HF_OK_RESPONSE "\r\nOK\r\n" -#define BT_HF_ERROR_RESPONSE "ERROR" -#define BT_HF_SEC_ERROR_RESPONSE "SERR" - -#define BT_HF_SERVICE_NAME "org.bluez.hf_agent" -#define BT_HF_AGENT_OBJECT_PATH "/org/bluez/handsfree_agent" -#define BT_HF_SERVICE_INTERFACE "org.tizen.HfApp" - -#define BT_HF_BLUEZ_OBJECT_PATH "/org/tizen/handsfree" -#define BT_HF_BLUEZ_INTERFACE "org.bluez.HandsfreeAgent" - -#define BLUEZ_SERVICE_NAME "org.bluez" -#define BLUEZ_HF_INTERFACE_NAME "org.bluez.HandsfreeGateway" - -#define PM_SERVICE_NAME "org.tizen.system.deviced" -#define PM_OBJECT_PATH "/Org/Tizen/System/DeviceD/Display" -#define PM_INTERFACE_NAME "org.tizen.system.deviced.display" -#define AT_CMD_BUFF_SIZE 500 -#define BLUEZ_PROFILE_MGMT_INTERFACE "org.bluez.ProfileManager1" -#define BT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager" -#define BT_ADAPTER_INTERFACE "org.bluez.Adapter1" - -#define BT_INTERFACES_ADDED "InterfacesAdded" -#define BT_INTERFACES_REMOVED "InterfacesRemoved" - -#define retv_if(expr, val) \ - do { \ - if (expr) { \ - ERR("(%s) return", #expr); \ - return (val); \ - } \ - } while (0) - -typedef enum { - BT_HF_STATE_DISCONNECTED, - BT_HF_STATE_CONNECTED -} bt_hf_state_t; - typedef struct { guint32 fd; gint sco_fd; @@ -297,6 +278,8 @@ typedef struct { gboolean is_dialing; gboolean call_active; + gboolean inband_ringtone_support; + gboolean is_companion_dev; guint ciev_call_status; guint ciev_call_setup_status; @@ -321,10 +304,10 @@ typedef struct { int timer_id; } bt_hf_agent_send_at_info; -struct hf_event { +typedef struct { const char *cmd; int (*callback) (bt_hf_agent_info_t *bt_hf_info, const char *buf); -}; +} bt_hf_event; typedef struct { unsigned char b[6];