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"
43 #include "bluetooth-agent-profile.h"
45 #define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3
46 #define CALL_APP_ID "org.tizen.call-ui"
48 #define MAX_WAITING_DELAY 8
49 #define READ_TX_POWER_MIN -30
51 #define BT_ADDRESS_STRING_SIZE 18
52 #define BT_AT_COMMAND_BUFFER_MAX 4000
53 #define BT_HF_ERROR_RESP "\r\nERROR\r\n"
54 #define BT_HF_COMMAND_TIMEOUT 3
56 #define ret_if(expr) \
59 ERR("(%s) return", #expr); \
64 static GMainLoop *gmain_loop = NULL;
65 static char *g_obj_path;
67 static GDBusConnection *gdbus_conn;
68 static GDBusProxy *service_gproxy;
69 static int owner_sig_id = -1;
73 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
74 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
76 /*Below Inrospection data is exposed to bluez from agent*/
77 static const gchar hf_agent_bluez_introspection_xml[] =
79 " <interface name='org.bluez.Profile1'>"
80 " <method name='NewConnection'>"
81 " <arg type='o' name='device' direction='in'/>"
82 " <arg type='h' name='fd' direction='in'/>"
83 " <arg type='a{sv}' name='options' direction='in'/>"
85 " <method name='RequestDisconnection'>"
86 " <arg type='o' name='device' direction='in'/>"
91 /*Below Inrospection data is exposed to application from agent*/
92 static const gchar hf_agent_introspection_xml[] =
94 " <interface name='org.tizen.HfApp'>"
95 " <method name='AnswerCall'>"
97 " <method name='TerminateCall'>"
99 " <method name='InitiateCall'>"
100 " <arg type='s' name='phoneno' direction='in'/>"
102 " <method name='VoiceRecognition'>"
103 " <arg type='i' name='status' direction='in'/>"
105 " <method name='ScoDisconnect'>"
107 " <method name='SpeakerGain'>"
108 " <arg type='u' name='gain' direction='in'/>"
110 " <method name='SendDtmf'>"
111 " <arg type='s' name='dtmf' direction='in'/>"
113 " <method name='SendAtCmd'>"
114 " <arg type='s' name='atcmd' direction='in'/>"
116 " <method name='ReleaseAndAccept'>"
118 " <method name='CallSwap'>"
120 " <method name='ReleaseAllCall'>"
122 " <method name='JoinCall'>"
124 " <method name='GetCurrentCodec'>"
125 " <arg type='i' name='codec' direction='out'/>"
127 " <method name='RequestCallList'>"
128 " <arg type='i' name='count' direction='out'/>"
129 " <arg type='a(siiii)' name='callList' direction='out'/>"
131 " <method name='GetAudioConnected'>"
132 " <arg type='i' name='status' direction='out'/>"
134 " <method name='IsHfConnected'>"
135 " <arg type='b' name='status' direction='out'/>"
140 static bt_hf_agent_info_t bt_hf_info;
141 static gboolean is_hf_connected = FALSE;
142 static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD;
143 static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
145 static char global_buff[BT_AT_COMMAND_BUFFER_MAX] = {0,};
148 static char prev_cmd[BT_HF_CMD_BUF_SIZE];
158 } hf_call_list_info_t;
160 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error);
162 static gboolean __bt_hf_agent_emit_property_changed(
163 GDBusConnection *connection,
165 const char *interface,
169 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
170 bt_hf_agent_info_t *bt_hf_info);
171 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info);
172 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info);
173 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
175 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
176 gchar *data, gsize count);
178 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
180 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
181 gchar *data, gchar *response, gsize count);
182 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indies);
183 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indies);
184 static guint __bt_hf_get_hold_mpty_features(gchar *features);
185 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info);
186 static void __bt_hf_agent_sigterm_handler(int signo);
187 static gboolean __bt_hf_agent_release(void);
189 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info);
190 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info);
191 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path);
192 static gboolean __bt_hf_agent_connection_release(void);
195 gchar descr[BT_HF_INDICATOR_DESCR_SIZE];
199 static int _hf_agent_answer_call(GDBusMethodInvocation *context);
201 static int _hf_agent_terminate_call(GDBusMethodInvocation *context);
203 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no);
205 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context,
208 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd);
210 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context,
211 unsigned int status);
213 static gboolean bt_hf_agent_sco_disconnect(void);
215 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf);
217 static GVariant *bt_hf_agent_request_call_list(void);
219 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd);
221 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf);
222 static GQuark __bt_hf_agent_error_quark(void)
226 static GQuark quark = 0;
228 quark = g_quark_from_static_string("hf-agent");
233 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error)
235 ERR("error[%d]", error);
238 case BT_HF_AGENT_ERROR_NOT_AVAILABLE:
239 return g_error_new(BT_HF_AGENT_ERROR, error,
240 BT_ERROR_NOT_AVAILABLE);
241 case BT_HF_AGENT_ERROR_NOT_CONNECTED:
242 return g_error_new(BT_HF_AGENT_ERROR, error,
243 BT_ERROR_NOT_CONNECTED);
244 case BT_HF_AGENT_ERROR_CONNECTION_FAILED:
245 return g_error_new(BT_HF_AGENT_ERROR, error,
246 BT_ERROR_NOT_CONNECTION_FAILED);
247 case BT_HF_AGENT_ERROR_BUSY:
248 return g_error_new(BT_HF_AGENT_ERROR, error,
250 case BT_HF_AGENT_ERROR_INVALID_PARAM:
251 return g_error_new(BT_HF_AGENT_ERROR, error,
252 BT_ERROR_INVALID_PARAM);
253 case BT_HF_AGENT_ERROR_ALREADY_EXIST:
254 return g_error_new(BT_HF_AGENT_ERROR, error,
255 BT_ERROR_ALREADY_EXIST);
256 case BT_HF_AGENT_ERROR_ALREADY_CONNECTED:
257 return g_error_new(BT_HF_AGENT_ERROR, error,
258 BT_ERROR_ALREADY_CONNECTED);
259 case BT_HF_AGENT_ERROR_NO_MEMORY:
260 return g_error_new(BT_HF_AGENT_ERROR, error,
262 case BT_HF_AGENT_ERROR_I_O_ERROR:
263 return g_error_new(BT_HF_AGENT_ERROR, error,
265 case BT_HF_AGENT_ERROR_APPLICATION:
266 return g_error_new(BT_HF_AGENT_ERROR, error,
267 BT_ERROR_OPERATION_NOT_AVAILABLE);
268 case BT_HF_AGENT_ERROR_NOT_ALLOWED:
269 return g_error_new(BT_HF_AGENT_ERROR, error,
270 BT_ERROR_OPERATION_NOT_ALLOWED);
271 case BT_HF_AGENT_ERROR_NOT_SUPPORTED:
272 return g_error_new(BT_HF_AGENT_ERROR, error,
273 BT_ERROR_OPERATION_NOT_SUPPORTED);
274 case BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
275 return g_error_new(BT_HF_AGENT_ERROR, error,
276 BT_ERROR_INVALID_FILE_DESCRIPTOR);
277 case BT_HF_AGENT_ERROR_INTERNAL:
279 return g_error_new(BT_HF_AGENT_ERROR, error,
284 static void __bt_hf_lock_display(int timeout)
288 ret = device_power_request_lock(POWER_LOCK_DISPLAY, timeout);
290 DBG("Lock PM state as current state!");
292 ERR("deviced error!");
295 static void __bt_hf_unlock_display()
299 ret = device_power_release_lock(POWER_LOCK_DISPLAY);
301 DBG("UnLock PM state");
303 ERR("deviced error!");
306 static void __hf_agent_method(GDBusConnection *connection,
308 const gchar *object_path,
309 const gchar *interface_name,
310 const gchar *method_name,
311 GVariant *parameters,
312 GDBusMethodInvocation *context,
317 INFO("method %s", method_name);
321 if (g_strcmp0(method_name, "NewConnection") == 0) {
325 GUnixFDList *fd_list;
326 const gchar *object_path;
329 g_variant_get(parameters, "(oha{sv})",
330 &object_path, &index, &options);
332 msg = g_dbus_method_invocation_get_message(context);
333 fd_list = g_dbus_message_get_unix_fd_list(msg);
334 if (fd_list == NULL) {
335 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
339 fd = g_unix_fd_list_get(fd_list, index, NULL);
341 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
345 DBG("FD is = [%d], Object path = [%s]", fd, object_path);
347 if (!__bt_hf_agent_connection(fd, object_path)) {
348 ret = BT_HF_AGENT_ERROR_INTERNAL;
352 g_dbus_method_invocation_return_value(context, NULL);
353 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
354 if (!__bt_hf_agent_connection_release()) {
355 ret = BT_HF_AGENT_ERROR_INTERNAL;
358 INFO_C("Disconnected [HF role] [Terminated by local host]");
359 g_dbus_method_invocation_return_value(context, NULL);
360 } else if (g_strcmp0(method_name, "Release") == 0) {
361 if (!__bt_hf_agent_connection_release()) {
362 ret = BT_HF_AGENT_ERROR_INTERNAL;
366 g_dbus_method_invocation_return_value(context, NULL);
367 } else if (g_strcmp0(method_name, "AnswerCall") == 0) {
368 DBG("Going to call AnswerCall");
369 ret = _hf_agent_answer_call(context);
373 } else if (g_strcmp0(method_name, "TerminateCall") == 0) {
374 DBG("Going to call TerminateCall");
375 ret = _hf_agent_terminate_call(context);
379 } else if (g_strcmp0(method_name, "InitiateCall") == 0) {
380 char *phoneno = NULL;
382 g_variant_get(parameters, "(&s)", &phoneno);
384 DBG_SECURE("Going to call InitiateCall, Number is = [%s]\n", phoneno);
385 ret = _hf_agent_dial_no(NULL, phoneno);
389 g_dbus_method_invocation_return_value(context, NULL);
391 } else if (g_strcmp0(method_name, "VoiceRecognition") == 0) {
394 g_variant_get(parameters, "(i)", &status);
396 DBG("Going to call VoiceRecognition, Status [%d]", status);
397 ret = _hf_agent_voice_recognition(context, status);
401 } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) {
402 DBG("Going to call ScoDisconnect");
403 if (!bt_hf_agent_sco_disconnect()) {
404 ret = BT_HF_AGENT_ERROR_INTERNAL;
408 g_dbus_method_invocation_return_value(context, NULL);
409 } else if (g_strcmp0(method_name, "SpeakerGain") == 0) {
410 unsigned int gain = 0;
412 g_variant_get(parameters, "(u)", &gain);
414 DBG("Going to call SpeakerGain, gain is = [%d]\n", gain);
415 ret = _hf_agent_set_speaker_gain(context, gain);
419 } else if (g_strcmp0(method_name, "SendDtmf") == 0) {
422 g_variant_get(parameters, "(&s)", &dtmf);
424 DBG("Going to call SendDtmf, dtmf is = [%s]\n", dtmf);
425 ret = _hf_agent_send_dtmf(NULL, dtmf);
428 g_dbus_method_invocation_return_value(context, NULL);
430 } else if (g_strcmp0(method_name, "SendAtCmd") == 0) {
433 g_variant_get(parameters, "(&s)", &cmd);
435 DBG("Going to call SendAtCmd, cmd is = [%s]\n", cmd);
436 ret = bt_hf_agent_send_at_cmd(context, cmd);
440 } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) {
441 DBG("Going to call ReleaseAndAccept");
442 ret = _hf_agent_send_3way_cmd(context,
443 BT_HF_RELEASE_AND_ACCEPT);
447 } else if (g_strcmp0(method_name, "CallSwap") == 0) {
448 DBG("Going to call CallSwap");
449 ret = _hf_agent_send_3way_cmd(context,
450 BT_HF_ACCEPT_AND_HOLD);
454 } else if (g_strcmp0(method_name, "ReleaseAllCall") == 0) {
455 DBG("Going to call ReleaseAllCall");
456 ret = _hf_agent_send_3way_cmd(context, BT_HF_RELEASE_ALL);
460 } else if (g_strcmp0(method_name, "JoinCall") == 0) {
461 DBG("Going to call JoinCall");
462 ret = _hf_agent_send_3way_cmd(context, BT_HF_JOIN_CALL);
466 } else if (g_strcmp0(method_name, "GetCurrentCodec") == 0) {
467 DBG("Going to call GetCurrentCodec");
468 INFO("Current codec : %d", current_codec_id);
469 g_dbus_method_invocation_return_value(context,
470 g_variant_new("(i)", current_codec_id));
471 } else if (g_strcmp0(method_name, "RequestCallList") == 0) {
474 DBG("Going to call RequestCallList");
475 call_var = bt_hf_agent_request_call_list();
477 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
480 g_dbus_method_invocation_return_value(context, call_var);
481 } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) {
482 DBG("Going to call GetAudioConnected");
483 g_dbus_method_invocation_return_value(context,
484 g_variant_new("(i)", sco_audio_connected));
485 } else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
486 DBG("Going to call IsHfConnected");
487 INFO("is_hf_connected : %s", is_hf_connected ? "Connected" : "Disconnected");
489 g_dbus_method_invocation_return_value(context,
490 g_variant_new("(b)", is_hf_connected));
496 err = __bt_hf_agent_set_error(ret);
497 g_dbus_method_invocation_return_gerror(context, err);
502 static const GDBusInterfaceVTable method_table = {
508 static GDBusNodeInfo *__bt_hf_create_method_node_info
509 (const gchar *introspection_data)
511 if (introspection_data == NULL)
514 return g_dbus_node_info_new_for_xml(introspection_data, NULL);
517 static GDBusConnection *__bt_hf_get_gdbus_connection(void)
519 GDBusConnection *local_system_gconn = NULL;
522 if (gdbus_conn == NULL) {
523 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
526 ERR("Unable to connect to dbus: %s", err->message);
531 } else if (g_dbus_connection_is_closed(gdbus_conn)) {
532 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
534 if (!local_system_gconn) {
535 ERR("Unable to connect to dbus: %s", err->message);
539 gdbus_conn = local_system_gconn;
545 static gboolean __bt_hf_register_profile_methods(void)
548 GError *error = NULL;
551 GDBusNodeInfo *node_info;
553 GDBusConnection *conn;
555 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
557 G_BUS_NAME_OWNER_FLAGS_NONE,
561 DBG("owner_id is [%d]", owner_id);
563 node_info = __bt_hf_create_method_node_info(
564 hf_agent_bluez_introspection_xml);
565 if (node_info == NULL)
568 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
569 DBG("path is [%s]", path);
571 conn = __bt_hf_get_gdbus_connection();
573 ERR("Unable to get connection");
578 object_id = g_dbus_connection_register_object(conn, path,
579 node_info->interfaces[0],
582 if (object_id == 0) {
583 ERR("Failed to register: %s", error->message);
585 g_dbus_node_info_unref(node_info);
590 g_dbus_node_info_unref(node_info);
592 node_info = __bt_hf_create_method_node_info(hf_agent_introspection_xml);
593 if (node_info == NULL)
596 path = g_strdup(BT_HF_AGENT_OBJECT_PATH);
597 DBG("path is [%s]", path);
599 object_id = g_dbus_connection_register_object(conn, path,
600 node_info->interfaces[0],
603 if (object_id == 0) {
605 ERR("Failed to register: %s", error->message);
608 g_dbus_node_info_unref(node_info);
613 g_dbus_node_info_unref(node_info);
619 static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service,
620 const gchar *path, const gchar *interface)
626 GDBusConnection *conn;
628 conn = __bt_hf_get_gdbus_connection();
630 ERR("Unable to get connection");
634 proxy = g_dbus_proxy_new_sync(conn,
635 G_DBUS_PROXY_FLAGS_NONE, NULL,
637 interface, NULL, &err);
641 ERR("Unable to create proxy: %s", err->message);
651 static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service,
652 const gchar *path, const gchar *interface)
654 return (service_gproxy) ? service_gproxy :
655 __bt_hf_gdbus_init_service_proxy(service,
659 static char __bt_hf_agent_get_tx_power(char *address)
663 GError *error = NULL;
664 char result = READ_TX_POWER_MIN; /* default minimum */
666 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, g_obj_path,
667 BLUEZ_HF_INTERFACE_NAME);
669 ERR("Proxy is NULL");
673 ret = g_dbus_proxy_call_sync(proxy,
674 "GetTxPowerLevel", g_variant_new("(s)", address),
675 G_DBUS_CALL_FLAGS_NONE, -1,
678 ERR("DBus is failed");
680 /* Dbus gives error cause */
681 ERR("D-Bus API failure: errCode[%x], message[%s]",
682 error->code, error->message);
683 g_clear_error(&error);
687 g_variant_get(ret, "(y)", &result);
688 DBG("TX power level = %d", result);
689 g_variant_unref(ret);
693 static int __bt_hf_agent_gdbus_method_send(const char *service,
694 GVariant *path, const char *interface,
701 GError *error = NULL;
703 proxy = __bt_hf_gdbus_get_service_proxy(service, g_obj_path, interface);
705 return BT_HF_AGENT_ERROR_INTERNAL;
707 ret = g_dbus_proxy_call_sync(proxy,
709 G_DBUS_CALL_FLAGS_NONE, -1,
712 /* dBUS-RPC is failed */
713 ERR("dBUS-RPC is failed");
715 /* dBUS gives error cause */
716 ERR("D-Bus API failure: errCode[%x], message[%s]",
717 error->code, error->message);
719 g_clear_error(&error);
721 return BT_HF_AGENT_ERROR_INTERNAL;
724 g_variant_unref(ret);
726 return BT_HF_AGENT_ERROR_NONE;
729 static void __bt_hf_agent_release_queue(void)
732 bt_hf_agent_send_at_info *cmd;
735 len = g_slist_length(bt_hf_info.cmd_send_queue);
736 for (i = 0; i < len; ++i) {
737 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
738 if (cmd && cmd->context) {
739 DBG("Pending context found for %.6s[%d]",
740 cmd->at_cmd, cmd->id);
741 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_INTERNAL);
742 g_dbus_method_invocation_return_gerror(cmd->context, err);
745 if (cmd && cmd->timer_id)
746 g_source_remove(cmd->timer_id);
748 g_slist_free(bt_hf_info.cmd_send_queue);
749 bt_hf_info.cmd_send_queue = NULL;
753 static gboolean __bt_hf_monitor_timer_cb(gpointer data)
756 bt_hf_agent_send_at_info *cmd = data;
757 ERR_C("Monitor timer came becuase of timeout for sendflag %d, %s",
758 send_flag, cmd->at_cmd);
759 /* In the case of ATD, we have to inform the remote to end the call */
760 if (strstr(cmd->at_cmd, "ATD") || strstr(cmd->at_cmd, "BLDN")) {
761 INFO_C("Sending CHUP for remote call termination");
762 __bt_hf_send_only_without_queue(&bt_hf_info, BT_HF_END_CALL,
763 strlen(BT_HF_END_CALL));
764 /* Here there is a high posisbility that we do not get response
765 * for CHUP. Hence we need to decrement send_flag to process further
766 * incomming packets because we already incremented it in the CHUP case. */
770 /* In the case of ATD, prev_cmd will be always ATD, because we will not
771 * allow further commands. For safer side again set prev_cmd as ATD */
772 strncpy(prev_cmd, "ATD\0", BT_HF_CMD_BUF_SIZE - 1);
774 hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
782 gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
783 int count, gboolean pending_flag)
786 if (bt_hf_info.slc == FALSE)
790 DBG("*** Add Pending queue request for = %s **** ", at);
792 DBG("Add Pending queue respnse for = %s ", at);
794 bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
796 memcpy(cmd->at_cmd, at, count);
798 cmd->context = context;
799 cmd->pending = pending_flag;
800 bt_hf_info.cmd_send_queue = g_slist_append(bt_hf_info.cmd_send_queue,
802 len = g_slist_length(bt_hf_info.cmd_send_queue);
803 for (i = 0; i < len; ++i) {
804 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
805 DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id);
808 /* We need to have base timeout + tolerance value to process other request */
809 if (strstr(at, "ATD") || strstr(at, "BLDN")) {
810 /* Android 15 seconds timeout in case of ATD timeout in flight mode */
811 cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len,
812 __bt_hf_monitor_timer_cb, cmd);
814 cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len,
815 __bt_hf_monitor_timer_cb, cmd);
821 Below methods exposed to Applicatoins
823 static gboolean __bt_hf_agent_emit_signal(GDBusConnection *connection,
824 const char *path, const char *interface,
825 const char *signal_name, GVariant *param)
827 GError *error = NULL;
829 ret = g_dbus_connection_emit_signal(connection,
831 interface, signal_name,
835 /* dBUS gives error cause */
836 ERR("D-Bus API failure: errCode[%x], message[%s]",
837 error->code, error->message);
838 g_clear_error(&error);
841 INFO_C("Emit Signal [%s]", signal_name);
846 static gboolean __bt_hf_agent_emit_property_changed(
847 GDBusConnection *connection,
849 const char *interface,
855 GError *error = NULL;
857 ret = g_dbus_connection_emit_signal(connection,
858 NULL, path, interface,
860 g_variant_new("s(v)", name, property),
864 /* dBUS gives error cause */
865 ERR("D-Bus API failure: errCode[%x], message[%s]",
866 error->code, error->message);
867 g_clear_error(&error);
875 Below methods exposed to Bluez
878 static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
879 guint index, gint value)
881 GDBusConnection *conn;
883 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
885 ERR("Indicator is NULL");
892 conn = __bt_hf_get_gdbus_connection();
894 ERR("Unable to get connection");
898 INFO("Indicator name is %s, value = [%d]", name, value);
899 if (!strcmp(name, "\"call\"")) {
900 bt_hf_info->ciev_call_status = value;
902 __bt_hf_agent_emit_signal(conn,
903 BT_HF_AGENT_OBJECT_PATH,
904 BT_HF_SERVICE_INTERFACE,
905 "CallStarted", NULL);
906 bt_hf_info->is_dialing = FALSE;
907 bt_hf_info->call_active = TRUE;
908 } else if (bt_hf_info->call_active) {
909 __bt_hf_agent_emit_signal(conn,
910 BT_HF_AGENT_OBJECT_PATH,
911 BT_HF_SERVICE_INTERFACE,
913 bt_hf_info->call_active = FALSE;
916 } else if (!strcmp(name, "\"callsetup\"")) {
917 bt_hf_info->ciev_call_setup_status = value;
918 if (value == 0 && bt_hf_info->is_dialing) {
919 __bt_hf_agent_emit_signal(conn,
920 BT_HF_AGENT_OBJECT_PATH,
921 BT_HF_SERVICE_INTERFACE,
924 bt_hf_info->is_dialing = FALSE;
925 } else if (!bt_hf_info->is_dialing && value > 0)
926 bt_hf_info->is_dialing = TRUE;
928 if (bt_hf_info->ciev_call_status == 0 &&
929 bt_hf_info->ciev_call_setup_status == 0)
930 __bt_hf_agent_emit_signal(gdbus_conn,
931 BT_HF_AGENT_OBJECT_PATH,
932 BT_HF_SERVICE_INTERFACE,
935 } else if (!strcmp(name, "\"callheld\"")) {
936 if (value == 0) { /* No calls held*/
937 __bt_hf_agent_emit_signal(conn,
938 BT_HF_AGENT_OBJECT_PATH,
939 BT_HF_SERVICE_INTERFACE,
942 } else if (value == 1) {
943 /*Call is placed on hold or active/held calls swapped */
944 __bt_hf_agent_emit_signal(conn,
945 BT_HF_AGENT_OBJECT_PATH,
946 BT_HF_SERVICE_INTERFACE,
947 "CallsSwapped", NULL);
948 bt_hf_info->is_dialing = FALSE;
950 /*Call on hold, no active call*/
951 __bt_hf_agent_emit_signal(conn,
952 BT_HF_AGENT_OBJECT_PATH,
953 BT_HF_SERVICE_INTERFACE,
955 bt_hf_info->is_dialing = FALSE;
957 } else if (!strcmp(name, "\"service\""))
958 __bt_hf_agent_emit_property_changed(conn,
959 BT_HF_AGENT_OBJECT_PATH,
960 BT_HF_SERVICE_INTERFACE,
961 "RegistrationStatus",
962 g_variant_new("(q)", value));
963 else if (!strcmp(name, "\"signal\""))
964 __bt_hf_agent_emit_property_changed(conn,
965 BT_HF_AGENT_OBJECT_PATH,
966 BT_HF_SERVICE_INTERFACE, "SignalStrength",
967 g_variant_new("(q)", value));
968 else if (!strcmp(name, "\"roam\""))
969 __bt_hf_agent_emit_property_changed(conn,
970 BT_HF_AGENT_OBJECT_PATH,
971 BT_HF_SERVICE_INTERFACE, "RoamingStatus",
972 g_variant_new("(q)", value));
973 else if (!strcmp(name, "\"battchg\""))
974 __bt_hf_agent_emit_property_changed(conn,
975 BT_HF_AGENT_OBJECT_PATH,
976 BT_HF_SERVICE_INTERFACE, "BatteryCharge",
977 g_variant_new("(q)", value));
981 static gboolean __bt_hf_agent_launch_call_app(const char *launch_type,
988 app_manager_is_running(CALL_APP_ID, &is_running);
992 DBG_SECURE("Launch type = %s, number(%s)", launch_type, number);
996 ERR("bundle_create() Failed");
1000 bundle_add(b, "launch-type", launch_type);
1002 if (strlen(number) != 0)
1003 bundle_add(b, "number", number);
1005 bundle_add(b, "carrier-type", "BT");
1006 DBG("For 3G, carrier-type: BT has been added");
1008 aul_launch_app(CALL_APP_ID, b);
1016 static void __bt_hf_agent_handle_voice_activation(gint value)
1018 GDBusConnection *conn;
1020 conn = __bt_hf_get_gdbus_connection();
1022 ERR("Unable to get connection");
1026 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1027 BT_HF_SERVICE_INTERFACE,
1029 g_variant_new("(i)", value));
1034 static void __bt_hf_agent_handle_speaker_gain(gint value)
1036 GDBusConnection *conn;
1038 conn = __bt_hf_get_gdbus_connection();
1040 ERR("Unable to get connection");
1044 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1045 BT_HF_SERVICE_INTERFACE, "VolumeSpeaker",
1046 g_variant_new("(i)", value));
1051 static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info,
1054 GDBusConnection *conn;
1059 char fmt_str[BT_HF_FMT_STR_SIZE];
1060 int len = strlen(buf);
1062 DBG("__bt_hf_agent_handle_ccwa +");
1063 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1064 ERR("buf len %d is too long", len);
1068 if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
1069 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds",
1070 BT_HF_CALLER_NUM_SIZE - 1);
1071 if ((ptr = strstr(ccwa, "\"")) != NULL) {
1073 sep = strchr(number, '"');
1078 conn = __bt_hf_get_gdbus_connection();
1080 ERR("Unable to get connection");
1084 __bt_hf_agent_emit_signal(conn,
1085 BT_HF_AGENT_OBJECT_PATH,
1086 BT_HF_SERVICE_INTERFACE, "CallWaiting",
1087 g_variant_new("(s)", ccwa));
1089 ERR_SECURE("CCWA '%s' is Call Wating", buf);
1093 DBG("__bt_hf_agent_handle_ccwa -");
1097 static GSList *__bt_hf_prepare_call_list(const char *buf)
1099 GSList *call_list = NULL;
1105 char delim_sep[] = "\r\n";
1106 char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1108 hf_call_list_info_t *call_info;
1111 strncpy(temp_buf, buf, BT_HF_DATA_BUF_SIZE - 1);
1113 str = strtok_r(temp_buf, delim_sep, &sp);
1114 while (str != NULL) {
1115 if (!(strstr(str, "+CLCC:"))) {
1116 str = strtok_r(NULL, delim_sep, &sp);
1120 call_info = g_new0(hf_call_list_info_t, 1);
1122 /* str format : "+CLCC: %1d,%1d, %1d, %1d, %1d" */
1123 if ((ptr = strchr(str, ':')) != NULL) {
1124 call_info->idx = strtol(ptr + 1, &stop, 10);
1125 call_info->dir = strtol(stop + 1, &stop, 10);
1126 call_info->status = strtol(stop + 1, &stop, 10);
1127 call_info->mode = strtol(stop + 1, &stop, 10);
1128 call_info->multi_party = strtol(stop + 1, &stop, 10);
1130 DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n",
1131 call_info->idx, call_info->dir, call_info->status,
1132 call_info->mode, call_info->multi_party);
1135 ptr = strstr(str, "\"");
1137 temp = strstr(ptr + 1, "\"");
1140 DBG_SECURE("\tPhone Number = [%s]\n", ptr + 1);
1141 call_info->number = g_strdup(ptr + 1);
1143 if (strstr(temp + 1, ",")) {
1145 DBG("\tType = [%s]\n", temp);
1146 call_info->type = atoi(temp);
1150 /*In case of no phone no. in CLCC respnse, we should launch call application
1151 * with NULL string. By doing so "unknown" shall be displayed*/
1152 DBG("Phone number does not exist\n");
1153 call_info->number = g_strdup("");
1156 call_list = g_slist_append(call_list, call_info);
1157 str = strtok_r(NULL, delim_sep, &sp);
1163 static GSList *__bt_hf_get_call_list(bt_hf_agent_info_t *bt_hf_info)
1165 char buf[BT_HF_DATA_BUF_SIZE] = {0,};
1166 GSList *call_list = NULL;
1170 /* Send CLCC when the callsetup */
1171 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLLIST, buf,
1172 sizeof(BT_HF_CALLLIST) - 1);
1173 DBG_SECURE("Receive CLCC response buffer = '%s'", buf);
1175 call_list = __bt_hf_prepare_call_list(buf);
1180 static void __bt_hf_call_info_free(void *data)
1184 hf_call_list_info_t *call_info = data;
1185 g_free(call_info->number);
1191 static void __bt_hf_free_call_list(GSList *call_list)
1195 g_slist_free_full(call_list, __bt_hf_call_info_free);
1200 static void __bt_hf_launch_call_using_call_list(GSList *call_list,
1201 bt_hf_agent_info_t *bt_hf_info)
1204 const char *launch_type_str;
1205 hf_call_list_info_t *call_info;
1208 if (call_list == NULL)
1211 len = g_slist_length(call_list);
1214 call_info = g_slist_nth_data(call_list, len);
1216 /* Launch based on below conditions
1217 * DC - Active call which is initiated from H
1218 * MR - Alerting call which is initiated from H
1219 * MT - Incoming call */
1220 if (call_info->status == BT_HF_CALL_STAT_ACTIVE) {
1221 launch_type_str = "DC";
1223 if (call_info->dir == BT_HF_CALL_DIR_INCOMING)
1224 launch_type_str = "MT";
1226 launch_type_str = "MR";
1229 if (__bt_hf_agent_launch_call_app(launch_type_str,
1230 call_info->number) == FALSE)
1231 DBG("call app launching failed");
1236 static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list)
1242 hf_call_list_info_t *call_info;
1244 GVariantBuilder *builder;
1247 builder = g_variant_builder_new(G_VARIANT_TYPE("a(siiii)"));
1249 call_count = g_slist_length(call_list);
1250 DBG("Total call count = '%d'", call_count);
1252 while (call_count--) {
1253 call_info = g_slist_nth_data(call_list, call_count);
1254 INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d",
1255 call_info->idx, call_info->dir, call_info->status,
1256 call_info->mode, call_info->multi_party);
1257 caller = call_info->number;
1259 g_variant_builder_add(builder, "(siiii)",
1260 caller, call_info->dir, call_info->status,
1261 call_info->multi_party, call_info->idx);
1263 var_data = g_variant_new("(ia(siiii))",
1264 g_slist_length(call_list), builder);
1266 g_variant_builder_unref(builder);
1271 static void __bt_hf_clear_prev_sent_cmd(void)
1273 if (prev_cmd[0] != 0)
1274 ERR("No sent command");
1276 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
1281 static void __bt_hf_agent_send_call_status_info(GSList *call_list)
1283 GDBusConnection *conn;
1286 var_data = __bt_hf_agent_get_call_status_info(call_list);
1287 conn = __bt_hf_get_gdbus_connection();
1289 ERR("Unable to get connection");
1294 __bt_hf_agent_emit_signal(conn,
1295 BT_HF_AGENT_OBJECT_PATH,
1296 BT_HF_SERVICE_INTERFACE,
1301 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info)
1305 __bt_hf_lock_display(0);
1307 bt_hf_info->context = NULL;
1309 /* Send CLCC. The response will be handled in the handler */
1310 ret = __bt_hf_send_only(bt_hf_info, BT_HF_CALLLIST,
1311 sizeof(BT_HF_CALLLIST) - 1);
1313 ERR("Failed to send CLCC");
1315 __bt_hf_unlock_display();
1318 static void __bt_hf_agent_request_call_list_info(bt_hf_agent_info_t *bt_hf_info,
1322 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
1324 ERR("Indicator is NULL");
1328 DBG("name : %s", name);
1330 if ((strcmp(name, "\"callsetup\"") != 0) &&
1331 (strcmp(name, "\"call\"") != 0) &&
1332 (strcmp(name, "\"callheld\"") != 0))
1335 __bt_hf_lock_display(0);
1337 __bt_hf_agent_handle_call_list(bt_hf_info);
1339 __bt_hf_unlock_display();
1343 static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only)
1345 gchar buf[BT_HF_DATA_BUF_SIZE];
1346 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1349 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_AVAILABLE_CODEC,
1350 BT_HF_CODEC_ID_CVSD, BT_HF_CODEC_ID_MSBC);
1352 bt_hf_info->context = NULL;
1354 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1357 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
1360 if (!ret || !strstr(buf, "OK"))
1366 static int _hf_agent_codec_setup(const char *addr, guint codec_id)
1371 ERR("g_obj_path is NULL\n");
1372 return BT_HF_AGENT_ERROR_INTERNAL;
1376 case BT_HF_CODEC_ID_CVSD:
1377 INFO("Set NB parameters");
1378 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1379 g_variant_new("(ss)", "Handsfree", addr),
1380 BT_ADAPTER_INTERFACE,
1383 case BT_HF_CODEC_ID_MSBC:
1384 INFO("Set WBS parameters");
1385 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1386 g_variant_new("(ss)", "Handsfree", addr),
1387 BT_ADAPTER_INTERFACE,
1388 "SetWbsParameters");
1391 ret = BT_HF_AGENT_ERROR_INTERNAL;
1392 ERR("Invalid Codec\n");
1397 ERR("Failed to setup the Codec\n");
1399 current_codec_id = codec_id;
1404 static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info,
1407 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1410 if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) {
1411 INFO("Codec id doesn't match, so send available codec again");
1412 ret = __bt_hf_send_available_codec(bt_hf_info, 1);
1414 ERR("Failed to send avalable codec");
1418 /* HF should be ready accpet SCO connection before sending theresponse for
1419 "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */
1420 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id);
1422 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id);
1424 bt_hf_info->context = NULL;
1426 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1428 ERR("Failed to select the Codec");
1431 void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
1435 char s[BT_HF_DATA_BUF_SIZE] = {0, };
1436 gboolean hide = FALSE;
1438 gboolean has_clcc = FALSE;
1439 gboolean has_clip = FALSE;
1440 gboolean has_ccwa = FALSE;
1443 strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
1445 has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
1446 if (has_clcc == TRUE)
1448 has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
1449 if (has_clip == TRUE)
1451 has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
1454 /* +XSAT: 11,DISC */
1455 xsat_ptr = strstr(s, "11,DISC,");
1457 xsat_ptr = xsat_ptr + 8;
1459 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
1465 /* AT+XSAT=11,Q_CT,X,XXXX */
1466 xsat_ptr = strstr(s, "11,Q_CT,");
1468 xsat_ptr = xsat_ptr + 8;
1470 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
1471 if (x > 1) /* ignore 0 and 1 position */
1478 while (s[i] != '\0') {
1479 if (s[i] == '\r' || s[i] == '\n') {
1483 hide = hide ? FALSE : TRUE;
1484 else if ((has_clcc || has_clip || has_ccwa) && hide) {
1492 INFO("%s Buffer = %s, Length = %d ", message, s, strlen(s));
1497 static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1504 char fmt_str[BT_HF_FMT_STR_SIZE];
1506 DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
1508 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n",
1509 BT_HF_INDICATOR_DESCR_SIZE + 4 - 1);
1510 if ((ptr = strchr(buf, ':')) != NULL) {
1511 indicator = ptr + 1;
1512 sep = strchr(indicator, ',');
1515 index = atoi(indicator);
1517 __bt_hf_agent_handle_ind_change(bt_hf_info, index, value);
1519 if (bt_hf_info->ciev_call_status == 0 &&
1520 bt_hf_info->ciev_call_setup_status == 0)
1521 INFO("No active call");
1523 /* Request CLCC based on indicator change for call/callsetup/callHeld */
1524 __bt_hf_agent_request_call_list_info(bt_hf_info, index);
1526 DBG("--------- __bt_hf_agent_handler_ciev ------------");
1530 static void __bt_hf_agent_handle_ven_samsung(bt_hf_agent_info_t *bt_hf_info,
1531 gint app_id, const char *msg)
1533 /* Whomesoever wants need to handle it */
1534 char *sig_name = "SamsungXSAT";
1535 GDBusConnection *conn;
1537 conn = __bt_hf_get_gdbus_connection();
1539 ERR("Unable to get connection");
1543 __bt_hf_agent_emit_signal(conn,
1544 BT_HF_AGENT_OBJECT_PATH,
1545 BT_HF_SERVICE_INTERFACE,
1547 g_variant_new("(is)", app_id, msg));
1550 static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1552 DBG("++++++++ __bt_hf_agent_handler_ring ++++++++");
1553 DBG("---------__bt_hf_agent_handler_ring --------");
1558 static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1560 DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++");
1561 DBG("---------__bt_hf_agent_handler_clip --------");
1566 static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1568 DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++");
1572 if ((ptr = strstr(buf, "BVRA:")) != NULL) {
1573 value = strtol(ptr + 5, &stop, 10);
1574 __bt_hf_agent_handle_voice_activation(value);
1577 DBG("---------__bt_hf_agent_handler_bvra --------");
1581 static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1586 DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-");
1587 if ((ptr = strstr(buf, "BCS:")) != NULL) {
1588 codec_id = strtol(ptr + 4, &stop, 10);
1589 __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id);
1592 DBG("---------__bt_hf_agent_handler_bcs --------");
1596 static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1601 DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
1602 if ((ptr = strstr(buf, "VGS:")) != NULL) {
1603 value = strtol(ptr + 4, &stop, 10);
1604 __bt_hf_agent_handle_speaker_gain(value);
1607 DBG("---------__bt_hf_agent_handler_vgs --------");
1612 static int __bt_hf_agent_handler_ccwa(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1614 DBG("+++++++++ __bt_hf_agent_handler_ccwa ++++++++");
1615 __bt_hf_agent_handle_ccwa(bt_hf_info, buf);
1616 DBG("---------__bt_hf_agent_handler_ccwa --------");
1622 static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
1627 char fmt_str[BT_HF_CMD_BUF_SIZE];
1629 char *save_ptr = NULL;
1632 DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
1633 snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n",
1634 (int)(sizeof(msg) - 1));
1635 ptr = strstr(buf, "XSAT:");
1637 app_id = strtol(ptr + 5, &stop, 10);
1640 msg = strtok_r(stop + 1, "\\", &save_ptr);
1642 if (app_id || msg) {
1643 if (app_id == 2 && strstr(msg, "READTXPOWER")) {
1644 char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, };
1645 char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr);
1646 snprintf(cmd_buf, sizeof(cmd_buf), "AT+XSAT: 2,%d", power);
1647 bt_hf_agent_send_at_cmd(NULL, cmd_buf);
1649 __bt_hf_agent_handle_ven_samsung(bt_hf_info, app_id, msg);
1653 DBG("---------__bt_hf_agent_handler_xsat --------");
1658 static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info,
1661 DBG("+++++++++ __bt_hf_agent_handler_cme_error ++++++++");
1663 GDBusConnection *conn;
1665 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1666 conn = __bt_hf_get_gdbus_connection();
1668 ERR("Unable to get connection");
1672 __bt_hf_agent_emit_signal(conn,
1673 BT_HF_AGENT_OBJECT_PATH,
1674 BT_HF_SERVICE_INTERFACE,
1679 __bt_hf_clear_prev_sent_cmd();
1684 static int __bt_hf_agent_handler_response_ok(bt_hf_agent_info_t *bt_hf_info,
1687 DBG("+++++++++ __bt_hf_agent_handler_response_ok ++++++++");
1689 __bt_hf_clear_prev_sent_cmd();
1694 static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info,
1697 DBG("+++++++++ __bt_hf_agent_handler_response_err ++++++++");
1698 GDBusConnection *conn;
1700 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1701 conn = __bt_hf_get_gdbus_connection();
1703 ERR("Unable to get connection");
1707 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1708 BT_HF_SERVICE_INTERFACE,
1712 __bt_hf_clear_prev_sent_cmd();
1717 static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info,
1721 GDBusConnection *conn;
1723 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1724 conn = __bt_hf_get_gdbus_connection();
1726 ERR("Unable to get connection");
1730 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1731 BT_HF_SERVICE_INTERFACE,
1736 __bt_hf_clear_prev_sent_cmd();
1742 static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char *buffer)
1745 GSList *call_list = NULL;
1746 DBG("+++++++++ __bt_hf_agent_handler_clcc ++++++++");
1747 DBG_SECURE("Receive CLCC response buffer = '%s'", buffer);
1749 __bt_hf_lock_display(0);
1751 call_list = __bt_hf_prepare_call_list(buffer);
1753 if (call_list == NULL)
1756 __bt_hf_launch_call_using_call_list(call_list, bt_hf_info);
1758 __bt_hf_agent_send_call_status_info(call_list);
1760 __bt_hf_free_call_list(call_list);
1763 __bt_hf_unlock_display();
1764 DBG("---------__bt_hf_agent_handler_clcc --------");
1768 static struct hf_event hf_event_callbacks[] = {
1769 { "\r\n+CIEV:", __bt_hf_agent_handler_ciev },
1770 { "\r\nRING", __bt_hf_agent_handler_ring },
1771 { "\r\n+CLIP:", __bt_hf_agent_handler_clip },
1772 { "\r\n+BVRA:", __bt_hf_agent_handler_bvra },
1773 { "\r\n+BCS:", __bt_hf_agent_handler_bcs },
1774 { "\r\n+VGS:", __bt_hf_agent_handler_vgs },
1775 { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa },
1776 { "\r\n+XSAT:", __bt_hf_agent_handler_xsat },
1777 {"\r\n+CLCC:", __bt_hf_agent_handler_clcc },
1781 static struct hf_event hf_event_resp_callbacks[] = {
1782 { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error },
1783 { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok },
1784 { "ERROR", __bt_hf_agent_handler_response_err },
1785 { "SERR", __bt_hf_agent_handler_response_serr },
1789 bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info)
1793 bt_hf_agent_send_at_info *cmd;
1794 len = g_slist_length(bt_hf_info->cmd_send_queue);
1795 for (i = 0; i < len; ++i) {
1796 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i);
1797 DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id);
1799 len = g_slist_length(bt_hf_info->cmd_send_queue);
1800 DBG("Context queue length = %d", len);
1804 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
1806 bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
1807 DBG("NEXT[%d] Found %s, context = 0x%x, pending = %d", cmd->id,
1808 cmd->at_cmd, cmd->context, cmd->pending);
1812 DBG("**** Not found any pending command on list length %d ****", len);
1817 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1819 struct hf_event *ev;
1821 bt_hf_agent_send_at_info *cmd = NULL;
1823 __bt_hf_agent_print_at_buffer("Processing [Rx cmd]:", buf);
1825 for (ev = hf_event_resp_callbacks; ev->cmd; ev++) {
1826 if (strstr(buf, ev->cmd)) {
1829 DBG("Send flag value = %d(after)", send_flag);
1830 ret = ev->callback(bt_hf_info, buf);
1837 for (ev = hf_event_callbacks; ev->cmd; ev++) {
1838 if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) {
1839 ret = ev->callback(bt_hf_info, buf);
1847 cmd = __bt_hf_agent_find_next(bt_hf_info);
1849 if (cmd && cmd->context) {
1850 DBG("Pending context found for %.6s[%d]", cmd->at_cmd, cmd->id);
1851 g_dbus_method_invocation_return_value(cmd->context, NULL);
1853 g_source_remove(cmd->timer_id);
1859 cmd = __bt_hf_agent_find_next(bt_hf_info);
1861 if (cmd && cmd->pending && send_flag == 0) {
1862 DBG("Pending only found of %.6s[%d]", cmd->at_cmd, cmd->id);
1863 __bt_hf_send_only_without_queue(bt_hf_info,
1864 cmd->at_cmd, cmd->count);
1865 cmd->pending = FALSE;
1866 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
1868 DBG("Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
1871 DBG("Pending free for %.6s[%d] - send_flag = %d",
1872 cmd->at_cmd, cmd->id, send_flag);
1874 g_source_remove(cmd->timer_id);
1880 /* Need to process further pending */
1881 cmd = __bt_hf_agent_find_next(bt_hf_info);
1883 if (cmd->pending && send_flag == 0) {
1884 DBG("2nd Pending only found of %.6s[%d]",
1885 cmd->at_cmd, cmd->id);
1886 __bt_hf_send_only_without_queue(bt_hf_info,
1887 cmd->at_cmd, cmd->count);
1888 cmd->pending = FALSE;
1890 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
1892 DBG("2nd Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
1898 static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf)
1902 int cmd_buf_len = 0;
1903 char *pos_start, *pos_end;
1904 const char *datap = buf;
1906 cmd_buf_len = strlen(cmd_buf);
1907 buf_length = strlen(buf);
1908 DBG("buf_length = %d, cmd_buf_len = %d", buf_length, cmd_buf_len);
1910 if (buf_length > 0 && strstr(datap, "+CLCC")) {
1911 pos_start = strstr(datap, "\r\n");
1912 if (pos_start == NULL) {
1913 ERR("Invalid AT command signature..\n");
1917 pos_end = g_strrstr(datap, "+CLCC");
1918 if (pos_end == NULL) {
1919 ERR("Invalid AT command signature..\n");
1922 pos_end = strstr(pos_end, "\r\n");
1923 cmd_length = (pos_end - pos_start) + 2;
1924 INFO("CLCC balance Cmd Length = %d\n", cmd_length);
1925 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
1926 cmd_buf[cmd_buf_len + cmd_length] = '\0';
1928 if (strstr(cmd_buf, "\r\nOK\r\n")) {
1929 pos_end = strstr(datap, "\r\nOK\r\n");
1930 cmd_length = (pos_end - pos_start);
1931 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
1932 cmd_buf[cmd_buf_len + cmd_length] = '\0';
1933 INFO("New CLCC balance Cmd Length = %d", cmd_length);
1940 static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1944 char *pos_start, *pos_end;
1946 gchar cmd_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1947 const char *datap = buf;
1949 __bt_hf_agent_print_at_buffer("[HF AT CMD] Recv >>>>>:", buf);
1951 buf_length = strlen(buf);
1953 while (buf_length > 0) {
1954 pos_start = strstr(datap, "\r\n");
1955 if (pos_start == NULL) {
1956 ERR("Invalid AT command start signature..\n");
1961 pos_end = strstr(datap, "\r\n");
1962 if (pos_end == NULL) {
1963 ERR("Invalid AT command end signature..\n");
1966 cmd_length = (pos_end - pos_start) + 2;
1967 DBG("Cmd Length = %d\n", cmd_length);
1969 memcpy(cmd_buf, pos_start, cmd_length);
1970 cmd_buf[cmd_length] = '\0';
1972 buf_length = buf_length - cmd_length;
1973 datap = datap + cmd_length - 2;
1975 /* We need to pass all the CLCC's together to its handler */
1976 if (strstr(cmd_buf, "+CLCC")) {
1977 tmp = hf_handle_append_clcc_buff(cmd_buf, datap);
1979 buf_length = buf_length - tmp;
1981 hf_handle_rx_at_cmd(bt_hf_info, cmd_buf);
1982 DBG("Pending buf_length = %d\n", buf_length);
1987 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
1988 bt_hf_agent_info_t *bt_hf_info)
1990 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
1992 GError *gerr = NULL;
1993 gboolean recvd_ok = FALSE;
1994 gboolean recvd_error = FALSE;
1995 gboolean recvd_sec_error = FALSE;
1997 if (cond & (G_IO_ERR | G_IO_HUP)) {
1998 ERR("ERR or HUP on RFCOMM socket");
1999 INFO_C("### Disconnected [HF role] [Terminated by remote dev]");
2000 is_hf_connected = FALSE;
2001 bt_hf_info->slc = FALSE;
2002 __bt_hf_agent_release();
2006 if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, &gerr)
2007 != G_IO_STATUS_NORMAL) {
2009 ERR("Read failed, cond = [%d], Err msg = [%s]",
2010 cond, gerr->message);
2016 recvd_ok = NULL != strstr(buf, BT_HF_OK_RESPONSE);
2017 recvd_error = NULL != strstr(buf, BT_HF_ERROR_RESPONSE);
2018 recvd_sec_error = NULL != strstr(buf, BT_HF_SEC_ERROR_RESPONSE);
2019 DBG("<-------Received data --send flag status = %d ----->", send_flag);
2021 /* Once service level connection is established we need to handle
2022 * all the intermediate AT commands */
2023 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2027 strncat(global_buff, buf,
2028 (BT_AT_COMMAND_BUFFER_MAX - 1) - strlen(global_buff));
2029 if (!(recvd_ok || recvd_error || recvd_sec_error)) {
2030 __bt_hf_agent_print_at_buffer("Concat ()", global_buff);
2032 DBG("*** Received terminator.. process Rx buffer ***");
2033 hf_handle_rx_at_buff(bt_hf_info, global_buff);
2034 memset(global_buff, 0, sizeof(global_buff));
2037 INFO("*** Received Direct AT buffer packet handling ****");
2038 hf_handle_rx_at_buff(bt_hf_info, buf);
2043 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info)
2045 bt_hf_info->watch_id = g_io_add_watch(bt_hf_info->io_chan,
2046 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2047 (GIOFunc) __bt_hf_agent_data_cb, bt_hf_info);
2050 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info)
2052 if (bt_hf_info->watch_id > 0) {
2053 g_source_remove(bt_hf_info->watch_id);
2054 bt_hf_info->watch_id = 0;
2058 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
2065 status = g_io_channel_write_chars(io, data, count, &written,
2067 if (status != G_IO_STATUS_NORMAL)
2076 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
2077 gchar *data, gsize count)
2079 GIOChannel *io_chan = bt_hf_info->io_chan;
2080 if (!__bt_hf_channel_write(io_chan, data, count))
2083 g_io_channel_flush(io_chan, NULL);
2085 if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
2086 INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
2087 count, count - 6, "ATDXXXXXXX");
2088 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
2090 INFO("No queue....Send only buffer size =[%d] - Send <<<<<| %s",
2095 /* DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2096 * send_flag, count, data); */
2101 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
2104 gboolean pending = FALSE;
2105 GIOChannel *io_chan = bt_hf_info->io_chan;
2110 __bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
2115 if (!__bt_hf_channel_write(io_chan, data, count))
2118 g_io_channel_flush(io_chan, NULL);
2120 if (count > 2 && data[2] == 'D') /* ATDXXXXX */
2121 INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
2122 count, count - 6, "ATDXXXXXXX");
2124 INFO("Send only buffer size =[%d] - Send <<<<<| %s", count, data);
2127 DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2128 send_flag, count, data);
2132 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
2133 gchar *data, gchar *response, gsize count)
2135 GIOChannel *io_chan = bt_hf_info->io_chan;
2137 gboolean recvd_ok = FALSE;
2138 gboolean recvd_error = FALSE;
2139 gboolean recvd_sec_error = FALSE;
2140 gchar *resp_buf = response;
2141 gsize toread = BT_HF_DATA_BUF_SIZE - 1;
2146 GDBusConnection *conn;
2148 /* Should not send cmds if DUT send a command and wait the response */
2149 if (prev_cmd[0] != 0) {
2150 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
2154 memset(resp_buf, 0, BT_HF_DATA_BUF_SIZE);
2156 if (!__bt_hf_channel_write(io_chan, data, count))
2159 g_io_channel_flush(io_chan, NULL);
2161 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send <<<<<:", data);
2163 fd = g_io_channel_unix_get_fd(io_chan);
2165 p.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
2167 /* Maximun 8 seconds of poll or 8 minus no of cmd received */
2168 for (i = 1; i <= MAX_WAITING_DELAY; i++) {
2169 DBG("Loop Counter = %d", i);
2171 err = poll(&p, 1, 1000);
2173 ERR("Loop Counter = %d, >>>> Poll error happen", i);
2175 } else if (err == 0) {
2176 INFO("Loop Counter = %d, >>>> Poll Timeout", i);
2179 if (p.revents & (POLLERR | POLLHUP | POLLNVAL)) {
2180 ERR("Loop Counter = %d, >> Poll ERR/HUP/INV (%d)",
2183 conn = __bt_hf_get_gdbus_connection();
2185 ERR("Unable to get connection");
2189 __bt_hf_agent_emit_signal(conn,
2190 BT_HF_AGENT_OBJECT_PATH,
2191 BT_HF_SERVICE_INTERFACE,
2193 g_variant_new("(s)",
2194 bt_hf_info->remote_addr));
2196 bt_hf_info->state = BT_HF_STATE_DISCONNECTED;
2200 if (p.revents & POLLIN) {
2201 rd_size = read(fd, resp_buf, toread);
2202 resp_buf[rd_size] = '\0';
2203 DBG_SECURE("size = %d, Buffer=[%s]", rd_size, resp_buf);
2204 recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
2205 recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
2206 recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
2208 resp_buf += rd_size;
2211 if (recvd_ok || recvd_error || recvd_sec_error) {
2212 DBG("Break Loop Counter = %d", i);
2218 /* Once service level connection is established we need to handle
2219 * all the intermediate AT commands */
2220 if (bt_hf_info->state == BT_HF_STATE_CONNECTED)
2221 hf_handle_rx_at_buff(bt_hf_info, response);
2225 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indices)
2227 struct indicator *ind;
2228 gchar *cur = names - 1;
2229 GSList *list = indices;
2232 DBG("Indicator buffer = %s", names);
2233 __bt_hf_agent_print_at_buffer("Indicator names :", names);
2234 while (cur != NULL) {
2236 next = strstr(cur, ",(");
2237 ind = g_new0(struct indicator, 1);
2238 g_strlcpy(ind->descr, cur, BT_HF_INDICATOR_DESCR_SIZE);
2239 ind->descr[(intptr_t) next - (intptr_t) cur] = '\0';
2240 list = g_slist_append(list, (gpointer) ind);
2241 cur = strstr(next + 1, ",(");
2246 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices)
2249 struct indicator *ind;
2250 GSList *runner = indices;
2252 gchar *cur = values - 1;
2254 DBG("Indicator string = %s", values);
2255 __bt_hf_agent_print_at_buffer("Indicator values :", values);
2256 while (cur != NULL) {
2258 val = strtol(cur, &stop, 10);
2259 cur = strchr(cur, ',');
2260 ind = g_slist_nth_data(runner, 0);
2262 runner = g_slist_next(runner);
2267 static guint __bt_hf_get_hold_mpty_features(gchar *features)
2271 if (strstr(features, "0"))
2272 result |= BT_HF_CHLD_0;
2274 if (strstr(features, "1"))
2275 result |= BT_HF_CHLD_1;
2277 if (strstr(features, "1x"))
2278 result |= BT_HF_CHLD_1x;
2280 if (strstr(features, "2"))
2281 result |= BT_HF_CHLD_2;
2283 if (strstr(features, "2x"))
2284 result |= BT_HF_CHLD_2x;
2286 if (strstr(features, "3"))
2287 result |= BT_HF_CHLD_3;
2289 if (strstr(features, "4"))
2290 result |= BT_HF_CHLD_4;
2295 static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2297 bt_hf_agent_info_t *bt_hf_info = user_data;
2298 GDBusConnection *conn;
2301 if (cond & G_IO_NVAL)
2304 if (cond & (G_IO_HUP | G_IO_ERR)) {
2305 g_io_channel_shutdown(chan, TRUE, NULL);
2306 close(bt_hf_info->cli_sco_fd);
2307 g_io_channel_unref(chan);
2308 DBG("Emit AudioDisconnected Signal");
2310 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2312 conn = __bt_hf_get_gdbus_connection();
2314 ERR("Unable to get connection");
2317 __bt_hf_agent_emit_signal(conn,
2318 BT_HF_AGENT_OBJECT_PATH,
2319 BT_HF_SERVICE_INTERFACE,
2320 "AudioDisconnected", NULL);
2328 static gboolean __bt_agent_query_and_update_call_list(gpointer data)
2331 bt_hf_agent_info_t *bt_hf_info = data;
2333 if (bt_hf_info->cli_sco_fd >= 0)
2334 __bt_hf_agent_handle_call_list(bt_hf_info);
2336 INFO("SCO Audio is already disconnected");
2343 static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2345 bt_hf_agent_info_t *bt_hf_info = user_data;
2349 GDBusConnection *conn;
2351 INFO("Incoming SCO....");
2353 if (cond & G_IO_NVAL)
2356 sco_skt = g_io_channel_unix_get_fd(chan);
2358 if (cond & (G_IO_HUP | G_IO_ERR)) {
2363 cli_sco_sock = accept(sco_skt, NULL, NULL);
2364 if (cli_sco_sock < 0)
2367 bt_hf_info->cli_sco_fd = cli_sco_sock;
2369 sco_io = g_io_channel_unix_new(cli_sco_sock);
2370 g_io_channel_set_close_on_unref(sco_io, TRUE);
2371 g_io_channel_set_encoding(sco_io, NULL, NULL);
2372 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2373 g_io_channel_set_buffered(sco_io, FALSE);
2375 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2376 __bt_hf_agent_sco_conn_cb, bt_hf_info);
2378 /* S-Voice app requires the AudioConnected signal earlier */
2379 DBG("Emit AudioConnected Signal");
2381 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
2383 conn = __bt_hf_get_gdbus_connection();
2385 ERR("Unable to get connection");
2389 __bt_hf_agent_emit_signal(conn,
2390 BT_HF_AGENT_OBJECT_PATH,
2391 BT_HF_SERVICE_INTERFACE,
2392 "AudioConnected", NULL);
2394 /* In the case of incoming call, the call app is already launched,
2395 * hence AudioConnected signal is enough to update the call status.
2396 * In the case of outgoing call we need to lauch the callapp.
2399 g_idle_add(__bt_agent_query_and_update_call_list, bt_hf_info);
2404 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
2405 const char *address)
2410 ret_if(address == NULL);
2411 ret_if(addr == NULL);
2413 for (i = 0; i < 6; i++) {
2414 addr[5 - i] = strtol(address, &ptr, 16);
2415 if (ptr[0] != '\0') {
2424 static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
2426 struct sockaddr_sco addr;
2428 bdaddr_t bd_addr = {{0},};
2431 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2435 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
2437 ERR("Can't create socket:\n");
2441 /* Bind to local address */
2442 memset(&addr, 0, sizeof(addr));
2443 addr.sco_family = AF_BLUETOOTH;
2445 DBG("Bind to address %s", bt_hf_info->remote_addr);
2447 _bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
2448 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2450 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2451 ERR("Can't bind socket:\n");
2455 if (listen(sco_skt, 1)) {
2456 ERR("Can not listen on the socket:\n");
2460 sco_io = g_io_channel_unix_new(sco_skt);
2461 g_io_channel_set_close_on_unref(sco_io, TRUE);
2462 g_io_channel_set_encoding(sco_io, NULL, NULL);
2463 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2464 g_io_channel_set_buffered(sco_io, FALSE);
2466 bt_hf_info->sco_fd = sco_skt;
2467 bt_hf_info->sco_io_chan = sco_io;
2469 bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
2470 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
2472 g_io_channel_unref(sco_io);
2481 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
2483 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2486 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
2487 sizeof(BT_HF_INDICATORS_SUPP) - 1);
2488 if (!ret || !strstr(buf, "+CIND:"))
2491 bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
2496 static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
2501 if (bt_hf_info == NULL || cmd == NULL) {
2502 ERR("Invalid parameter");
2506 ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
2508 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
2509 ret = g_strlcat(cmd, "0,", cmd_size);
2510 if (ret >= cmd_size) {
2511 ERR("Too many indices");
2517 cmd[ret - 1] = '\0';
2518 DBG("BIA Str : %s", cmd);
2520 ret = g_strlcat(cmd, "\r", cmd_size);
2521 if (ret >= cmd_size) {
2522 ERR("Too many indices");
2529 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
2531 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2537 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
2538 sizeof(BT_HF_INDICATORS_VAL) - 1);
2539 if (!ret || !strstr(buf, "+CIND:"))
2542 /* if buf has other command prefix, skip it */
2543 str = strstr(buf, "+CIND");
2547 bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
2549 /* Parse the updated value */
2550 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
2551 struct indicator *ind = l->data;
2553 DBG("Index is NULL");
2557 if (0 == g_strcmp0(ind->descr, "\"call\"")) {
2558 DBG("CIND Match found index = %d, %s, value = %d",
2559 index, ind->descr, ind->value);
2560 bt_hf_info->ciev_call_status = ind->value;
2561 if (ind->value > 0) {
2562 bt_hf_info->is_dialing = FALSE;
2563 bt_hf_info->call_active = TRUE;
2565 } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
2566 DBG("CIND Match found index = %d, %s, value = %d",
2567 index, ind->descr, ind->value);
2568 bt_hf_info->ciev_call_setup_status = ind->value;
2569 if (!bt_hf_info->is_dialing && ind->value > 0)
2570 bt_hf_info->is_dialing = TRUE;
2577 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
2579 gchar buf[BT_HF_DATA_BUF_SIZE];
2580 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
2584 guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
2585 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
2586 BT_HF_FEATURE_CLI_PRESENTATION |
2587 BT_HF_FEATURE_VOICE_RECOGNITION |
2588 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
2589 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
2591 if (TIZEN_PROFILE_WEARABLE)
2592 feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
2594 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
2595 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
2600 buf_ptr = strstr(buf, "\r\n+BRSF:");
2601 if (buf_ptr == NULL)
2604 buf_ptr = strstr(buf_ptr, "BRSF:");
2605 bt_hf_info->ag_features = strtol(buf_ptr + 5, &stop, 10);
2608 if (!ret || !bt_hf_info->ag_features)
2610 INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
2612 if (TIZEN_PROFILE_WEARABLE) {
2613 if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
2614 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
2615 if (ret != BT_HF_AGENT_ERROR_NONE)
2616 ERR("Unable to set the default WBC codec");
2618 ret = __bt_hf_send_available_codec(bt_hf_info, 0);
2623 /* Default codec is NB */
2624 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
2625 if (ret != BT_HF_AGENT_ERROR_NONE)
2626 ERR("Unable to set the default NBC codec");
2629 ret = __bt_get_supported_indicators(bt_hf_info);
2634 ret = __bt_get_current_indicators(bt_hf_info);
2638 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
2639 sizeof(BT_HF_INDICATORS_ENABLE) - 1);
2640 if (!ret || !strstr(buf, "OK"))
2643 if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
2644 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
2645 buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
2646 if (!ret || !strstr(buf, "+CHLD:")) {
2647 ERR("Unable to get the CHLD Supported info");
2650 bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
2653 bt_hf_info->hold_multiparty_features = 0;
2655 INFO("Service layer connection successfully established...!");
2657 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
2658 sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
2659 __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
2660 sizeof(BT_HF_CARRIER_FORMAT) - 1);
2661 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
2662 sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
2664 if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
2665 __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
2666 sizeof(BT_HF_NREC) - 1);
2668 if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
2669 __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
2670 buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
2672 if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
2673 __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
2675 ERR("__bt_get_bia_cmd is failed");
2677 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
2678 sizeof(BT_HF_XSAT) - 1);
2680 DBG("sent BT_HF_XSAT");
2682 ERR("BT_HF_XSAT sending failed");
2684 /* send Bluetooth Samsung Support Feature cmd */
2685 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
2686 sizeof(BT_HF_BSSF) - 1);
2688 INFO("SLC completed with all commands");
2690 ERR("BT_HF_BSSF sending failed");
2692 bt_hf_info->slc = TRUE;
2695 memset(global_buff, 0, sizeof(global_buff));
2699 static void __bt_hf_agent_sigterm_handler(int signo)
2701 ERR_C("***** Signal handler came with signal %d *****", signo);
2702 GDBusConnection *conn;
2704 conn = __bt_hf_get_gdbus_connection();
2706 ERR("Unable to get connection");
2710 __bt_hf_agent_emit_signal(conn,
2711 BT_HF_AGENT_OBJECT_PATH,
2712 BT_HF_SERVICE_INTERFACE,
2714 DBG("CallEnded Signal done");
2716 g_main_loop_quit(gmain_loop);
2720 INFO_C("Terminating HF agent");
2725 static void __bt_convert_addr_type_to_rev_string(char *address,
2726 unsigned char *addr)
2728 ret_if(address == NULL);
2729 ret_if(addr == NULL);
2731 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
2732 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
2733 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
2737 static gboolean __bt_hf_agent_release_after(gpointer user_data)
2739 if (__bt_hf_agent_release() == FALSE)
2740 ERR("Unable to release hf connection");
2745 static gboolean __bt_agent_request_service_level_conn(gpointer data)
2748 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2749 GDBusConnection *conn;
2752 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
2754 if (!__bt_establish_service_level_conn(&bt_hf_info)) {
2755 ERR("Service Level Connection is fail");
2757 conn = __bt_hf_get_gdbus_connection();
2759 remote_addr = bt_hf_info.remote_addr;
2760 __bt_hf_agent_emit_signal(conn,
2761 BT_HF_AGENT_OBJECT_PATH,
2762 BT_HF_SERVICE_INTERFACE,
2764 g_variant_new("(s)", remote_addr));
2766 bt_hf_info.state = BT_HF_STATE_CONNECTED;
2768 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2769 DBG("BT device state is : 0x%X", bt_device_state);
2770 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2771 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2772 ERR("vconf_set_int failed");
2774 ERR("vconf_get_int failed");
2777 g_idle_add(__bt_hf_agent_release_after, NULL);
2782 bt_hf_info.state = BT_HF_STATE_CONNECTED;
2784 __bt_hf_agent_sco_accept(&bt_hf_info);
2786 __bt_hf_agent_start_watch(&bt_hf_info);
2788 remote_addr = bt_hf_info.remote_addr;
2790 INFO_SECURE("Address is : %s", remote_addr);
2791 INFO_C("### Connected [HF role]");
2793 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2794 DBG("BT device state is : 0x%X", bt_device_state);
2795 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2797 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2798 ERR("vconf_set_int failed");
2800 ERR("vconf_get_int failed");
2803 conn = __bt_hf_get_gdbus_connection();
2805 ERR("Unable to get connection");
2809 __bt_hf_agent_emit_signal(conn,
2810 BT_HF_AGENT_OBJECT_PATH,
2811 BT_HF_SERVICE_INTERFACE,
2813 g_variant_new("(s)", remote_addr));
2815 /* Request the call list and launch call app if required */
2816 __bt_hf_agent_handle_call_list(&bt_hf_info);
2823 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
2827 struct sockaddr_remote address;
2828 socklen_t address_len;
2829 bt_hf_info.path = g_strdup(obj_path);
2831 INFO_C("**** New HFP connection ****");
2833 is_hf_connected = TRUE;
2835 address_len = sizeof(address);
2836 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2837 ERR("BD_ADDR is NULL");
2839 DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
2841 bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
2842 flags = g_io_channel_get_flags(bt_hf_info.io_chan);
2844 flags &= ~G_IO_FLAG_NONBLOCK;
2845 flags &= G_IO_FLAG_MASK;
2846 g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
2847 g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
2848 g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
2850 bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2851 __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
2852 address.remote_bdaddr.b);
2854 g_idle_add(__bt_agent_request_service_level_conn, NULL);
2859 static void __bt_hf_agent_indicator_free(gpointer mem)
2864 static gboolean __bt_hf_agent_release(void)
2866 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2867 GDBusConnection *conn;
2869 if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
2870 ERR("hf is already disconnected");
2874 if (bt_hf_info.indies) {
2875 g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
2876 bt_hf_info.indies = NULL;
2879 if (bt_hf_info.io_chan) {
2880 g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
2881 g_io_channel_unref(bt_hf_info.io_chan);
2882 bt_hf_info.io_chan = NULL;
2885 if (bt_hf_info.sco_watch_id > 0) {
2886 g_source_remove(bt_hf_info.sco_watch_id);
2887 bt_hf_info.sco_watch_id = 0;
2890 bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
2892 __bt_hf_agent_release_queue();
2894 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2895 DBG("BT device state is : 0x%X", bt_device_state);
2896 bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2898 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2899 ERR("vconf_set_int failed");
2901 ERR("vconf_get_int failed");
2904 __bt_hf_agent_stop_watch(&bt_hf_info);
2905 conn = __bt_hf_get_gdbus_connection();
2907 ERR("Unable to get connection");
2911 __bt_hf_agent_emit_signal(conn,
2912 BT_HF_AGENT_OBJECT_PATH,
2913 BT_HF_SERVICE_INTERFACE,
2915 g_variant_new("(s)", bt_hf_info.remote_addr));
2917 g_free(bt_hf_info.path);
2918 bt_hf_info.path = NULL;
2920 g_free(bt_hf_info.remote_addr);
2921 bt_hf_info.remote_addr = NULL;
2923 is_hf_connected = FALSE;
2928 static gboolean __bt_hf_agent_connection_release(void)
2930 return __bt_hf_agent_release();
2933 static int __bt_hf_register_profile(const char *uuid, uint16_t version,
2934 const char *name, const char *object, uint16_t features)
2939 GError *error = NULL;
2940 GVariantBuilder *builder;
2943 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
2944 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
2947 return BT_HF_AGENT_ERROR_INTERNAL;
2949 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2951 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2953 g_variant_builder_add(builder, "{sv}",
2954 "Name", g_variant_new("s",
2956 g_variant_builder_add(builder, "{sv}",
2957 "Version", g_variant_new("q", version));
2959 g_variant_builder_add(builder, "{sv}",
2960 "features", g_variant_new("q", features));
2962 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
2963 g_variant_new("(osa{sv})", path,
2964 HFP_HF_UUID, builder),
2965 G_DBUS_CALL_FLAGS_NONE, -1,
2968 g_variant_builder_unref(builder);
2971 /* dBUS-RPC is failed */
2972 ERR("dBUS-RPC is failed");
2973 if (error != NULL) {
2974 /* dBUS gives error cause */
2975 ERR("D-Bus API failure: errCode[%x], message[%s]",
2976 error->code, error->message);
2977 g_clear_error(&error);
2980 return BT_HF_AGENT_ERROR_INTERNAL;
2982 g_variant_unref(ret);
2986 return BT_HF_AGENT_ERROR_NONE;
2989 static void __bt_hf_agent_register(void)
2994 uint16_t version = hf_ver;
2995 uint16_t features = bt_hf_info.feature;
2997 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2998 name = g_strdup("Hands-Free");
3000 ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
3003 ERR("Error in register");
3012 static void __bt_hf_agent_unregister(void)
3016 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3019 __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
3020 g_variant_new("(o)", path),
3021 BLUEZ_HF_INTERFACE_NAME,
3033 static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
3034 const gchar *sender_name,
3035 const gchar *object_path,
3036 const gchar *interface_name,
3037 const gchar *signal_name,
3038 GVariant *parameters,
3044 GVariant *optional_param;
3046 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3048 g_variant_get(parameters, "(&o@a{sa{sv}})",
3049 &path, &optional_param);
3051 ERR("Invalid adapter path");
3055 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3056 g_obj_path = g_strdup(path);
3057 INFO("Adapter Path = [%s]", path);
3058 __bt_hf_agent_register();
3060 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
3061 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
3063 __bt_hf_agent_unregister();
3068 static void __bt_hf_agent_dbus_init(void)
3070 GDBusConnection *conn;
3074 conn = __bt_hf_get_gdbus_connection();
3076 ERR("Error in creating the gdbus connection\n");
3079 if (!__bt_hf_register_profile_methods()) {
3080 ERR("Error in register_profile_methods\n");
3084 owner_sig_id = g_dbus_connection_signal_subscribe(conn,
3085 NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
3086 __bt_hf_agent_filter_cb, NULL, NULL);
3091 static void __bt_hf_agent_dbus_deinit(void)
3094 if (service_gproxy) {
3095 g_object_unref(service_gproxy);
3096 service_gproxy = NULL;
3100 if (owner_sig_id != -1)
3101 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3104 g_object_unref(gdbus_conn);
3110 static int _hf_agent_answer_call(GDBusMethodInvocation *context)
3115 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3116 ERR("HF not Connected");
3117 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3119 bt_hf_info.context = context;
3121 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
3122 sizeof(BT_HF_ANSWER_CALL) - 1);
3124 return BT_HF_AGENT_ERROR_INTERNAL;
3127 return BT_HF_AGENT_ERROR_NONE;
3131 static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
3136 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3137 ERR("HF not Connected");
3138 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3141 bt_hf_info.context = context;
3143 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
3144 sizeof(BT_HF_END_CALL) - 1);
3146 return BT_HF_AGENT_ERROR_INTERNAL;
3149 return BT_HF_AGENT_ERROR_NONE;
3152 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
3155 char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
3157 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3158 ERR("HF not Connected");
3159 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3162 bt_hf_info.context = context;
3164 if (strlen(no) > 0) {
3165 snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
3167 if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
3168 && bt_hf_info.ciev_call_setup_status == 0) {
3169 INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
3170 ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
3174 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3177 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3178 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
3181 return BT_HF_AGENT_ERROR_INTERNAL;
3183 return BT_HF_AGENT_ERROR_NONE;
3186 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3187 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
3189 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
3190 sizeof(BT_HF_REDIAL) - 1);
3192 return BT_HF_AGENT_ERROR_INTERNAL;
3194 return BT_HF_AGENT_ERROR_NONE;
3197 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
3202 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3203 ERR("HF not Connected");
3204 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3207 snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
3209 bt_hf_info.context = context;
3211 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3213 return BT_HF_AGENT_ERROR_INTERNAL;
3216 return BT_HF_AGENT_ERROR_NONE;
3219 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
3224 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3225 ERR("HF not Connected");
3226 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3229 if (gain > BT_HF_MAX_SPEAKER_GAIN)
3230 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3232 snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
3234 bt_hf_info.context = context;
3236 ret = __bt_hf_send_only(&bt_hf_info, buf,
3239 return BT_HF_AGENT_ERROR_INTERNAL;
3241 return BT_HF_AGENT_ERROR_NONE;
3245 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
3250 if (strlen(dtmf) <= 0)
3251 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3253 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3254 ERR("HF not Connected");
3255 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3258 snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
3260 bt_hf_info.context = context;
3262 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3264 return BT_HF_AGENT_ERROR_INTERNAL;
3267 return BT_HF_AGENT_ERROR_NONE;
3271 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
3275 if (strlen(cmd) <= 0)
3276 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3278 bt_hf_info.context = context;
3280 ret = __bt_hf_send_only(&bt_hf_info, cmd,
3283 return BT_HF_AGENT_ERROR_INTERNAL;
3285 return BT_HF_AGENT_ERROR_NONE;
3288 static gboolean bt_hf_agent_sco_disconnect(void)
3291 GDBusConnection *conn;
3293 close(bt_hf_info.cli_sco_fd);
3294 bt_hf_info.cli_sco_fd = -1;
3296 DBG("Emit AudioDisconnected Signal");
3297 conn = __bt_hf_get_gdbus_connection();
3299 ERR("Unable to get connection");
3303 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
3305 __bt_hf_agent_emit_signal(conn,
3306 BT_HF_AGENT_OBJECT_PATH,
3307 BT_HF_SERVICE_INTERFACE,
3308 "AudioDisconnected", NULL);
3313 static GVariant *bt_hf_agent_request_call_list(void)
3315 GSList *call_list = NULL;
3319 call_list = __bt_hf_get_call_list(&bt_hf_info);
3321 INFO("call list is NULL");
3325 var_data = __bt_hf_agent_get_call_status_info(call_list);
3326 __bt_hf_free_call_list(call_list);
3332 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
3336 char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
3341 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3343 if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
3344 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3346 /* Should not send cmds if DUT has sent a command and waiting for response */
3347 if (prev_cmd[0] != 0) {
3348 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
3349 return BT_HF_AGENT_ERROR_INTERNAL;
3352 strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
3353 strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
3355 bt_hf_info.context = context;
3357 ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
3359 return BT_HF_AGENT_ERROR_INTERNAL;
3362 return BT_HF_AGENT_ERROR_NONE;
3365 static uint32_t __bt_hf_agent_get_hf_features(void)
3367 uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
3368 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
3369 BT_HF_FEATURE_CLI_PRESENTATION |
3370 BT_HF_FEATURE_VOICE_RECOGNITION |
3371 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3372 BT_HF_FEATURE_ENHANCED_CALL_STATUS |
3373 BT_HF_FEATURE_CODEC_NEGOTIATION;
3375 if (TIZEN_PROFILE_WEARABLE)
3376 hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
3378 hf_ver = HFP_VERSION_1_6;
3385 struct sigaction sa;
3386 uint32_t hf_features;
3388 INFO_C("### Starting Bluetooth HF agent");
3390 hf_features = __bt_hf_agent_get_hf_features();
3391 bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
3393 memset(&sa, 0, sizeof(sa));
3394 sa.sa_flags = SA_NOCLDSTOP;
3395 sa.sa_handler = __bt_hf_agent_sigterm_handler;
3396 sigaction(SIGTERM, &sa, NULL);
3398 /* Temporarily, block the below signal for debugging */
3399 // sigaction(SIGSEGV, &sa, NULL);
3400 // sigaction(SIGABRT, &sa, NULL);
3401 gmain_loop = g_main_loop_new(NULL, FALSE);
3403 if (gmain_loop == NULL) {
3404 ERR("GMainLoop create failed\n");
3405 return EXIT_FAILURE;
3408 __bt_hf_agent_dbus_init();
3409 g_main_loop_run(gmain_loop);
3411 __bt_hf_agent_dbus_deinit();
3414 g_main_loop_unref(gmain_loop);
3416 INFO_C("### Terminating Bluetooth HF agent");