#include <bundle_internal.h>
#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_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
static GMainLoop *gmain_loop = NULL;
static char *g_obj_path;
-static GDBusConnection *gdbus_conn;
-static GDBusProxy *service_gproxy;
-static int owner_sig_id = -1;
+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 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*/
" <method name='VoiceRecognition'>"
" <arg type='i' name='status' direction='in'/>"
" </method>"
+" <method name='ScoConnect'>"
+" </method>"
" <method name='ScoDisconnect'>"
" </method>"
" <method name='SpeakerGain'>"
" <arg type='i' name='count' direction='out'/>"
" <arg type='a(siiii)' name='callList' direction='out'/>"
" </method>"
+" <method name='RequestCallListAsync'>"
+" </method>"
" <method name='GetAudioConnected'>"
" <arg type='i' name='status' direction='out'/>"
" </method>"
" <method name='IsHfConnected'>"
" <arg type='b' name='status' direction='out'/>"
" </method>"
+" <method name='IsInbandRingtoneSupported'>"
+" <arg type='b' name='status' direction='out'/>"
+" </method>"
+" <method name='AudioMuteOn'>"
+" </method>"
+" <method name='AudioMuteOff'>"
+" </method>"
" </interface>"
"</node>";
-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;
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(
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];
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);
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);
+
+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;
+ char s[BT_HF_DATA_BUF_SIZE] = {0, };
+ gboolean hide = FALSE;
+
+ gboolean has_clcc = FALSE;
+ gboolean has_clip = FALSE;
+ gboolean has_ccwa = FALSE;
+ char *xsat_ptr;
+
+ strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
+
+ has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
+ if (has_clcc == TRUE)
+ goto done;
+ has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
+ if (has_clip == TRUE)
+ goto done;
+ has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
+
+done:
+ /* +XSAT: 11,DISC */
+ xsat_ptr = strstr(s, "11,DISC,");
+ if (xsat_ptr) {
+ xsat_ptr = xsat_ptr + 8;
+ int x = 0;
+ while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
+ xsat_ptr[x] = 'X';
+ x++;
+ }
+ }
+
+ /* AT+XSAT=11,Q_CT,X,XXXX */
+ xsat_ptr = strstr(s, "11,Q_CT,");
+ if (xsat_ptr) {
+ xsat_ptr = xsat_ptr + 8;
+ int x = 0;
+ while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
+ if (x > 1) /* ignore 0 and 1 position */
+ xsat_ptr[x] = 'X';
+ x++;
+ }
+ }
+
+ i = 0;
+ while (s[i] != '\0') {
+ if (s[i] == '\r' || s[i] == '\n') {
+ s[i] = '.';
+ } else {
+ if (s[i] == '\"')
+ hide = hide ? FALSE : TRUE;
+ else if ((has_clcc || has_clip || has_ccwa) && hide) {
+ if (i % 2)
+ s[i] = 'X';
+ }
+ }
+ i++;
+ }
+ if (message)
+ INFO("%s Buffer = %s, Length = %zd ", message, s, strlen(s));
+ else
+ INFO("%s", s);
+}
+
static GQuark __bt_hf_agent_error_quark(void)
{
DBG("");
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);
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,
+ const gchar *path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
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()) {
g_variant_get(parameters, "(&s)", &cmd);
- DBG("Going to call SendAtCmd, cmd is = [%s]\n", cmd);
- ret = bt_hf_agent_send_at_cmd(context, cmd);
+ DBG("Going to call SendAtCmd\n");
+ 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");
} 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,
g_variant_new("(i)", sco_audio_connected));
} else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
DBG("Going to call IsHfConnected");
- INFO("is_hf_connected : %s", is_hf_connected ? "Connected":"Disconnected");
+ INFO("is_hf_connected : %s", is_hf_connected ? "Connected" : "Disconnected");
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));
+ } 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("-");
return;
conn = __bt_hf_get_gdbus_connection();
if (!conn) {
ERR("Unable to get connection");
+ g_free(path);
return FALSE;
}
&method_table,
NULL, NULL, &error);
if (object_id == 0) {
- ERR("Failed to register: %s", error->message);
- g_error_free(error);
+ if (error != NULL) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ }
g_dbus_node_info_unref(node_info);
g_free(path);
return FALSE;
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("+");
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) {
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)
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;
}
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;
}
/* In the case of ATD, prev_cmd will be always ATD, because we will not
* allow further commands. For safer side again set prev_cmd as ATD */
- strcpy(prev_cmd, "ATD");
+ strncpy(prev_cmd, "ATD\0", BT_HF_CMD_BUF_SIZE - 1);
}
hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
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;
- if (pending_flag)
- DBG("*** Add Pending queue request for = %s **** ", at);
- else
- DBG("Add Pending queue respnse for = %s ", at);
+ DBG("Add Pending queue. (pending_flag is %s)",
+ 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;
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;
}
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) {
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)
{
"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;
+ }
}
} 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)
+ 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;
+ }
- 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 (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) {
+ __bt_hf_agent_emit_signal(gdbus_conn,
+ 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*/
__bt_hf_agent_emit_signal(conn,
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)
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)
{
}
if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
- snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds", sizeof(number) - 1);
+ snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds",
+ (int)(sizeof(number) - 1));
if (sscanf(ccwa, fmt_str, number) == 1) {
sep = strchr(number, '"');
sep[0] = '\0';
return 0;
}
-static GSList *__bt_hf_prepare_call_list(const char *buf) {
+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;
char *str = NULL;
char *ptr = NULL;
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)
len = g_slist_length(call_list);
- while (len--) {
- call_info = g_slist_nth_data(call_list, len);
+ if (len > 0 && __bt_hf_agent_launch_call_app() == FALSE)
+ DBG("call app launching failed");
- /* 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 (__bt_hf_agent_launch_call_app(launch_type_str,
- call_info->number) == FALSE)
- DBG("call app launching failed");
- }
DBG("-");
}
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);
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)
__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];
{
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");
-}
-
-void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
-{
-
- int i = 0;
- char s[BT_HF_DATA_BUF_SIZE] = {0, };
- gboolean hide = FALSE;
-
- gboolean has_clcc = FALSE;
- gboolean has_clip = FALSE;
- gboolean has_ccwa = FALSE;
- char *xsat_ptr;
-
- strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
-
- has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
- if (has_clcc == TRUE)
- goto done;
- has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
- if (has_clip == TRUE)
- goto done;
- has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
-
-done:
- /* +XSAT: 11,DISC */
- xsat_ptr = strstr(s, "11,DISC,");
- if (xsat_ptr) {
- xsat_ptr = xsat_ptr + 8;
- int x = 0;
- while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
- xsat_ptr[x] = 'X';
- x++;
- }
- }
-
- /* AT+XSAT=11,Q_CT,X,XXXX */
- xsat_ptr = strstr(s, "11,Q_CT,");
- if (xsat_ptr) {
- xsat_ptr = xsat_ptr + 8;
- int x = 0;
- while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
- if (x > 1) /* ignore 0 and 1 position */
- xsat_ptr[x] = 'X';
- x++;
- }
- }
-
- i = 0;
- while (s[i] != '\0') {
- if (s[i] == '\r' || s[i] == '\n') {
- s[i] = '.';
- } else {
- if (s[i] == '\"')
- hide = hide ? FALSE : TRUE;
- else if ((has_clcc || has_clip || has_ccwa) && hide) {
- if (i % 2)
- s[i] = 'X';
- }
- }
- i++;
+ if (FALSE == ret) {
+ ERR("__bt_hf_send_only : FALSE");
}
- if (message)
- INFO("%s Buffer = %s, Length = %d ", message, s, strlen(s));
- else
- INFO("%s", s);
}
static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
- snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n", sizeof(indicator) - 1);
+ snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n",
+ BT_HF_INDICATOR_DESCR_SIZE + 4 - 1);
if (sscanf(buf, fmt_str, indicator) == 1) {
sep = strchr(indicator, ',');
sep[0] = '\0';
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;
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;
static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
{
gint value;
+ int ret = 0;
DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
- if (sscanf(buf, "\r\n+VGS:%2d\r\n", &value))
+ 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 --------");
static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
const char *buf)
{
- gint app_id;
+ gint app_id = 0;
char msg[BT_HF_DATA_BUF_SIZE];
char fmt_str[BT_HF_CMD_BUF_SIZE];
DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
- snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n", sizeof(msg) - 1);
+ snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n",
+ (int)(sizeof(msg) - 1));
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, };
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)
{
__bt_hf_agent_emit_signal(conn,
BT_HF_AGENT_OBJECT_PATH,
BT_HF_SERVICE_INTERFACE,
- "CallTerminated",
+ "FailedToDial",
NULL);
}
__bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
BT_HF_SERVICE_INTERFACE,
- "CallTerminated",
+ "FailedToDial",
NULL);
}
__bt_hf_clear_prev_sent_cmd();
__bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
BT_HF_SERVICE_INTERFACE,
- "CallTerminated",
+ "FailedToDial",
NULL);
}
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);
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 },
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);
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;
}
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;
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);
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';
if (cond & (G_IO_ERR | G_IO_HUP)) {
ERR("ERR or HUP on RFCOMM socket");
- INFO_C("Disconnected [HF role] [Terminated by remote dev]");
+ INFO_C("### Disconnected [HF role] [Terminated by remote dev]");
is_hf_connected = FALSE;
bt_hf_info->slc = FALSE;
__bt_hf_agent_release();
g_io_channel_flush(io_chan, NULL);
if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
- INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
- count, count - 6, "ATDXXXXXXX");
+ 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 {
- INFO("No queue....Send only buffer size =[%d] - Send <<<<<| %s",
- count, data);
+ __bt_hf_agent_print_at_buffer("[HF AT CMD] Send only without queue <<<<<:",
+ data);
}
send_flag++;
gboolean pending = FALSE;
GIOChannel *io_chan = bt_hf_info->io_chan;
- if (send_flag) {
+ if (send_flag)
pending = TRUE;
- }
+
__bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
if (pending)
g_io_channel_flush(io_chan, NULL);
if (count > 2 && data[2] == 'D') /* ATDXXXXX */
- INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
- count, count - 6, "ATDXXXXXXX");
+ INFO("[HF AT CMD] Send only <<<<<: Buffer = %s, Length = %zd ",
+ "ATDXXXXXXX", count);
else
- INFO("Send only buffer size =[%d] - Send <<<<<| %s", count, data);
+ __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 <<<<<| %s",
- send_flag, count, data);
+ DBG("Ref %d(after) on Send only buffer size =[%zd] - Send <<<<<",
+ send_flag, count);
return TRUE;
}
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);
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;
}
return result;
}
-static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+/* 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;
GDBusConnection *conn;
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");
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;
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_conn_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");
/* S-Voice app requires the AudioConnected signal earlier */
DBG("Emit AudioConnected Signal");
* 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;
- char *ptr = NULL;
+ int i;
+ char *ptr = NULL;
ret_if(address == NULL);
ret_if(addr == NULL);
- for (i = 0; i < 6; i++) {
- addr[5 - i] = strtol(address, &ptr, 16);
- if (ptr[0] != '\0') {
- if (ptr[0] != ':')
- return;
+ for (i = 0; i < BT_ADDRESS_LENGTH_MAX; i++) {
+ addr[5 - i] = strtol(address, &ptr, 16);
+ if (ptr[0] != '\0') {
+ if (ptr[0] != ':')
+ return;
- address = ptr + 1;
- }
- }
+ address = ptr + 1;
+ }
+ }
}
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) {
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) {
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_VOICE_RECOGNITION |
- BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
- BT_HF_FEATURE_ENHANCED_CALL_STATUS |
- 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,
strlen(cmd_buf));
- if (!ret )
+ if (!ret)
return FALSE;
buf_ptr = strstr(buf, "\r\n+BRSF:");
return FALSE;
INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
- if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
- ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
- if (ret != BT_HF_AGENT_ERROR_NONE)
- ERR("Unable to set the default WBC codec");
+ if (TIZEN_PROFILE_WEARABLE) {
+ if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
+ ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
+ if (ret != BT_HF_AGENT_ERROR_NONE)
+ ERR("Unable to set the default WBC codec");
- ret = __bt_hf_send_available_codec(bt_hf_info, 0);
- if (!ret)
- return FALSE;
+ ret = __bt_hf_send_available_codec(bt_hf_info, 0);
+ if (!ret)
+ return FALSE;
+ }
} else {
/* Default codec is NB */
ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
} 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,
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);
- bt_hf_info->slc = TRUE;
- send_flag = FALSE;
- g_id = 0;
- memset(global_buff, 0, sizeof(global_buff));
- return TRUE;
+ /* 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;
+
+ 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,
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");
if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
DBG("BT device state is : 0x%X", bt_device_state);
bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
- if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0) {
+ if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
ERR("vconf_set_int failed");
- }
} else {
ERR("vconf_get_int failed");
}
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;
INFO_SECURE("Address is : %s", remote_addr);
- INFO_C("Connected [HF role]");
+ INFO_C("### Connected [HF role]");
if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
DBG("BT device state is : 0x%X", bt_device_state);
bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
- if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0) {
+
+ if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
ERR("vconf_set_int failed");
- }
} else {
ERR("vconf_get_int failed");
}
"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("-");
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;
__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;
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;
+ }
+
if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
ERR("hf is already disconnected");
return FALSE;
if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
DBG("BT device state is : 0x%X", bt_device_state);
bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
- if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0) {
+
+ if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
ERR("vconf_set_int failed");
- }
} else {
ERR("vconf_get_int failed");
}
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;
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);
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);
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;
return;
}
- owner_sig_id = g_dbus_connection_signal_subscribe(conn,
- NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
+ 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);
+
+ interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
+ NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
+ __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) {
- if (owner_sig_id != -1)
+ if (interface_added_sig_id > 0)
+ g_dbus_connection_signal_unsubscribe(gdbus_conn,
+ interface_added_sig_id);
+
+ if (interface_removed_sig_id > 0)
g_dbus_connection_signal_unsubscribe(gdbus_conn,
- owner_sig_id);
+ interface_removed_sig_id);
+
+ interface_added_sig_id = 0;
+ interface_removed_sig_id = 0;
g_object_unref(gdbus_conn);
gdbus_conn = NULL;
}
- return;
}
static int _hf_agent_answer_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) {
}
/* 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;
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("+");
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));
static uint32_t __bt_hf_agent_get_hf_features(void)
{
+ uint32_t hf_features;
- 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;
+ 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;
}
int main(void)
{
+ int i;
struct sigaction sa;
uint32_t hf_features;
- INFO("Starting Bluetooth HF agent");
+ 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;
+ 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;
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) {
}
__bt_hf_agent_dbus_init();
+
g_main_loop_run(gmain_loop);
__bt_hf_agent_dbus_deinit();
if (gmain_loop)
g_main_loop_unref(gmain_loop);
- INFO("Terminating Bluetooth HF agent");
+ INFO_C("### Terminating Bluetooth HF agent");
return 0;
}