4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Chethan T N <chethan.tn@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
31 #include <sys/socket.h>
35 #include <gio/gunixfdlist.h>
36 #include <device/power.h>
37 #include <app_manager.h>
39 #include <vconf-keys.h>
40 #include <bundle_internal.h>
42 #include "bluetooth-hf-agent.h"
44 #define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3
45 #define CALL_APP_ID "org.tizen.call-ui"
47 #define MAX_WAITING_DELAY 8
48 #define READ_TX_POWER_MIN -30
50 #define BT_ADDRESS_STRING_SIZE 18
51 #define BT_AT_COMMAND_BUFFER_MAX 4000
52 #define BT_HF_ERROR_RESP "\r\nERROR\r\n"
53 #define BT_HF_COMMAND_TIMEOUT 3
55 #define ret_if(expr) \
58 ERR("(%s) return", #expr); \
63 static GMainLoop *gmain_loop = NULL;
64 static char *g_obj_path;
66 static GDBusConnection *gdbus_conn;
67 static GDBusProxy *service_gproxy;
68 static int owner_sig_id = -1;
72 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
73 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
75 /*Below Inrospection data is exposed to bluez from agent*/
76 static const gchar hf_agent_bluez_introspection_xml[] =
78 " <interface name='org.bluez.Profile1'>"
79 " <method name='NewConnection'>"
80 " <arg type='o' name='device' direction='in'/>"
81 " <arg type='h' name='fd' direction='in'/>"
82 " <arg type='a{sv}' name='options' direction='in'/>"
84 " <method name='RequestDisconnection'>"
85 " <arg type='o' name='device' direction='in'/>"
90 /*Below Inrospection data is exposed to application from agent*/
91 static const gchar hf_agent_introspection_xml[] =
93 " <interface name='org.tizen.HfApp'>"
94 " <method name='AnswerCall'>"
96 " <method name='TerminateCall'>"
98 " <method name='InitiateCall'>"
99 " <arg type='s' name='phoneno' direction='in'/>"
101 " <method name='VoiceRecognition'>"
102 " <arg type='i' name='status' direction='in'/>"
104 " <method name='ScoDisconnect'>"
106 " <method name='SpeakerGain'>"
107 " <arg type='u' name='gain' direction='in'/>"
109 " <method name='SendDtmf'>"
110 " <arg type='s' name='dtmf' direction='in'/>"
112 " <method name='SendAtCmd'>"
113 " <arg type='s' name='atcmd' direction='in'/>"
115 " <method name='ReleaseAndAccept'>"
117 " <method name='CallSwap'>"
119 " <method name='ReleaseAllCall'>"
121 " <method name='JoinCall'>"
123 " <method name='GetCurrentCodec'>"
124 " <arg type='i' name='codec' direction='out'/>"
126 " <method name='RequestCallList'>"
127 " <arg type='i' name='count' direction='out'/>"
128 " <arg type='a(siiii)' name='callList' direction='out'/>"
130 " <method name='GetAudioConnected'>"
131 " <arg type='i' name='status' direction='out'/>"
133 " <method name='IsHfConnected'>"
134 " <arg type='b' name='status' direction='out'/>"
139 static bt_hf_agent_info_t bt_hf_info;
140 static gboolean is_hf_connected = FALSE;
141 static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD;
142 static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
144 static char global_buff[BT_AT_COMMAND_BUFFER_MAX] = {0,};
147 static char prev_cmd[BT_HF_CMD_BUF_SIZE];
157 } hf_call_list_info_t;
159 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error);
161 static gboolean __bt_hf_agent_emit_property_changed(
162 GDBusConnection *connection,
164 const char *interface,
168 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
169 bt_hf_agent_info_t *bt_hf_info);
170 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info);
171 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info);
172 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
174 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
175 gchar *data, gsize count);
177 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
179 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
180 gchar *data, gchar *response, gsize count);
181 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indies);
182 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indies);
183 static guint __bt_hf_get_hold_mpty_features(gchar *features);
184 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info);
185 static void __bt_hf_agent_sigterm_handler(int signo);
186 static gboolean __bt_hf_agent_release(void);
188 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info);
189 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info);
190 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path);
191 static gboolean __bt_hf_agent_connection_release(void);
194 gchar descr[BT_HF_INDICATOR_DESCR_SIZE];
198 static int _hf_agent_answer_call(GDBusMethodInvocation *context);
200 static int _hf_agent_terminate_call(GDBusMethodInvocation *context);
202 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no);
204 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context,
207 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd);
209 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context,
210 unsigned int status);
212 static gboolean bt_hf_agent_sco_disconnect(void);
214 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf);
216 static GVariant *bt_hf_agent_request_call_list(void);
218 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd);
220 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf);
221 static GQuark __bt_hf_agent_error_quark(void)
225 static GQuark quark = 0;
227 quark = g_quark_from_static_string("hf-agent");
232 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error)
234 ERR("error[%d]", error);
237 case BT_HF_AGENT_ERROR_NOT_AVAILABLE:
238 return g_error_new(BT_HF_AGENT_ERROR, error,
239 BT_ERROR_NOT_AVAILABLE);
240 case BT_HF_AGENT_ERROR_NOT_CONNECTED:
241 return g_error_new(BT_HF_AGENT_ERROR, error,
242 BT_ERROR_NOT_CONNECTED);
243 case BT_HF_AGENT_ERROR_CONNECTION_FAILED:
244 return g_error_new(BT_HF_AGENT_ERROR, error,
245 BT_ERROR_NOT_CONNECTION_FAILED);
246 case BT_HF_AGENT_ERROR_BUSY:
247 return g_error_new(BT_HF_AGENT_ERROR, error,
249 case BT_HF_AGENT_ERROR_INVALID_PARAM:
250 return g_error_new(BT_HF_AGENT_ERROR, error,
251 BT_ERROR_INVALID_PARAM);
252 case BT_HF_AGENT_ERROR_ALREADY_EXIST:
253 return g_error_new(BT_HF_AGENT_ERROR, error,
254 BT_ERROR_ALREADY_EXIST);
255 case BT_HF_AGENT_ERROR_ALREADY_CONNECTED:
256 return g_error_new(BT_HF_AGENT_ERROR, error,
257 BT_ERROR_ALREADY_CONNECTED);
258 case BT_HF_AGENT_ERROR_NO_MEMORY:
259 return g_error_new(BT_HF_AGENT_ERROR, error,
261 case BT_HF_AGENT_ERROR_I_O_ERROR:
262 return g_error_new(BT_HF_AGENT_ERROR, error,
264 case BT_HF_AGENT_ERROR_APPLICATION:
265 return g_error_new(BT_HF_AGENT_ERROR, error,
266 BT_ERROR_OPERATION_NOT_AVAILABLE);
267 case BT_HF_AGENT_ERROR_NOT_ALLOWED:
268 return g_error_new(BT_HF_AGENT_ERROR, error,
269 BT_ERROR_OPERATION_NOT_ALLOWED);
270 case BT_HF_AGENT_ERROR_NOT_SUPPORTED:
271 return g_error_new(BT_HF_AGENT_ERROR, error,
272 BT_ERROR_OPERATION_NOT_SUPPORTED);
273 case BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
274 return g_error_new(BT_HF_AGENT_ERROR, error,
275 BT_ERROR_INVALID_FILE_DESCRIPTOR);
276 case BT_HF_AGENT_ERROR_INTERNAL:
278 return g_error_new(BT_HF_AGENT_ERROR, error,
283 static void __bt_hf_lock_display(int timeout)
287 ret = device_power_request_lock(POWER_LOCK_DISPLAY, timeout);
289 DBG("Lock PM state as current state!");
291 ERR("deviced error!");
294 static void __bt_hf_unlock_display()
298 ret = device_power_release_lock(POWER_LOCK_DISPLAY);
300 DBG("UnLock PM state");
302 ERR("deviced error!");
305 static void __hf_agent_method(GDBusConnection *connection,
307 const gchar *object_path,
308 const gchar *interface_name,
309 const gchar *method_name,
310 GVariant *parameters,
311 GDBusMethodInvocation *context,
316 INFO("method %s", method_name);
320 if (g_strcmp0(method_name, "NewConnection") == 0) {
324 GUnixFDList *fd_list;
325 const gchar *object_path;
328 g_variant_get(parameters, "(oha{sv})",
329 &object_path, &index, &options);
331 msg = g_dbus_method_invocation_get_message(context);
332 fd_list = g_dbus_message_get_unix_fd_list(msg);
333 if (fd_list == NULL) {
334 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
338 fd = g_unix_fd_list_get(fd_list, index, NULL);
340 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
344 DBG("FD is = [%d], Object path = [%s]", fd, object_path);
346 if (!__bt_hf_agent_connection(fd, object_path)) {
347 ret = BT_HF_AGENT_ERROR_INTERNAL;
351 g_dbus_method_invocation_return_value(context, NULL);
352 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
353 if (!__bt_hf_agent_connection_release()) {
354 ret = BT_HF_AGENT_ERROR_INTERNAL;
357 INFO_C("Disconnected [HF role] [Terminated by local host]");
358 g_dbus_method_invocation_return_value(context, NULL);
359 } else if (g_strcmp0(method_name, "Release") == 0) {
360 if (!__bt_hf_agent_connection_release()) {
361 ret = BT_HF_AGENT_ERROR_INTERNAL;
365 g_dbus_method_invocation_return_value(context, NULL);
366 } else if (g_strcmp0(method_name, "AnswerCall") == 0) {
367 DBG("Going to call AnswerCall");
368 ret = _hf_agent_answer_call(context);
372 } else if (g_strcmp0(method_name, "TerminateCall") == 0) {
373 DBG("Going to call TerminateCall");
374 ret = _hf_agent_terminate_call(context);
378 } else if (g_strcmp0(method_name, "InitiateCall") == 0) {
379 char *phoneno = NULL;
381 g_variant_get(parameters, "(&s)", &phoneno);
383 DBG_SECURE("Going to call InitiateCall, Number is = [%s]\n", phoneno);
384 ret = _hf_agent_dial_no(NULL, phoneno);
388 g_dbus_method_invocation_return_value(context, NULL);
390 } else if (g_strcmp0(method_name, "VoiceRecognition") == 0) {
393 g_variant_get(parameters, "(i)", &status);
395 DBG("Going to call VoiceRecognition, Status [%d]", status);
396 ret = _hf_agent_voice_recognition(context, status);
400 } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) {
401 DBG("Going to call ScoDisconnect");
402 if (!bt_hf_agent_sco_disconnect()) {
403 ret = BT_HF_AGENT_ERROR_INTERNAL;
407 g_dbus_method_invocation_return_value(context, NULL);
408 } else if (g_strcmp0(method_name, "SpeakerGain") == 0) {
409 unsigned int gain = 0;
411 g_variant_get(parameters, "(u)", &gain);
413 DBG("Going to call SpeakerGain, gain is = [%d]\n", gain);
414 ret = _hf_agent_set_speaker_gain(context, gain);
418 } else if (g_strcmp0(method_name, "SendDtmf") == 0) {
421 g_variant_get(parameters, "(&s)", &dtmf);
423 DBG("Going to call SendDtmf, dtmf is = [%s]\n", dtmf);
424 ret = _hf_agent_send_dtmf(NULL, dtmf);
427 g_dbus_method_invocation_return_value(context, NULL);
429 } else if (g_strcmp0(method_name, "SendAtCmd") == 0) {
432 g_variant_get(parameters, "(&s)", &cmd);
434 DBG("Going to call SendAtCmd, cmd is = [%s]\n", cmd);
435 ret = bt_hf_agent_send_at_cmd(context, cmd);
439 } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) {
440 DBG("Going to call ReleaseAndAccept");
441 ret = _hf_agent_send_3way_cmd(context,
442 BT_HF_RELEASE_AND_ACCEPT);
446 } else if (g_strcmp0(method_name, "CallSwap") == 0) {
447 DBG("Going to call CallSwap");
448 ret = _hf_agent_send_3way_cmd(context,
449 BT_HF_ACCEPT_AND_HOLD);
453 } else if (g_strcmp0(method_name, "ReleaseAllCall") == 0) {
454 DBG("Going to call ReleaseAllCall");
455 ret = _hf_agent_send_3way_cmd(context, BT_HF_RELEASE_ALL);
459 } else if (g_strcmp0(method_name, "JoinCall") == 0) {
460 DBG("Going to call JoinCall");
461 ret = _hf_agent_send_3way_cmd(context, BT_HF_JOIN_CALL);
465 } else if (g_strcmp0(method_name, "GetCurrentCodec") == 0) {
466 DBG("Going to call GetCurrentCodec");
467 INFO("Current codec : %d", current_codec_id);
468 g_dbus_method_invocation_return_value(context,
469 g_variant_new("(i)", current_codec_id));
470 } else if (g_strcmp0(method_name, "RequestCallList") == 0) {
473 DBG("Going to call RequestCallList");
474 call_var = bt_hf_agent_request_call_list();
476 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
479 g_dbus_method_invocation_return_value(context, call_var);
480 } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) {
481 DBG("Going to call GetAudioConnected");
482 g_dbus_method_invocation_return_value(context,
483 g_variant_new("(i)", sco_audio_connected));
484 } else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
485 DBG("Going to call IsHfConnected");
486 INFO("is_hf_connected : %s", is_hf_connected ? "Connected" : "Disconnected");
488 g_dbus_method_invocation_return_value(context,
489 g_variant_new("(b)", is_hf_connected));
495 err = __bt_hf_agent_set_error(ret);
496 g_dbus_method_invocation_return_gerror(context, err);
501 static const GDBusInterfaceVTable method_table = {
507 static GDBusNodeInfo *__bt_hf_create_method_node_info
508 (const gchar *introspection_data)
510 if (introspection_data == NULL)
513 return g_dbus_node_info_new_for_xml(introspection_data, NULL);
516 static GDBusConnection *__bt_hf_get_gdbus_connection(void)
518 GDBusConnection *local_system_gconn = NULL;
521 if (gdbus_conn == NULL) {
522 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
525 ERR("Unable to connect to dbus: %s", err->message);
530 } else if (g_dbus_connection_is_closed(gdbus_conn)) {
531 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
533 if (!local_system_gconn) {
534 ERR("Unable to connect to dbus: %s", err->message);
538 gdbus_conn = local_system_gconn;
544 static gboolean __bt_hf_register_profile_methods(void)
547 GError *error = NULL;
550 GDBusNodeInfo *node_info;
552 GDBusConnection *conn;
554 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
556 G_BUS_NAME_OWNER_FLAGS_NONE,
560 DBG("owner_id is [%d]", owner_id);
562 node_info = __bt_hf_create_method_node_info(
563 hf_agent_bluez_introspection_xml);
564 if (node_info == NULL)
567 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
568 DBG("path is [%s]", path);
570 conn = __bt_hf_get_gdbus_connection();
572 ERR("Unable to get connection");
577 object_id = g_dbus_connection_register_object(conn, path,
578 node_info->interfaces[0],
581 if (object_id == 0) {
582 ERR("Failed to register: %s", error->message);
584 g_dbus_node_info_unref(node_info);
589 g_dbus_node_info_unref(node_info);
591 node_info = __bt_hf_create_method_node_info(hf_agent_introspection_xml);
592 if (node_info == NULL)
595 path = g_strdup(BT_HF_AGENT_OBJECT_PATH);
596 DBG("path is [%s]", path);
598 object_id = g_dbus_connection_register_object(conn, path,
599 node_info->interfaces[0],
602 if (object_id == 0) {
604 ERR("Failed to register: %s", error->message);
607 g_dbus_node_info_unref(node_info);
612 g_dbus_node_info_unref(node_info);
618 static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service,
619 const gchar *path, const gchar *interface)
625 GDBusConnection *conn;
627 conn = __bt_hf_get_gdbus_connection();
629 ERR("Unable to get connection");
633 proxy = g_dbus_proxy_new_sync(conn,
634 G_DBUS_PROXY_FLAGS_NONE, NULL,
636 interface, NULL, &err);
640 ERR("Unable to create proxy: %s", err->message);
650 static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service,
651 const gchar *path, const gchar *interface)
653 return (service_gproxy) ? service_gproxy :
654 __bt_hf_gdbus_init_service_proxy(service,
658 static char __bt_hf_agent_get_tx_power(char *address)
662 GError *error = NULL;
663 char result = READ_TX_POWER_MIN; /* default minimum */
665 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, g_obj_path,
666 BLUEZ_HF_INTERFACE_NAME);
668 ERR("Proxy is NULL");
672 ret = g_dbus_proxy_call_sync(proxy,
673 "GetTxPowerLevel", g_variant_new("(s)", address),
674 G_DBUS_CALL_FLAGS_NONE, -1,
677 ERR("DBus is failed");
679 /* Dbus gives error cause */
680 ERR("D-Bus API failure: errCode[%x], message[%s]",
681 error->code, error->message);
682 g_clear_error(&error);
686 g_variant_get(ret, "(y)", &result);
687 DBG("TX power level = %d", result);
688 g_variant_unref(ret);
692 static int __bt_hf_agent_gdbus_method_send(const char *service,
693 GVariant *path, const char *interface,
700 GError *error = NULL;
702 proxy = __bt_hf_gdbus_get_service_proxy(service, g_obj_path, interface);
704 return BT_HF_AGENT_ERROR_INTERNAL;
706 ret = g_dbus_proxy_call_sync(proxy,
708 G_DBUS_CALL_FLAGS_NONE, -1,
711 /* dBUS-RPC is failed */
712 ERR("dBUS-RPC is failed");
714 /* dBUS gives error cause */
715 ERR("D-Bus API failure: errCode[%x], message[%s]",
716 error->code, error->message);
718 g_clear_error(&error);
720 return BT_HF_AGENT_ERROR_INTERNAL;
723 g_variant_unref(ret);
725 return BT_HF_AGENT_ERROR_NONE;
728 static void __bt_hf_agent_release_queue(void)
731 bt_hf_agent_send_at_info *cmd;
734 len = g_slist_length(bt_hf_info.cmd_send_queue);
735 for (i = 0; i < len; ++i) {
736 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
737 if (cmd && cmd->context) {
738 DBG("Pending context found for %.6s[%d]",
739 cmd->at_cmd, cmd->id);
740 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_INTERNAL);
741 g_dbus_method_invocation_return_gerror(cmd->context, err);
744 if (cmd && cmd->timer_id)
745 g_source_remove(cmd->timer_id);
747 g_slist_free(bt_hf_info.cmd_send_queue);
748 bt_hf_info.cmd_send_queue = NULL;
752 static gboolean __bt_hf_monitor_timer_cb(gpointer data)
755 bt_hf_agent_send_at_info *cmd = data;
756 ERR_C("Monitor timer came becuase of timeout for sendflag %d, %s",
757 send_flag, cmd->at_cmd);
758 /* In the case of ATD, we have to inform the remote to end the call */
759 if (strstr(cmd->at_cmd, "ATD") || strstr(cmd->at_cmd, "BLDN")) {
760 INFO_C("Sending CHUP for remote call termination");
761 __bt_hf_send_only_without_queue(&bt_hf_info, BT_HF_END_CALL,
762 strlen(BT_HF_END_CALL));
763 /* Here there is a high posisbility that we do not get response
764 * for CHUP. Hence we need to decrement send_flag to process further
765 * incomming packets because we already incremented it in the CHUP case. */
769 /* In the case of ATD, prev_cmd will be always ATD, because we will not
770 * allow further commands. For safer side again set prev_cmd as ATD */
771 strncpy(prev_cmd, "ATD\0", BT_HF_CMD_BUF_SIZE - 1);
773 hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
781 gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
782 int count, gboolean pending_flag)
785 if (bt_hf_info.slc == FALSE)
789 DBG("*** Add Pending queue request for = %s **** ", at);
791 DBG("Add Pending queue respnse for = %s ", at);
793 bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
795 memcpy(cmd->at_cmd, at, count);
797 cmd->context = context;
798 cmd->pending = pending_flag;
799 bt_hf_info.cmd_send_queue = g_slist_append(bt_hf_info.cmd_send_queue,
801 len = g_slist_length(bt_hf_info.cmd_send_queue);
802 for (i = 0; i < len; ++i) {
803 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
804 DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id);
807 /* We need to have base timeout + tolerance value to process other request */
808 if (strstr(at, "ATD") || strstr(at, "BLDN")) {
809 /* Android 15 seconds timeout in case of ATD timeout in flight mode */
810 cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len,
811 __bt_hf_monitor_timer_cb, cmd);
813 cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len,
814 __bt_hf_monitor_timer_cb, cmd);
820 Below methods exposed to Applicatoins
822 static gboolean __bt_hf_agent_emit_signal(GDBusConnection *connection,
823 const char *path, const char *interface,
824 const char *signal_name, GVariant *param)
826 GError *error = NULL;
828 ret = g_dbus_connection_emit_signal(connection,
830 interface, signal_name,
834 /* dBUS gives error cause */
835 ERR("D-Bus API failure: errCode[%x], message[%s]",
836 error->code, error->message);
837 g_clear_error(&error);
840 INFO_C("Emit Signal [%s]", signal_name);
845 static gboolean __bt_hf_agent_emit_property_changed(
846 GDBusConnection *connection,
848 const char *interface,
854 GError *error = NULL;
856 ret = g_dbus_connection_emit_signal(connection,
857 NULL, path, interface,
859 g_variant_new("s(v)", name, property),
863 /* dBUS gives error cause */
864 ERR("D-Bus API failure: errCode[%x], message[%s]",
865 error->code, error->message);
866 g_clear_error(&error);
874 Below methods exposed to Bluez
877 static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
878 guint index, gint value)
880 GDBusConnection *conn;
882 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
884 ERR("Indicator is NULL");
891 conn = __bt_hf_get_gdbus_connection();
893 ERR("Unable to get connection");
897 INFO("Indicator name is %s, value = [%d]", name, value);
898 if (!strcmp(name, "\"call\"")) {
899 bt_hf_info->ciev_call_status = value;
901 __bt_hf_agent_emit_signal(conn,
902 BT_HF_AGENT_OBJECT_PATH,
903 BT_HF_SERVICE_INTERFACE,
904 "CallStarted", NULL);
905 bt_hf_info->is_dialing = FALSE;
906 bt_hf_info->call_active = TRUE;
907 } else if (bt_hf_info->call_active) {
908 __bt_hf_agent_emit_signal(conn,
909 BT_HF_AGENT_OBJECT_PATH,
910 BT_HF_SERVICE_INTERFACE,
912 bt_hf_info->call_active = FALSE;
915 } else if (!strcmp(name, "\"callsetup\"")) {
916 bt_hf_info->ciev_call_setup_status = value;
917 if (value == 0 && bt_hf_info->is_dialing) {
918 __bt_hf_agent_emit_signal(conn,
919 BT_HF_AGENT_OBJECT_PATH,
920 BT_HF_SERVICE_INTERFACE,
923 bt_hf_info->is_dialing = FALSE;
924 } else if (!bt_hf_info->is_dialing && value > 0)
925 bt_hf_info->is_dialing = TRUE;
927 if (bt_hf_info->ciev_call_status == 0 &&
928 bt_hf_info->ciev_call_setup_status == 0)
929 __bt_hf_agent_emit_signal(gdbus_conn,
930 BT_HF_AGENT_OBJECT_PATH,
931 BT_HF_SERVICE_INTERFACE,
934 } else if (!strcmp(name, "\"callheld\"")) {
935 if (value == 0) { /* No calls held*/
936 __bt_hf_agent_emit_signal(conn,
937 BT_HF_AGENT_OBJECT_PATH,
938 BT_HF_SERVICE_INTERFACE,
941 } else if (value == 1) {
942 /*Call is placed on hold or active/held calls swapped */
943 __bt_hf_agent_emit_signal(conn,
944 BT_HF_AGENT_OBJECT_PATH,
945 BT_HF_SERVICE_INTERFACE,
946 "CallsSwapped", NULL);
947 bt_hf_info->is_dialing = FALSE;
949 /*Call on hold, no active call*/
950 __bt_hf_agent_emit_signal(conn,
951 BT_HF_AGENT_OBJECT_PATH,
952 BT_HF_SERVICE_INTERFACE,
954 bt_hf_info->is_dialing = FALSE;
956 } else if (!strcmp(name, "\"service\""))
957 __bt_hf_agent_emit_property_changed(conn,
958 BT_HF_AGENT_OBJECT_PATH,
959 BT_HF_SERVICE_INTERFACE,
960 "RegistrationStatus",
961 g_variant_new("(q)", value));
962 else if (!strcmp(name, "\"signal\""))
963 __bt_hf_agent_emit_property_changed(conn,
964 BT_HF_AGENT_OBJECT_PATH,
965 BT_HF_SERVICE_INTERFACE, "SignalStrength",
966 g_variant_new("(q)", value));
967 else if (!strcmp(name, "\"roam\""))
968 __bt_hf_agent_emit_property_changed(conn,
969 BT_HF_AGENT_OBJECT_PATH,
970 BT_HF_SERVICE_INTERFACE, "RoamingStatus",
971 g_variant_new("(q)", value));
972 else if (!strcmp(name, "\"battchg\""))
973 __bt_hf_agent_emit_property_changed(conn,
974 BT_HF_AGENT_OBJECT_PATH,
975 BT_HF_SERVICE_INTERFACE, "BatteryCharge",
976 g_variant_new("(q)", value));
980 static gboolean __bt_hf_agent_launch_call_app(const char *launch_type,
987 app_manager_is_running(CALL_APP_ID, &is_running);
991 DBG_SECURE("Launch type = %s, number(%s)", launch_type, number);
995 ERR("bundle_create() Failed");
999 bundle_add(b, "launch-type", launch_type);
1001 if (strlen(number) != 0)
1002 bundle_add(b, "number", number);
1004 bundle_add(b, "carrier-type", "BT");
1005 DBG("For 3G, carrier-type: BT has been added");
1007 aul_launch_app(CALL_APP_ID, b);
1015 static void __bt_hf_agent_handle_voice_activation(gint value)
1017 GDBusConnection *conn;
1019 conn = __bt_hf_get_gdbus_connection();
1021 ERR("Unable to get connection");
1025 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1026 BT_HF_SERVICE_INTERFACE,
1028 g_variant_new("(i)", value));
1033 static void __bt_hf_agent_handle_speaker_gain(gint value)
1035 GDBusConnection *conn;
1037 conn = __bt_hf_get_gdbus_connection();
1039 ERR("Unable to get connection");
1043 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1044 BT_HF_SERVICE_INTERFACE, "VolumeSpeaker",
1045 g_variant_new("(i)", value));
1050 static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info,
1053 GDBusConnection *conn;
1055 gchar number[BT_HF_CALLER_NUM_SIZE];
1057 char fmt_str[BT_HF_FMT_STR_SIZE];
1058 int len = strlen(buf);
1060 DBG("__bt_hf_agent_handle_ccwa +");
1061 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1062 ERR("buf len %d is too long", len);
1066 if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
1067 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds",
1068 (int)(sizeof(number) - 1));
1069 if (sscanf(ccwa, fmt_str, number) == 1) {
1070 sep = strchr(number, '"');
1075 conn = __bt_hf_get_gdbus_connection();
1077 ERR("Unable to get connection");
1081 __bt_hf_agent_emit_signal(conn,
1082 BT_HF_AGENT_OBJECT_PATH,
1083 BT_HF_SERVICE_INTERFACE, "CallWaiting",
1084 g_variant_new("(s)", ccwa));
1086 ERR_SECURE("CCWA '%s' is Call Wating", buf);
1090 DBG("__bt_hf_agent_handle_ccwa -");
1094 static GSList *__bt_hf_prepare_call_list(const char *buf)
1096 GSList *call_list = NULL;
1101 char delim_sep[] = "\r\n";
1102 char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1104 hf_call_list_info_t *call_info;
1107 strncpy(temp_buf, buf, BT_HF_DATA_BUF_SIZE - 1);
1109 str = strtok_r(temp_buf, delim_sep, &sp);
1110 while (str != NULL) {
1111 if (!(strstr(str, "+CLCC:"))) {
1112 str = strtok_r(NULL, delim_sep, &sp);
1116 call_info = g_new0(hf_call_list_info_t, 1);
1118 sscanf(str, "+CLCC: %1d,%1d, %1d, %1d, %1d",
1119 &call_info->idx, &call_info->dir,
1120 &call_info->status, &call_info->mode,
1121 &call_info->multi_party);
1122 DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n",
1123 call_info->idx, call_info->dir, call_info->status,
1124 call_info->mode, call_info->multi_party);
1126 ptr = strstr(str, "\"");
1128 temp = strstr(ptr + 1, "\"");
1131 DBG_SECURE("\tPhone Number = [%s]\n", ptr + 1);
1132 call_info->number = g_strdup(ptr + 1);
1134 if (strstr(temp + 1, ",")) {
1136 DBG("\tType = [%s]\n", temp);
1137 call_info->type = atoi(temp);
1141 /*In case of no phone no. in CLCC respnse, we should launch call application
1142 * with NULL string. By doing so "unknown" shall be displayed*/
1143 DBG("Phone number does not exist\n");
1144 call_info->number = g_strdup("");
1147 call_list = g_slist_append(call_list, call_info);
1148 str = strtok_r(NULL, delim_sep, &sp);
1154 static GSList *__bt_hf_get_call_list(bt_hf_agent_info_t *bt_hf_info)
1156 char buf[BT_HF_DATA_BUF_SIZE] = {0,};
1157 GSList *call_list = NULL;
1161 /* Send CLCC when the callsetup */
1162 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLLIST, buf,
1163 sizeof(BT_HF_CALLLIST) - 1);
1164 DBG_SECURE("Receive CLCC response buffer = '%s'", buf);
1166 call_list = __bt_hf_prepare_call_list(buf);
1171 static void __bt_hf_call_info_free(void *data)
1175 hf_call_list_info_t *call_info = data;
1176 g_free(call_info->number);
1182 static void __bt_hf_free_call_list(GSList *call_list)
1186 g_slist_free_full(call_list, __bt_hf_call_info_free);
1191 static void __bt_hf_launch_call_using_call_list(GSList *call_list,
1192 bt_hf_agent_info_t *bt_hf_info)
1195 const char *launch_type_str;
1196 hf_call_list_info_t *call_info;
1199 if (call_list == NULL)
1202 len = g_slist_length(call_list);
1205 call_info = g_slist_nth_data(call_list, len);
1207 /* Launch based on below conditions
1208 * DC - Active call which is initiated from H
1209 * MR - Alerting call which is initiated from H
1210 * MT - Incoming call */
1211 if (call_info->status == BT_HF_CALL_STAT_ACTIVE) {
1212 launch_type_str = "DC";
1214 if (call_info->dir == BT_HF_CALL_DIR_INCOMING)
1215 launch_type_str = "MT";
1217 launch_type_str = "MR";
1220 if (__bt_hf_agent_launch_call_app(launch_type_str,
1221 call_info->number) == FALSE)
1222 DBG("call app launching failed");
1227 static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list)
1233 hf_call_list_info_t *call_info;
1235 GVariantBuilder *builder;
1238 builder = g_variant_builder_new(G_VARIANT_TYPE("a(siiii)"));
1240 call_count = g_slist_length(call_list);
1241 DBG("Total call count = '%d'", call_count);
1243 while (call_count--) {
1244 call_info = g_slist_nth_data(call_list, call_count);
1245 INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d",
1246 call_info->idx, call_info->dir, call_info->status,
1247 call_info->mode, call_info->multi_party);
1248 caller = call_info->number;
1250 g_variant_builder_add(builder, "(siiii)",
1251 caller, call_info->dir, call_info->status,
1252 call_info->multi_party, call_info->idx);
1254 var_data = g_variant_new("(ia(siiii))",
1255 g_slist_length(call_list), builder);
1257 g_variant_builder_unref(builder);
1262 static void __bt_hf_clear_prev_sent_cmd(void)
1264 if (prev_cmd[0] != 0)
1265 ERR("No sent command");
1267 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
1272 static void __bt_hf_agent_send_call_status_info(GSList *call_list)
1274 GDBusConnection *conn;
1277 var_data = __bt_hf_agent_get_call_status_info(call_list);
1278 conn = __bt_hf_get_gdbus_connection();
1280 ERR("Unable to get connection");
1285 __bt_hf_agent_emit_signal(conn,
1286 BT_HF_AGENT_OBJECT_PATH,
1287 BT_HF_SERVICE_INTERFACE,
1292 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info)
1296 __bt_hf_lock_display(0);
1298 bt_hf_info->context = NULL;
1300 /* Send CLCC. The response will be handled in the handler */
1301 ret = __bt_hf_send_only(bt_hf_info, BT_HF_CALLLIST,
1302 sizeof(BT_HF_CALLLIST) - 1);
1304 ERR("Failed to send CLCC");
1306 __bt_hf_unlock_display();
1309 static void __bt_hf_agent_request_call_list_info(bt_hf_agent_info_t *bt_hf_info,
1313 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
1315 ERR("Indicator is NULL");
1319 DBG("name : %s", name);
1321 if ((strcmp(name, "\"callsetup\"") != 0) &&
1322 (strcmp(name, "\"call\"") != 0) &&
1323 (strcmp(name, "\"callheld\"") != 0))
1326 __bt_hf_lock_display(0);
1328 __bt_hf_agent_handle_call_list(bt_hf_info);
1330 __bt_hf_unlock_display();
1334 static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only)
1336 gchar buf[BT_HF_DATA_BUF_SIZE];
1337 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1340 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_AVAILABLE_CODEC,
1341 BT_HF_CODEC_ID_CVSD, BT_HF_CODEC_ID_MSBC);
1343 bt_hf_info->context = NULL;
1345 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1348 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
1351 if (!ret || !strstr(buf, "OK"))
1357 static int _hf_agent_codec_setup(const char *addr, guint codec_id)
1362 ERR("g_obj_path is NULL\n");
1363 return BT_HF_AGENT_ERROR_INTERNAL;
1367 case BT_HF_CODEC_ID_CVSD:
1368 INFO("Set NB parameters");
1369 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1370 g_variant_new("(ss)", "Handsfree", addr),
1371 BT_ADAPTER_INTERFACE,
1374 case BT_HF_CODEC_ID_MSBC:
1375 INFO("Set WBS parameters");
1376 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1377 g_variant_new("(ss)", "Handsfree", addr),
1378 BT_ADAPTER_INTERFACE,
1379 "SetWbsParameters");
1382 ret = BT_HF_AGENT_ERROR_INTERNAL;
1383 ERR("Invalid Codec\n");
1388 ERR("Failed to setup the Codec\n");
1390 current_codec_id = codec_id;
1395 static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info,
1398 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1401 if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) {
1402 INFO("Codec id doesn't match, so send available codec again");
1403 ret = __bt_hf_send_available_codec(bt_hf_info, 1);
1405 ERR("Failed to send avalable codec");
1409 /* HF should be ready accpet SCO connection before sending theresponse for
1410 "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */
1411 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id);
1413 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id);
1415 bt_hf_info->context = NULL;
1417 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1419 ERR("Failed to select the Codec");
1422 void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
1426 char s[BT_HF_DATA_BUF_SIZE] = {0, };
1427 gboolean hide = FALSE;
1429 gboolean has_clcc = FALSE;
1430 gboolean has_clip = FALSE;
1431 gboolean has_ccwa = FALSE;
1434 strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
1436 has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
1437 if (has_clcc == TRUE)
1439 has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
1440 if (has_clip == TRUE)
1442 has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
1445 /* +XSAT: 11,DISC */
1446 xsat_ptr = strstr(s, "11,DISC,");
1448 xsat_ptr = xsat_ptr + 8;
1450 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
1456 /* AT+XSAT=11,Q_CT,X,XXXX */
1457 xsat_ptr = strstr(s, "11,Q_CT,");
1459 xsat_ptr = xsat_ptr + 8;
1461 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
1462 if (x > 1) /* ignore 0 and 1 position */
1469 while (s[i] != '\0') {
1470 if (s[i] == '\r' || s[i] == '\n') {
1474 hide = hide ? FALSE : TRUE;
1475 else if ((has_clcc || has_clip || has_ccwa) && hide) {
1483 INFO("%s Buffer = %s, Length = %d ", message, s, strlen(s));
1488 static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1490 gchar indicator[BT_HF_INDICATOR_DESCR_SIZE + 4];
1494 char fmt_str[BT_HF_FMT_STR_SIZE];
1496 DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
1498 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n",
1499 (int)(sizeof(indicator) - 1));
1500 if (sscanf(buf, fmt_str, indicator) == 1) {
1501 sep = strchr(indicator, ',');
1504 index = atoi(indicator);
1506 __bt_hf_agent_handle_ind_change(bt_hf_info, index, value);
1508 if (bt_hf_info->ciev_call_status == 0 &&
1509 bt_hf_info->ciev_call_setup_status == 0)
1510 INFO("No active call");
1512 /* Request CLCC based on indicator change for call/callsetup/callHeld */
1513 __bt_hf_agent_request_call_list_info(bt_hf_info, index);
1515 DBG("--------- __bt_hf_agent_handler_ciev ------------");
1519 static void __bt_hf_agent_handle_ven_samsung(bt_hf_agent_info_t *bt_hf_info,
1520 gint app_id, const char *msg)
1522 /* Whomesoever wants need to handle it */
1523 char *sig_name = "SamsungXSAT";
1524 GDBusConnection *conn;
1526 conn = __bt_hf_get_gdbus_connection();
1528 ERR("Unable to get connection");
1532 __bt_hf_agent_emit_signal(conn,
1533 BT_HF_AGENT_OBJECT_PATH,
1534 BT_HF_SERVICE_INTERFACE,
1536 g_variant_new("(is)", app_id, msg));
1539 static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1541 DBG("++++++++ __bt_hf_agent_handler_ring ++++++++");
1542 DBG("---------__bt_hf_agent_handler_ring --------");
1547 static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1549 DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++");
1550 DBG("---------__bt_hf_agent_handler_clip --------");
1555 static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1557 DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++");
1559 if (sscanf(buf, "\r\n+BVRA:%1d\r\n", &value) == 1)
1560 __bt_hf_agent_handle_voice_activation(value);
1562 DBG("---------__bt_hf_agent_handler_bvra --------");
1566 static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1569 DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-");
1570 if (sscanf(buf, "\r\n+BCS:%3d\r\n", &codec_id))
1571 __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id);
1573 DBG("---------__bt_hf_agent_handler_bcs --------");
1577 static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1580 DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
1581 if (sscanf(buf, "\r\n+VGS:%2d\r\n", &value))
1582 __bt_hf_agent_handle_speaker_gain(value);
1584 DBG("---------__bt_hf_agent_handler_vgs --------");
1589 static int __bt_hf_agent_handler_ccwa(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1591 DBG("+++++++++ __bt_hf_agent_handler_ccwa ++++++++");
1592 __bt_hf_agent_handle_ccwa(bt_hf_info, buf);
1593 DBG("---------__bt_hf_agent_handler_ccwa --------");
1599 static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
1603 char msg[BT_HF_DATA_BUF_SIZE];
1604 char fmt_str[BT_HF_CMD_BUF_SIZE];
1606 DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
1607 snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n",
1608 (int)(sizeof(msg) - 1));
1609 if (sscanf(buf, fmt_str, &app_id, msg)) {
1610 if (app_id == 2 && strstr(msg, "READTXPOWER")) {
1611 char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, };
1612 char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr);
1613 snprintf(cmd_buf, sizeof(cmd_buf), "AT+XSAT: 2,%d", power);
1614 bt_hf_agent_send_at_cmd(NULL, cmd_buf);
1616 __bt_hf_agent_handle_ven_samsung(bt_hf_info, app_id, msg);
1620 DBG("---------__bt_hf_agent_handler_xsat --------");
1625 static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info,
1628 DBG("+++++++++ __bt_hf_agent_handler_cme_error ++++++++");
1630 GDBusConnection *conn;
1632 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1633 conn = __bt_hf_get_gdbus_connection();
1635 ERR("Unable to get connection");
1639 __bt_hf_agent_emit_signal(conn,
1640 BT_HF_AGENT_OBJECT_PATH,
1641 BT_HF_SERVICE_INTERFACE,
1646 __bt_hf_clear_prev_sent_cmd();
1651 static int __bt_hf_agent_handler_response_ok(bt_hf_agent_info_t *bt_hf_info,
1654 DBG("+++++++++ __bt_hf_agent_handler_response_ok ++++++++");
1656 __bt_hf_clear_prev_sent_cmd();
1661 static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info,
1664 DBG("+++++++++ __bt_hf_agent_handler_response_err ++++++++");
1665 GDBusConnection *conn;
1667 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1668 conn = __bt_hf_get_gdbus_connection();
1670 ERR("Unable to get connection");
1674 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1675 BT_HF_SERVICE_INTERFACE,
1679 __bt_hf_clear_prev_sent_cmd();
1684 static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info,
1688 GDBusConnection *conn;
1690 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1691 conn = __bt_hf_get_gdbus_connection();
1693 ERR("Unable to get connection");
1697 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1698 BT_HF_SERVICE_INTERFACE,
1703 __bt_hf_clear_prev_sent_cmd();
1709 static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char *buffer)
1712 GSList *call_list = NULL;
1713 DBG("+++++++++ __bt_hf_agent_handler_clcc ++++++++");
1714 DBG_SECURE("Receive CLCC response buffer = '%s'", buffer);
1716 __bt_hf_lock_display(0);
1718 call_list = __bt_hf_prepare_call_list(buffer);
1720 if (call_list == NULL)
1723 __bt_hf_launch_call_using_call_list(call_list, bt_hf_info);
1725 __bt_hf_agent_send_call_status_info(call_list);
1727 __bt_hf_free_call_list(call_list);
1730 __bt_hf_unlock_display();
1731 DBG("---------__bt_hf_agent_handler_clcc --------");
1735 static struct hf_event hf_event_callbacks[] = {
1736 { "\r\n+CIEV:", __bt_hf_agent_handler_ciev },
1737 { "\r\nRING", __bt_hf_agent_handler_ring },
1738 { "\r\n+CLIP:", __bt_hf_agent_handler_clip },
1739 { "\r\n+BVRA:", __bt_hf_agent_handler_bvra },
1740 { "\r\n+BCS:", __bt_hf_agent_handler_bcs },
1741 { "\r\n+VGS:", __bt_hf_agent_handler_vgs },
1742 { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa },
1743 { "\r\n+XSAT:", __bt_hf_agent_handler_xsat },
1744 {"\r\n+CLCC:", __bt_hf_agent_handler_clcc },
1748 static struct hf_event hf_event_resp_callbacks[] = {
1749 { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error },
1750 { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok },
1751 { "ERROR", __bt_hf_agent_handler_response_err },
1752 { "SERR", __bt_hf_agent_handler_response_serr },
1756 bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info)
1760 bt_hf_agent_send_at_info *cmd;
1761 len = g_slist_length(bt_hf_info->cmd_send_queue);
1762 for (i = 0; i < len; ++i) {
1763 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i);
1764 DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id);
1766 len = g_slist_length(bt_hf_info->cmd_send_queue);
1767 DBG("Context queue length = %d", len);
1771 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
1773 bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
1774 DBG("NEXT[%d] Found %s, context = 0x%x, pending = %d", cmd->id,
1775 cmd->at_cmd, cmd->context, cmd->pending);
1779 DBG("**** Not found any pending command on list length %d ****", len);
1784 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1786 struct hf_event *ev;
1788 bt_hf_agent_send_at_info *cmd = NULL;
1790 __bt_hf_agent_print_at_buffer("Processing [Rx cmd]:", buf);
1792 for (ev = hf_event_resp_callbacks; ev->cmd; ev++) {
1793 if (strstr(buf, ev->cmd)) {
1796 DBG("Send flag value = %d(after)", send_flag);
1797 ret = ev->callback(bt_hf_info, buf);
1804 for (ev = hf_event_callbacks; ev->cmd; ev++) {
1805 if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) {
1806 ret = ev->callback(bt_hf_info, buf);
1814 cmd = __bt_hf_agent_find_next(bt_hf_info);
1816 if (cmd && cmd->context) {
1817 DBG("Pending context found for %.6s[%d]", cmd->at_cmd, cmd->id);
1818 g_dbus_method_invocation_return_value(cmd->context, NULL);
1820 g_source_remove(cmd->timer_id);
1826 cmd = __bt_hf_agent_find_next(bt_hf_info);
1828 if (cmd && cmd->pending && send_flag == 0) {
1829 DBG("Pending only found of %.6s[%d]", cmd->at_cmd, cmd->id);
1830 __bt_hf_send_only_without_queue(bt_hf_info,
1831 cmd->at_cmd, cmd->count);
1832 cmd->pending = FALSE;
1833 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
1835 DBG("Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
1838 DBG("Pending free for %.6s[%d] - send_flag = %d",
1839 cmd->at_cmd, cmd->id, send_flag);
1841 g_source_remove(cmd->timer_id);
1847 /* Need to process further pending */
1848 cmd = __bt_hf_agent_find_next(bt_hf_info);
1850 if (cmd->pending && send_flag == 0) {
1851 DBG("2nd Pending only found of %.6s[%d]",
1852 cmd->at_cmd, cmd->id);
1853 __bt_hf_send_only_without_queue(bt_hf_info,
1854 cmd->at_cmd, cmd->count);
1855 cmd->pending = FALSE;
1857 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
1859 DBG("2nd Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
1865 static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf)
1869 int cmd_buf_len = 0;
1870 char *pos_start, *pos_end;
1871 const char *datap = buf;
1873 cmd_buf_len = strlen(cmd_buf);
1874 buf_length = strlen(buf);
1875 DBG("buf_length = %d, cmd_buf_len = %d", buf_length, cmd_buf_len);
1877 if (buf_length > 0 && strstr(datap, "+CLCC")) {
1878 pos_start = strstr(datap, "\r\n");
1879 if (pos_start == NULL) {
1880 ERR("Invalid AT command signature..\n");
1884 pos_end = g_strrstr(datap, "+CLCC");
1885 if (pos_end == NULL) {
1886 ERR("Invalid AT command signature..\n");
1889 pos_end = strstr(pos_end, "\r\n");
1890 cmd_length = (pos_end - pos_start) + 2;
1891 INFO("CLCC balance Cmd Length = %d\n", cmd_length);
1892 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
1893 cmd_buf[cmd_buf_len + cmd_length] = '\0';
1895 if (strstr(cmd_buf, "\r\nOK\r\n")) {
1896 pos_end = strstr(datap, "\r\nOK\r\n");
1897 cmd_length = (pos_end - pos_start);
1898 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
1899 cmd_buf[cmd_buf_len + cmd_length] = '\0';
1900 INFO("New CLCC balance Cmd Length = %d", cmd_length);
1907 static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1911 char *pos_start, *pos_end;
1913 gchar cmd_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1914 const char *datap = buf;
1916 __bt_hf_agent_print_at_buffer("[HF AT CMD] Recv >>>>>:", buf);
1918 buf_length = strlen(buf);
1920 while (buf_length > 0) {
1921 pos_start = strstr(datap, "\r\n");
1922 if (pos_start == NULL) {
1923 ERR("Invalid AT command start signature..\n");
1928 pos_end = strstr(datap, "\r\n");
1929 if (pos_end == NULL) {
1930 ERR("Invalid AT command end signature..\n");
1933 cmd_length = (pos_end - pos_start) + 2;
1934 DBG("Cmd Length = %d\n", cmd_length);
1936 memcpy(cmd_buf, pos_start, cmd_length);
1937 cmd_buf[cmd_length] = '\0';
1939 buf_length = buf_length - cmd_length;
1940 datap = datap + cmd_length - 2;
1942 /* We need to pass all the CLCC's together to its handler */
1943 if (strstr(cmd_buf, "+CLCC")) {
1944 tmp = hf_handle_append_clcc_buff(cmd_buf, datap);
1946 buf_length = buf_length - tmp;
1948 hf_handle_rx_at_cmd(bt_hf_info, cmd_buf);
1949 DBG("Pending buf_length = %d\n", buf_length);
1954 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
1955 bt_hf_agent_info_t *bt_hf_info)
1957 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
1959 GError *gerr = NULL;
1960 gboolean recvd_ok = FALSE;
1961 gboolean recvd_error = FALSE;
1962 gboolean recvd_sec_error = FALSE;
1964 if (cond & (G_IO_ERR | G_IO_HUP)) {
1965 ERR("ERR or HUP on RFCOMM socket");
1966 INFO_C("Disconnected [HF role] [Terminated by remote dev]");
1967 is_hf_connected = FALSE;
1968 bt_hf_info->slc = FALSE;
1969 __bt_hf_agent_release();
1973 if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, &gerr)
1974 != G_IO_STATUS_NORMAL) {
1976 ERR("Read failed, cond = [%d], Err msg = [%s]",
1977 cond, gerr->message);
1983 recvd_ok = NULL != strstr(buf, BT_HF_OK_RESPONSE);
1984 recvd_error = NULL != strstr(buf, BT_HF_ERROR_RESPONSE);
1985 recvd_sec_error = NULL != strstr(buf, BT_HF_SEC_ERROR_RESPONSE);
1986 DBG("<-------Received data --send flag status = %d ----->", send_flag);
1988 /* Once service level connection is established we need to handle
1989 * all the intermediate AT commands */
1990 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
1994 strncat(global_buff, buf,
1995 (BT_AT_COMMAND_BUFFER_MAX - 1) - strlen(global_buff));
1996 if (!(recvd_ok || recvd_error || recvd_sec_error)) {
1997 __bt_hf_agent_print_at_buffer("Concat ()", global_buff);
1999 DBG("*** Received terminator.. process Rx buffer ***");
2000 hf_handle_rx_at_buff(bt_hf_info, global_buff);
2001 memset(global_buff, 0, sizeof(global_buff));
2004 INFO("*** Received Direct AT buffer packet handling ****");
2005 hf_handle_rx_at_buff(bt_hf_info, buf);
2010 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info)
2012 bt_hf_info->watch_id = g_io_add_watch(bt_hf_info->io_chan,
2013 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2014 (GIOFunc) __bt_hf_agent_data_cb, bt_hf_info);
2017 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info)
2019 if (bt_hf_info->watch_id > 0) {
2020 g_source_remove(bt_hf_info->watch_id);
2021 bt_hf_info->watch_id = 0;
2025 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
2032 status = g_io_channel_write_chars(io, data, count, &written,
2034 if (status != G_IO_STATUS_NORMAL)
2043 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
2044 gchar *data, gsize count)
2046 GIOChannel *io_chan = bt_hf_info->io_chan;
2047 if (!__bt_hf_channel_write(io_chan, data, count))
2050 g_io_channel_flush(io_chan, NULL);
2052 if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
2053 INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
2054 count, count - 6, "ATDXXXXXXX");
2055 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
2057 INFO("No queue....Send only buffer size =[%d] - Send <<<<<| %s",
2062 /* DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2063 * send_flag, count, data); */
2068 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
2071 gboolean pending = FALSE;
2072 GIOChannel *io_chan = bt_hf_info->io_chan;
2077 __bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
2082 if (!__bt_hf_channel_write(io_chan, data, count))
2085 g_io_channel_flush(io_chan, NULL);
2087 if (count > 2 && data[2] == 'D') /* ATDXXXXX */
2088 INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
2089 count, count - 6, "ATDXXXXXXX");
2091 INFO("Send only buffer size =[%d] - Send <<<<<| %s", count, data);
2094 DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2095 send_flag, count, data);
2099 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
2100 gchar *data, gchar *response, gsize count)
2102 GIOChannel *io_chan = bt_hf_info->io_chan;
2104 gboolean recvd_ok = FALSE;
2105 gboolean recvd_error = FALSE;
2106 gboolean recvd_sec_error = FALSE;
2107 gchar *resp_buf = response;
2108 gsize toread = BT_HF_DATA_BUF_SIZE - 1;
2113 GDBusConnection *conn;
2115 /* Should not send cmds if DUT send a command and wait the response */
2116 if (prev_cmd[0] != 0) {
2117 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
2121 memset(resp_buf, 0, BT_HF_DATA_BUF_SIZE);
2123 if (!__bt_hf_channel_write(io_chan, data, count))
2126 g_io_channel_flush(io_chan, NULL);
2128 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send <<<<<:", data);
2130 fd = g_io_channel_unix_get_fd(io_chan);
2132 p.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
2134 /* Maximun 8 seconds of poll or 8 minus no of cmd received */
2135 for (i = 1; i <= MAX_WAITING_DELAY; i++) {
2136 DBG("Loop Counter = %d", i);
2138 err = poll(&p, 1, 1000);
2140 ERR("Loop Counter = %d, >>>> Poll error happen", i);
2142 } else if (err == 0) {
2143 INFO("Loop Counter = %d, >>>> Poll Timeout", i);
2146 if (p.revents & (POLLERR | POLLHUP | POLLNVAL)) {
2147 ERR("Loop Counter = %d, >> Poll ERR/HUP/INV (%d)",
2150 conn = __bt_hf_get_gdbus_connection();
2152 ERR("Unable to get connection");
2156 __bt_hf_agent_emit_signal(conn,
2157 BT_HF_AGENT_OBJECT_PATH,
2158 BT_HF_SERVICE_INTERFACE,
2160 g_variant_new("(s)",
2161 bt_hf_info->remote_addr));
2163 bt_hf_info->state = BT_HF_STATE_DISCONNECTED;
2167 if (p.revents & POLLIN) {
2168 rd_size = read(fd, resp_buf, toread);
2169 resp_buf[rd_size] = '\0';
2170 DBG_SECURE("size = %d, Buffer=[%s]", rd_size, resp_buf);
2171 recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
2172 recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
2173 recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
2175 resp_buf += rd_size;
2178 if (recvd_ok || recvd_error || recvd_sec_error) {
2179 DBG("Break Loop Counter = %d", i);
2185 /* Once service level connection is established we need to handle
2186 * all the intermediate AT commands */
2187 if (bt_hf_info->state == BT_HF_STATE_CONNECTED)
2188 hf_handle_rx_at_buff(bt_hf_info, response);
2192 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indices)
2194 struct indicator *ind;
2195 gchar *cur = names - 1;
2196 GSList *list = indices;
2199 DBG("Indicator buffer = %s", names);
2200 __bt_hf_agent_print_at_buffer("Indicator names :", names);
2201 while (cur != NULL) {
2203 next = strstr(cur, ",(");
2204 ind = g_new0(struct indicator, 1);
2205 g_strlcpy(ind->descr, cur, BT_HF_INDICATOR_DESCR_SIZE);
2206 ind->descr[(intptr_t) next - (intptr_t) cur] = '\0';
2207 list = g_slist_append(list, (gpointer) ind);
2208 cur = strstr(next + 1, ",(");
2213 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices)
2216 struct indicator *ind;
2217 GSList *runner = indices;
2219 gchar *cur = values - 1;
2220 DBG("Indicator string = %s", values);
2221 __bt_hf_agent_print_at_buffer("Indicator values :", values);
2222 while (cur != NULL) {
2224 sscanf(cur, "%1d", &val);
2225 cur = strchr(cur, ',');
2226 ind = g_slist_nth_data(runner, 0);
2228 runner = g_slist_next(runner);
2233 static guint __bt_hf_get_hold_mpty_features(gchar *features)
2237 if (strstr(features, "0"))
2238 result |= BT_HF_CHLD_0;
2240 if (strstr(features, "1"))
2241 result |= BT_HF_CHLD_1;
2243 if (strstr(features, "1x"))
2244 result |= BT_HF_CHLD_1x;
2246 if (strstr(features, "2"))
2247 result |= BT_HF_CHLD_2;
2249 if (strstr(features, "2x"))
2250 result |= BT_HF_CHLD_2x;
2252 if (strstr(features, "3"))
2253 result |= BT_HF_CHLD_3;
2255 if (strstr(features, "4"))
2256 result |= BT_HF_CHLD_4;
2261 static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2263 bt_hf_agent_info_t *bt_hf_info = user_data;
2264 GDBusConnection *conn;
2267 if (cond & G_IO_NVAL)
2270 if (cond & (G_IO_HUP | G_IO_ERR)) {
2271 g_io_channel_shutdown(chan, TRUE, NULL);
2272 close(bt_hf_info->cli_sco_fd);
2273 g_io_channel_unref(chan);
2274 DBG("Emit AudioDisconnected Signal");
2276 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2278 conn = __bt_hf_get_gdbus_connection();
2280 ERR("Unable to get connection");
2283 __bt_hf_agent_emit_signal(conn,
2284 BT_HF_AGENT_OBJECT_PATH,
2285 BT_HF_SERVICE_INTERFACE,
2286 "AudioDisconnected", NULL);
2294 static gboolean __bt_agent_query_and_update_call_list(gpointer data)
2297 bt_hf_agent_info_t *bt_hf_info = data;
2299 if (bt_hf_info->cli_sco_fd >= 0)
2300 __bt_hf_agent_handle_call_list(bt_hf_info);
2302 INFO("SCO Audio is already disconnected");
2309 static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2311 bt_hf_agent_info_t *bt_hf_info = user_data;
2315 GDBusConnection *conn;
2317 INFO("Incoming SCO....");
2319 if (cond & G_IO_NVAL)
2322 sco_skt = g_io_channel_unix_get_fd(chan);
2324 if (cond & (G_IO_HUP | G_IO_ERR)) {
2329 cli_sco_sock = accept(sco_skt, NULL, NULL);
2330 if (cli_sco_sock < 0)
2333 bt_hf_info->cli_sco_fd = cli_sco_sock;
2335 sco_io = g_io_channel_unix_new(cli_sco_sock);
2336 g_io_channel_set_close_on_unref(sco_io, TRUE);
2337 g_io_channel_set_encoding(sco_io, NULL, NULL);
2338 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2339 g_io_channel_set_buffered(sco_io, FALSE);
2341 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2342 __bt_hf_agent_sco_conn_cb, bt_hf_info);
2344 /* S-Voice app requires the AudioConnected signal earlier */
2345 DBG("Emit AudioConnected Signal");
2347 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
2349 conn = __bt_hf_get_gdbus_connection();
2351 ERR("Unable to get connection");
2355 __bt_hf_agent_emit_signal(conn,
2356 BT_HF_AGENT_OBJECT_PATH,
2357 BT_HF_SERVICE_INTERFACE,
2358 "AudioConnected", NULL);
2360 /* In the case of incoming call, the call app is already launched,
2361 * hence AudioConnected signal is enough to update the call status.
2362 * In the case of outgoing call we need to lauch the callapp.
2365 g_idle_add(__bt_agent_query_and_update_call_list, bt_hf_info);
2370 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
2371 const char *address)
2376 ret_if(address == NULL);
2377 ret_if(addr == NULL);
2379 for (i = 0; i < 6; i++) {
2380 addr[5 - i] = strtol(address, &ptr, 16);
2381 if (ptr[0] != '\0') {
2390 static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
2392 struct sockaddr_sco addr;
2394 bdaddr_t bd_addr = {{0},};
2397 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2401 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
2403 ERR("Can't create socket:\n");
2407 /* Bind to local address */
2408 memset(&addr, 0, sizeof(addr));
2409 addr.sco_family = AF_BLUETOOTH;
2411 DBG("Bind to address %s", bt_hf_info->remote_addr);
2413 _bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
2414 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2416 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2417 ERR("Can't bind socket:\n");
2421 if (listen(sco_skt, 1)) {
2422 ERR("Can not listen on the socket:\n");
2426 sco_io = g_io_channel_unix_new(sco_skt);
2427 g_io_channel_set_close_on_unref(sco_io, TRUE);
2428 g_io_channel_set_encoding(sco_io, NULL, NULL);
2429 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2430 g_io_channel_set_buffered(sco_io, FALSE);
2432 bt_hf_info->sco_fd = sco_skt;
2433 bt_hf_info->sco_io_chan = sco_io;
2435 bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
2436 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
2438 g_io_channel_unref(sco_io);
2447 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
2449 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2452 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
2453 sizeof(BT_HF_INDICATORS_SUPP) - 1);
2454 if (!ret || !strstr(buf, "+CIND:"))
2457 bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
2462 static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
2467 if (bt_hf_info == NULL || cmd == NULL) {
2468 ERR("Invalid parameter");
2472 ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
2474 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
2475 ret = g_strlcat(cmd, "0,", cmd_size);
2476 if (ret >= cmd_size) {
2477 ERR("Too many indices");
2483 cmd[ret - 1] = '\0';
2484 DBG("BIA Str : %s", cmd);
2486 ret = g_strlcat(cmd, "\r", cmd_size);
2487 if (ret >= cmd_size) {
2488 ERR("Too many indices");
2495 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
2497 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2503 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
2504 sizeof(BT_HF_INDICATORS_VAL) - 1);
2505 if (!ret || !strstr(buf, "+CIND:"))
2508 /* if buf has other command prefix, skip it */
2509 str = strstr(buf, "+CIND");
2513 bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
2515 /* Parse the updated value */
2516 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
2517 struct indicator *ind = l->data;
2519 DBG("Index is NULL");
2523 if (0 == g_strcmp0(ind->descr, "\"call\"")) {
2524 DBG("CIND Match found index = %d, %s, value = %d",
2525 index, ind->descr, ind->value);
2526 bt_hf_info->ciev_call_status = ind->value;
2527 if (ind->value > 0) {
2528 bt_hf_info->is_dialing = FALSE;
2529 bt_hf_info->call_active = TRUE;
2531 } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
2532 DBG("CIND Match found index = %d, %s, value = %d",
2533 index, ind->descr, ind->value);
2534 bt_hf_info->ciev_call_setup_status = ind->value;
2535 if (!bt_hf_info->is_dialing && ind->value > 0)
2536 bt_hf_info->is_dialing = TRUE;
2543 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
2545 gchar buf[BT_HF_DATA_BUF_SIZE];
2546 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
2549 guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
2550 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
2551 BT_HF_FEATURE_CLI_PRESENTATION |
2552 BT_HF_FEATURE_VOICE_RECOGNITION |
2553 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
2554 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
2556 #ifdef TIZEN_PROFILE_WEARABLE
2557 feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
2560 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
2561 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
2566 buf_ptr = strstr(buf, "\r\n+BRSF:");
2567 if (buf_ptr == NULL)
2570 if (!ret || sscanf(buf_ptr, "\r\n+BRSF:%5d", &bt_hf_info->ag_features) != 1)
2572 INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
2574 #ifdef TIZEN_PROFILE_WEARABLE
2575 if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
2576 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
2577 if (ret != BT_HF_AGENT_ERROR_NONE)
2578 ERR("Unable to set the default WBC codec");
2580 ret = __bt_hf_send_available_codec(bt_hf_info, 0);
2586 /* Default codec is NB */
2587 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
2588 if (ret != BT_HF_AGENT_ERROR_NONE)
2589 ERR("Unable to set the default NBC codec");
2592 ret = __bt_get_supported_indicators(bt_hf_info);
2597 ret = __bt_get_current_indicators(bt_hf_info);
2601 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
2602 sizeof(BT_HF_INDICATORS_ENABLE) - 1);
2603 if (!ret || !strstr(buf, "OK"))
2606 if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
2607 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
2608 buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
2609 if (!ret || !strstr(buf, "+CHLD:")) {
2610 ERR("Unable to get the CHLD Supported info");
2613 bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
2616 bt_hf_info->hold_multiparty_features = 0;
2618 INFO("Service layer connection successfully established...!");
2620 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
2621 sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
2622 __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
2623 sizeof(BT_HF_CARRIER_FORMAT) - 1);
2624 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
2625 sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
2627 if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
2628 __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
2629 sizeof(BT_HF_NREC) - 1);
2631 if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
2632 __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
2633 buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
2635 if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
2636 __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
2638 ERR("__bt_get_bia_cmd is failed");
2640 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
2641 sizeof(BT_HF_XSAT) - 1);
2643 DBG("sent BT_HF_XSAT");
2645 ERR("BT_HF_XSAT sending failed");
2647 /* send Bluetooth Samsung Support Feature cmd */
2648 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
2649 sizeof(BT_HF_BSSF) - 1);
2651 INFO("SLC completed with all commands");
2653 ERR("BT_HF_BSSF sending failed");
2655 bt_hf_info->slc = TRUE;
2658 memset(global_buff, 0, sizeof(global_buff));
2662 static void __bt_hf_agent_sigterm_handler(int signo)
2664 ERR_C("***** Signal handler came with signal %d *****", signo);
2665 GDBusConnection *conn;
2667 conn = __bt_hf_get_gdbus_connection();
2669 ERR("Unable to get connection");
2673 __bt_hf_agent_emit_signal(conn,
2674 BT_HF_AGENT_OBJECT_PATH,
2675 BT_HF_SERVICE_INTERFACE,
2677 DBG("CallEnded Signal done");
2679 g_main_loop_quit(gmain_loop);
2683 INFO_C("Terminating HF agent");
2688 static void __bt_convert_addr_type_to_rev_string(char *address,
2689 unsigned char *addr)
2691 ret_if(address == NULL);
2692 ret_if(addr == NULL);
2694 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
2695 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
2696 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
2700 static gboolean __bt_hf_agent_release_after(gpointer user_data)
2702 if (__bt_hf_agent_release() == FALSE)
2703 ERR("Unable to release hf connection");
2708 static gboolean __bt_agent_request_service_level_conn(gpointer data)
2711 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2712 GDBusConnection *conn;
2715 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
2717 if (!__bt_establish_service_level_conn(&bt_hf_info)) {
2718 ERR("Service Level Connection is fail");
2720 conn = __bt_hf_get_gdbus_connection();
2722 remote_addr = bt_hf_info.remote_addr;
2723 __bt_hf_agent_emit_signal(conn,
2724 BT_HF_AGENT_OBJECT_PATH,
2725 BT_HF_SERVICE_INTERFACE,
2727 g_variant_new("(s)", remote_addr));
2729 bt_hf_info.state = BT_HF_STATE_CONNECTED;
2731 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2732 DBG("BT device state is : 0x%X", bt_device_state);
2733 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2734 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2735 ERR("vconf_set_int failed");
2737 ERR("vconf_get_int failed");
2740 g_idle_add(__bt_hf_agent_release_after, NULL);
2745 bt_hf_info.state = BT_HF_STATE_CONNECTED;
2747 __bt_hf_agent_sco_accept(&bt_hf_info);
2749 __bt_hf_agent_start_watch(&bt_hf_info);
2751 remote_addr = bt_hf_info.remote_addr;
2753 INFO_SECURE("Address is : %s", remote_addr);
2754 INFO_C("Connected [HF role]");
2756 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2757 DBG("BT device state is : 0x%X", bt_device_state);
2758 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2760 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2761 ERR("vconf_set_int failed");
2763 ERR("vconf_get_int failed");
2766 conn = __bt_hf_get_gdbus_connection();
2768 ERR("Unable to get connection");
2772 __bt_hf_agent_emit_signal(conn,
2773 BT_HF_AGENT_OBJECT_PATH,
2774 BT_HF_SERVICE_INTERFACE,
2776 g_variant_new("(s)", remote_addr));
2778 /* Request the call list and launch call app if required */
2779 __bt_hf_agent_handle_call_list(&bt_hf_info);
2786 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
2790 struct sockaddr_remote address;
2791 socklen_t address_len;
2792 bt_hf_info.path = g_strdup(obj_path);
2794 INFO_C("**** New HFP connection ****");
2796 is_hf_connected = TRUE;
2798 address_len = sizeof(address);
2799 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2800 ERR("BD_ADDR is NULL");
2802 DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
2804 bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
2805 flags = g_io_channel_get_flags(bt_hf_info.io_chan);
2807 flags &= ~G_IO_FLAG_NONBLOCK;
2808 flags &= G_IO_FLAG_MASK;
2809 g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
2810 g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
2811 g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
2813 bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2814 __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
2815 address.remote_bdaddr.b);
2817 g_idle_add(__bt_agent_request_service_level_conn, NULL);
2822 static void __bt_hf_agent_indicator_free(gpointer mem)
2827 static gboolean __bt_hf_agent_release(void)
2829 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2830 GDBusConnection *conn;
2832 if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
2833 ERR("hf is already disconnected");
2837 if (bt_hf_info.indies) {
2838 g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
2839 bt_hf_info.indies = NULL;
2842 if (bt_hf_info.io_chan) {
2843 g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
2844 g_io_channel_unref(bt_hf_info.io_chan);
2845 bt_hf_info.io_chan = NULL;
2848 if (bt_hf_info.sco_watch_id > 0) {
2849 g_source_remove(bt_hf_info.sco_watch_id);
2850 bt_hf_info.sco_watch_id = 0;
2853 bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
2855 __bt_hf_agent_release_queue();
2857 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2858 DBG("BT device state is : 0x%X", bt_device_state);
2859 bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2861 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2862 ERR("vconf_set_int failed");
2864 ERR("vconf_get_int failed");
2867 __bt_hf_agent_stop_watch(&bt_hf_info);
2868 conn = __bt_hf_get_gdbus_connection();
2870 ERR("Unable to get connection");
2874 __bt_hf_agent_emit_signal(conn,
2875 BT_HF_AGENT_OBJECT_PATH,
2876 BT_HF_SERVICE_INTERFACE,
2878 g_variant_new("(s)", bt_hf_info.remote_addr));
2880 g_free(bt_hf_info.path);
2881 bt_hf_info.path = NULL;
2883 g_free(bt_hf_info.remote_addr);
2884 bt_hf_info.remote_addr = NULL;
2886 is_hf_connected = FALSE;
2891 static gboolean __bt_hf_agent_connection_release(void)
2893 return __bt_hf_agent_release();
2896 static int __bt_hf_register_profile(const char *uuid, uint16_t version,
2897 const char *name, const char *object, uint16_t features)
2902 GError *error = NULL;
2903 GVariantBuilder *builder;
2906 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
2907 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
2910 return BT_HF_AGENT_ERROR_INTERNAL;
2912 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2914 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2916 g_variant_builder_add(builder, "{sv}",
2917 "Name", g_variant_new("s",
2919 g_variant_builder_add(builder, "{sv}",
2920 "Version", g_variant_new("q", version));
2922 g_variant_builder_add(builder, "{sv}",
2923 "features", g_variant_new("q", features));
2925 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
2926 g_variant_new("(osa{sv})", path,
2927 HFP_HF_UUID, builder),
2928 G_DBUS_CALL_FLAGS_NONE, -1,
2931 g_variant_builder_unref(builder);
2934 /* dBUS-RPC is failed */
2935 ERR("dBUS-RPC is failed");
2936 if (error != NULL) {
2937 /* dBUS gives error cause */
2938 ERR("D-Bus API failure: errCode[%x], message[%s]",
2939 error->code, error->message);
2940 g_clear_error(&error);
2943 return BT_HF_AGENT_ERROR_INTERNAL;
2945 g_variant_unref(ret);
2949 return BT_HF_AGENT_ERROR_NONE;
2952 static void __bt_hf_agent_register(void)
2957 uint16_t version = hf_ver;
2958 uint16_t features = bt_hf_info.feature;
2960 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2961 name = g_strdup("Hands-Free");
2963 ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
2966 ERR("Error in register");
2975 static void __bt_hf_agent_unregister(void)
2979 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2982 __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
2983 g_variant_new("(o)", path),
2984 BLUEZ_HF_INTERFACE_NAME,
2996 static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
2997 const gchar *sender_name,
2998 const gchar *object_path,
2999 const gchar *interface_name,
3000 const gchar *signal_name,
3001 GVariant *parameters,
3007 GVariant *optional_param;
3009 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3011 g_variant_get(parameters, "(&o@a{sa{sv}})",
3012 &path, &optional_param);
3014 ERR("Invalid adapter path");
3018 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3019 g_obj_path = g_strdup(path);
3020 INFO("Adapter Path = [%s]", path);
3021 __bt_hf_agent_register();
3023 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
3024 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
3026 __bt_hf_agent_unregister();
3031 static void __bt_hf_agent_dbus_init(void)
3033 GDBusConnection *conn;
3037 conn = __bt_hf_get_gdbus_connection();
3039 ERR("Error in creating the gdbus connection\n");
3042 if (!__bt_hf_register_profile_methods()) {
3043 ERR("Error in register_profile_methods\n");
3047 owner_sig_id = g_dbus_connection_signal_subscribe(conn,
3048 NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
3049 __bt_hf_agent_filter_cb, NULL, NULL);
3054 static void __bt_hf_agent_dbus_deinit(void)
3057 if (service_gproxy) {
3058 g_object_unref(service_gproxy);
3059 service_gproxy = NULL;
3063 if (owner_sig_id != -1)
3064 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3067 g_object_unref(gdbus_conn);
3073 static int _hf_agent_answer_call(GDBusMethodInvocation *context)
3078 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3079 ERR("HF not Connected");
3080 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3082 bt_hf_info.context = context;
3084 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
3085 sizeof(BT_HF_ANSWER_CALL) - 1);
3087 return BT_HF_AGENT_ERROR_INTERNAL;
3090 return BT_HF_AGENT_ERROR_NONE;
3094 static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
3099 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3100 ERR("HF not Connected");
3101 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3104 bt_hf_info.context = context;
3106 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
3107 sizeof(BT_HF_END_CALL) - 1);
3109 return BT_HF_AGENT_ERROR_INTERNAL;
3112 return BT_HF_AGENT_ERROR_NONE;
3115 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
3118 char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
3120 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3121 ERR("HF not Connected");
3122 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3125 bt_hf_info.context = context;
3127 if (strlen(no) > 0) {
3128 snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
3130 if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
3131 && bt_hf_info.ciev_call_setup_status == 0) {
3132 INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
3133 ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
3137 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3140 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3141 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
3144 return BT_HF_AGENT_ERROR_INTERNAL;
3146 return BT_HF_AGENT_ERROR_NONE;
3149 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3150 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
3152 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
3153 sizeof(BT_HF_REDIAL) - 1);
3155 return BT_HF_AGENT_ERROR_INTERNAL;
3157 return BT_HF_AGENT_ERROR_NONE;
3160 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
3165 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3166 ERR("HF not Connected");
3167 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3170 snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
3172 bt_hf_info.context = context;
3174 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3176 return BT_HF_AGENT_ERROR_INTERNAL;
3179 return BT_HF_AGENT_ERROR_NONE;
3182 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
3187 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3188 ERR("HF not Connected");
3189 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3192 if (gain > BT_HF_MAX_SPEAKER_GAIN)
3193 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3195 snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
3197 bt_hf_info.context = context;
3199 ret = __bt_hf_send_only(&bt_hf_info, buf,
3202 return BT_HF_AGENT_ERROR_INTERNAL;
3204 return BT_HF_AGENT_ERROR_NONE;
3208 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
3213 if (strlen(dtmf) <= 0)
3214 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3216 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3217 ERR("HF not Connected");
3218 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3221 snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
3223 bt_hf_info.context = context;
3225 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3227 return BT_HF_AGENT_ERROR_INTERNAL;
3230 return BT_HF_AGENT_ERROR_NONE;
3234 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
3238 if (strlen(cmd) <= 0)
3239 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3241 bt_hf_info.context = context;
3243 ret = __bt_hf_send_only(&bt_hf_info, cmd,
3246 return BT_HF_AGENT_ERROR_INTERNAL;
3248 return BT_HF_AGENT_ERROR_NONE;
3251 static gboolean bt_hf_agent_sco_disconnect(void)
3254 GDBusConnection *conn;
3256 close(bt_hf_info.cli_sco_fd);
3257 bt_hf_info.cli_sco_fd = -1;
3259 DBG("Emit AudioDisconnected Signal");
3260 conn = __bt_hf_get_gdbus_connection();
3262 ERR("Unable to get connection");
3266 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
3268 __bt_hf_agent_emit_signal(conn,
3269 BT_HF_AGENT_OBJECT_PATH,
3270 BT_HF_SERVICE_INTERFACE,
3271 "AudioDisconnected", NULL);
3276 static GVariant *bt_hf_agent_request_call_list(void)
3278 GSList *call_list = NULL;
3282 call_list = __bt_hf_get_call_list(&bt_hf_info);
3284 INFO("call list is NULL");
3288 var_data = __bt_hf_agent_get_call_status_info(call_list);
3289 __bt_hf_free_call_list(call_list);
3295 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
3299 char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
3304 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3306 if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
3307 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3309 /* Should not send cmds if DUT has sent a command and waiting for response */
3310 if (prev_cmd[0] != 0) {
3311 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
3312 return BT_HF_AGENT_ERROR_INTERNAL;
3315 strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
3316 strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
3318 bt_hf_info.context = context;
3320 ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
3322 return BT_HF_AGENT_ERROR_INTERNAL;
3325 return BT_HF_AGENT_ERROR_NONE;
3328 static uint32_t __bt_hf_agent_get_hf_features(void)
3330 uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
3331 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
3332 BT_HF_FEATURE_CLI_PRESENTATION |
3333 BT_HF_FEATURE_VOICE_RECOGNITION |
3334 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3335 BT_HF_FEATURE_ENHANCED_CALL_STATUS |
3336 BT_HF_FEATURE_CODEC_NEGOTIATION;
3338 #ifdef TIZEN_PROFILE_WEARABLE
3339 hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
3342 hf_ver = HFP_VERSION_1_6;
3349 struct sigaction sa;
3350 uint32_t hf_features;
3352 INFO("Starting Bluetooth HF agent");
3354 hf_features = __bt_hf_agent_get_hf_features();
3355 bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
3357 memset(&sa, 0, sizeof(sa));
3358 sa.sa_flags = SA_NOCLDSTOP;
3359 sa.sa_handler = __bt_hf_agent_sigterm_handler;
3360 sigaction(SIGTERM, &sa, NULL);
3362 /* Temporarily, block the below signal for debugging */
3363 // sigaction(SIGSEGV, &sa, NULL);
3364 // sigaction(SIGABRT, &sa, NULL);
3365 gmain_loop = g_main_loop_new(NULL, FALSE);
3367 if (gmain_loop == NULL) {
3368 ERR("GMainLoop create failed\n");
3369 return EXIT_FAILURE;
3372 __bt_hf_agent_dbus_init();
3373 g_main_loop_run(gmain_loop);
3375 __bt_hf_agent_dbus_deinit();
3378 g_main_loop_unref(gmain_loop);
3380 INFO("Terminating Bluetooth HF agent");