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 guint interface_added_sig_id;
70 static guint interface_removed_sig_id;
74 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
75 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
77 /*Below Inrospection data is exposed to bluez from agent*/
78 static const gchar hf_agent_bluez_introspection_xml[] =
80 " <interface name='org.bluez.Profile1'>"
81 " <method name='NewConnection'>"
82 " <arg type='o' name='device' direction='in'/>"
83 " <arg type='h' name='fd' direction='in'/>"
84 " <arg type='a{sv}' name='options' direction='in'/>"
86 " <method name='RequestDisconnection'>"
87 " <arg type='o' name='device' direction='in'/>"
92 /*Below Inrospection data is exposed to application from agent*/
93 static const gchar hf_agent_introspection_xml[] =
95 " <interface name='org.tizen.HfApp'>"
96 " <method name='AnswerCall'>"
98 " <method name='TerminateCall'>"
100 " <method name='InitiateCall'>"
101 " <arg type='s' name='phoneno' direction='in'/>"
103 " <method name='VoiceRecognition'>"
104 " <arg type='i' name='status' direction='in'/>"
106 " <method name='ScoDisconnect'>"
108 " <method name='SpeakerGain'>"
109 " <arg type='u' name='gain' direction='in'/>"
111 " <method name='SendDtmf'>"
112 " <arg type='s' name='dtmf' direction='in'/>"
114 " <method name='SendAtCmd'>"
115 " <arg type='s' name='atcmd' direction='in'/>"
117 " <method name='ReleaseAndAccept'>"
119 " <method name='CallSwap'>"
121 " <method name='ReleaseAllCall'>"
123 " <method name='JoinCall'>"
125 " <method name='GetCurrentCodec'>"
126 " <arg type='i' name='codec' direction='out'/>"
128 " <method name='RequestCallList'>"
129 " <arg type='i' name='count' direction='out'/>"
130 " <arg type='a(siiii)' name='callList' direction='out'/>"
132 " <method name='GetAudioConnected'>"
133 " <arg type='i' name='status' direction='out'/>"
135 " <method name='IsHfConnected'>"
136 " <arg type='b' name='status' direction='out'/>"
141 static bt_hf_agent_info_t bt_hf_info;
142 static gboolean is_hf_connected = FALSE;
143 static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD;
144 static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
146 static char global_buff[BT_AT_COMMAND_BUFFER_MAX] = {0,};
149 static char prev_cmd[BT_HF_CMD_BUF_SIZE];
159 } hf_call_list_info_t;
161 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error);
163 static gboolean __bt_hf_agent_emit_property_changed(
164 GDBusConnection *connection,
166 const char *interface,
170 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
171 bt_hf_agent_info_t *bt_hf_info);
172 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info);
173 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info);
174 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
176 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
177 gchar *data, gsize count);
179 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
181 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
182 gchar *data, gchar *response, gsize count);
183 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indies);
184 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indies);
185 static guint __bt_hf_get_hold_mpty_features(gchar *features);
186 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info);
187 static void __bt_hf_agent_sigterm_handler(int signo);
188 static gboolean __bt_hf_agent_release(void);
190 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info);
191 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info);
192 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path);
193 static gboolean __bt_hf_agent_connection_release(void);
196 gchar descr[BT_HF_INDICATOR_DESCR_SIZE];
200 static int _hf_agent_answer_call(GDBusMethodInvocation *context);
202 static int _hf_agent_terminate_call(GDBusMethodInvocation *context);
204 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no);
206 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context,
209 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd);
211 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context,
212 unsigned int status);
214 static gboolean bt_hf_agent_sco_disconnect(void);
216 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf);
218 static GVariant *bt_hf_agent_request_call_list(void);
220 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd);
222 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf);
223 static GQuark __bt_hf_agent_error_quark(void)
227 static GQuark quark = 0;
229 quark = g_quark_from_static_string("hf-agent");
234 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error)
236 ERR("error[%d]", error);
239 case BT_HF_AGENT_ERROR_NOT_AVAILABLE:
240 return g_error_new(BT_HF_AGENT_ERROR, error,
241 BT_ERROR_NOT_AVAILABLE);
242 case BT_HF_AGENT_ERROR_NOT_CONNECTED:
243 return g_error_new(BT_HF_AGENT_ERROR, error,
244 BT_ERROR_NOT_CONNECTED);
245 case BT_HF_AGENT_ERROR_CONNECTION_FAILED:
246 return g_error_new(BT_HF_AGENT_ERROR, error,
247 BT_ERROR_NOT_CONNECTION_FAILED);
248 case BT_HF_AGENT_ERROR_BUSY:
249 return g_error_new(BT_HF_AGENT_ERROR, error,
251 case BT_HF_AGENT_ERROR_INVALID_PARAM:
252 return g_error_new(BT_HF_AGENT_ERROR, error,
253 BT_ERROR_INVALID_PARAM);
254 case BT_HF_AGENT_ERROR_ALREADY_EXIST:
255 return g_error_new(BT_HF_AGENT_ERROR, error,
256 BT_ERROR_ALREADY_EXIST);
257 case BT_HF_AGENT_ERROR_ALREADY_CONNECTED:
258 return g_error_new(BT_HF_AGENT_ERROR, error,
259 BT_ERROR_ALREADY_CONNECTED);
260 case BT_HF_AGENT_ERROR_NO_MEMORY:
261 return g_error_new(BT_HF_AGENT_ERROR, error,
263 case BT_HF_AGENT_ERROR_I_O_ERROR:
264 return g_error_new(BT_HF_AGENT_ERROR, error,
266 case BT_HF_AGENT_ERROR_APPLICATION:
267 return g_error_new(BT_HF_AGENT_ERROR, error,
268 BT_ERROR_OPERATION_NOT_AVAILABLE);
269 case BT_HF_AGENT_ERROR_NOT_ALLOWED:
270 return g_error_new(BT_HF_AGENT_ERROR, error,
271 BT_ERROR_OPERATION_NOT_ALLOWED);
272 case BT_HF_AGENT_ERROR_NOT_SUPPORTED:
273 return g_error_new(BT_HF_AGENT_ERROR, error,
274 BT_ERROR_OPERATION_NOT_SUPPORTED);
275 case BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
276 return g_error_new(BT_HF_AGENT_ERROR, error,
277 BT_ERROR_INVALID_FILE_DESCRIPTOR);
278 case BT_HF_AGENT_ERROR_INTERNAL:
280 return g_error_new(BT_HF_AGENT_ERROR, error,
285 static void __bt_hf_lock_display(int timeout)
289 ret = device_power_request_lock(POWER_LOCK_DISPLAY, timeout);
291 DBG("Lock PM state as current state!");
293 ERR("deviced error!");
296 static void __bt_hf_unlock_display()
300 ret = device_power_release_lock(POWER_LOCK_DISPLAY);
302 DBG("UnLock PM state");
304 ERR("deviced error!");
307 static void __hf_agent_method(GDBusConnection *connection,
309 const gchar *object_path,
310 const gchar *interface_name,
311 const gchar *method_name,
312 GVariant *parameters,
313 GDBusMethodInvocation *context,
318 INFO("method %s", method_name);
322 if (g_strcmp0(method_name, "NewConnection") == 0) {
326 GUnixFDList *fd_list;
327 const gchar *object_path;
330 g_variant_get(parameters, "(oha{sv})",
331 &object_path, &index, &options);
333 msg = g_dbus_method_invocation_get_message(context);
334 fd_list = g_dbus_message_get_unix_fd_list(msg);
335 if (fd_list == NULL) {
336 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
340 fd = g_unix_fd_list_get(fd_list, index, NULL);
342 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
346 DBG("FD is = [%d], Object path = [%s]", fd, object_path);
348 if (!__bt_hf_agent_connection(fd, object_path)) {
349 ret = BT_HF_AGENT_ERROR_INTERNAL;
353 g_dbus_method_invocation_return_value(context, NULL);
354 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
355 if (!__bt_hf_agent_connection_release()) {
356 ret = BT_HF_AGENT_ERROR_INTERNAL;
359 INFO_C("Disconnected [HF role] [Terminated by local host]");
360 g_dbus_method_invocation_return_value(context, NULL);
361 } else if (g_strcmp0(method_name, "Release") == 0) {
362 if (!__bt_hf_agent_connection_release()) {
363 ret = BT_HF_AGENT_ERROR_INTERNAL;
367 g_dbus_method_invocation_return_value(context, NULL);
368 } else if (g_strcmp0(method_name, "AnswerCall") == 0) {
369 DBG("Going to call AnswerCall");
370 ret = _hf_agent_answer_call(context);
374 } else if (g_strcmp0(method_name, "TerminateCall") == 0) {
375 DBG("Going to call TerminateCall");
376 ret = _hf_agent_terminate_call(context);
380 } else if (g_strcmp0(method_name, "InitiateCall") == 0) {
381 char *phoneno = NULL;
383 g_variant_get(parameters, "(&s)", &phoneno);
385 DBG_SECURE("Going to call InitiateCall, Number is = [%s]\n", phoneno);
386 ret = _hf_agent_dial_no(NULL, phoneno);
390 g_dbus_method_invocation_return_value(context, NULL);
392 } else if (g_strcmp0(method_name, "VoiceRecognition") == 0) {
395 g_variant_get(parameters, "(i)", &status);
397 DBG("Going to call VoiceRecognition, Status [%d]", status);
398 ret = _hf_agent_voice_recognition(context, status);
402 } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) {
403 DBG("Going to call ScoDisconnect");
404 if (!bt_hf_agent_sco_disconnect()) {
405 ret = BT_HF_AGENT_ERROR_INTERNAL;
409 g_dbus_method_invocation_return_value(context, NULL);
410 } else if (g_strcmp0(method_name, "SpeakerGain") == 0) {
411 unsigned int gain = 0;
413 g_variant_get(parameters, "(u)", &gain);
415 DBG("Going to call SpeakerGain, gain is = [%d]\n", gain);
416 ret = _hf_agent_set_speaker_gain(context, gain);
420 } else if (g_strcmp0(method_name, "SendDtmf") == 0) {
423 g_variant_get(parameters, "(&s)", &dtmf);
425 DBG("Going to call SendDtmf, dtmf is = [%s]\n", dtmf);
426 ret = _hf_agent_send_dtmf(NULL, dtmf);
429 g_dbus_method_invocation_return_value(context, NULL);
431 } else if (g_strcmp0(method_name, "SendAtCmd") == 0) {
434 g_variant_get(parameters, "(&s)", &cmd);
436 DBG("Going to call SendAtCmd, cmd is = [%s]\n", cmd);
437 ret = bt_hf_agent_send_at_cmd(context, cmd);
441 } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) {
442 DBG("Going to call ReleaseAndAccept");
443 ret = _hf_agent_send_3way_cmd(context,
444 BT_HF_RELEASE_AND_ACCEPT);
448 } else if (g_strcmp0(method_name, "CallSwap") == 0) {
449 DBG("Going to call CallSwap");
450 ret = _hf_agent_send_3way_cmd(context,
451 BT_HF_ACCEPT_AND_HOLD);
455 } else if (g_strcmp0(method_name, "ReleaseAllCall") == 0) {
456 DBG("Going to call ReleaseAllCall");
457 ret = _hf_agent_send_3way_cmd(context, BT_HF_RELEASE_ALL);
461 } else if (g_strcmp0(method_name, "JoinCall") == 0) {
462 DBG("Going to call JoinCall");
463 ret = _hf_agent_send_3way_cmd(context, BT_HF_JOIN_CALL);
467 } else if (g_strcmp0(method_name, "GetCurrentCodec") == 0) {
468 DBG("Going to call GetCurrentCodec");
469 INFO("Current codec : %d", current_codec_id);
470 g_dbus_method_invocation_return_value(context,
471 g_variant_new("(i)", current_codec_id));
472 } else if (g_strcmp0(method_name, "RequestCallList") == 0) {
475 DBG("Going to call RequestCallList");
476 call_var = bt_hf_agent_request_call_list();
478 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
481 g_dbus_method_invocation_return_value(context, call_var);
482 } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) {
483 DBG("Going to call GetAudioConnected");
484 g_dbus_method_invocation_return_value(context,
485 g_variant_new("(i)", sco_audio_connected));
486 } else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
487 DBG("Going to call IsHfConnected");
488 INFO("is_hf_connected : %s", is_hf_connected ? "Connected" : "Disconnected");
490 g_dbus_method_invocation_return_value(context,
491 g_variant_new("(b)", is_hf_connected));
497 err = __bt_hf_agent_set_error(ret);
498 g_dbus_method_invocation_return_gerror(context, err);
503 static const GDBusInterfaceVTable method_table = {
509 static GDBusNodeInfo *__bt_hf_create_method_node_info
510 (const gchar *introspection_data)
512 if (introspection_data == NULL)
515 return g_dbus_node_info_new_for_xml(introspection_data, NULL);
518 static GDBusConnection *__bt_hf_get_gdbus_connection(void)
520 GDBusConnection *local_system_gconn = NULL;
523 if (gdbus_conn == NULL) {
524 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
527 ERR("Unable to connect to dbus: %s", err->message);
532 } else if (g_dbus_connection_is_closed(gdbus_conn)) {
533 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
535 if (!local_system_gconn) {
536 ERR("Unable to connect to dbus: %s", err->message);
540 gdbus_conn = local_system_gconn;
546 static gboolean __bt_hf_register_profile_methods(void)
549 GError *error = NULL;
552 GDBusNodeInfo *node_info;
554 GDBusConnection *conn;
556 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
558 G_BUS_NAME_OWNER_FLAGS_NONE,
562 DBG("owner_id is [%d]", owner_id);
564 node_info = __bt_hf_create_method_node_info(
565 hf_agent_bluez_introspection_xml);
566 if (node_info == NULL)
569 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
570 DBG("path is [%s]", path);
572 conn = __bt_hf_get_gdbus_connection();
574 ERR("Unable to get connection");
579 object_id = g_dbus_connection_register_object(conn, path,
580 node_info->interfaces[0],
583 if (object_id == 0) {
584 ERR("Failed to register: %s", error->message);
586 g_dbus_node_info_unref(node_info);
591 g_dbus_node_info_unref(node_info);
593 node_info = __bt_hf_create_method_node_info(hf_agent_introspection_xml);
594 if (node_info == NULL)
597 path = g_strdup(BT_HF_AGENT_OBJECT_PATH);
598 DBG("path is [%s]", path);
600 object_id = g_dbus_connection_register_object(conn, path,
601 node_info->interfaces[0],
604 if (object_id == 0) {
606 ERR("Failed to register: %s", error->message);
609 g_dbus_node_info_unref(node_info);
614 g_dbus_node_info_unref(node_info);
620 static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service,
621 const gchar *path, const gchar *interface)
627 GDBusConnection *conn;
629 conn = __bt_hf_get_gdbus_connection();
631 ERR("Unable to get connection");
635 proxy = g_dbus_proxy_new_sync(conn,
636 G_DBUS_PROXY_FLAGS_NONE, NULL,
638 interface, NULL, &err);
642 ERR("Unable to create proxy: %s", err->message);
652 static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service,
653 const gchar *path, const gchar *interface)
655 return (service_gproxy) ? service_gproxy :
656 __bt_hf_gdbus_init_service_proxy(service,
660 static char __bt_hf_agent_get_tx_power(char *address)
664 GError *error = NULL;
665 char result = READ_TX_POWER_MIN; /* default minimum */
667 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, g_obj_path,
668 BLUEZ_HF_INTERFACE_NAME);
670 ERR("Proxy is NULL");
674 ret = g_dbus_proxy_call_sync(proxy,
675 "GetTxPowerLevel", g_variant_new("(s)", address),
676 G_DBUS_CALL_FLAGS_NONE, -1,
679 ERR("DBus is failed");
681 /* Dbus gives error cause */
682 ERR("D-Bus API failure: errCode[%x], message[%s]",
683 error->code, error->message);
684 g_clear_error(&error);
688 g_variant_get(ret, "(y)", &result);
689 DBG("TX power level = %d", result);
690 g_variant_unref(ret);
694 static int __bt_hf_agent_gdbus_method_send(const char *service,
695 GVariant *path, const char *interface,
702 GError *error = NULL;
704 proxy = __bt_hf_gdbus_get_service_proxy(service, g_obj_path, interface);
706 return BT_HF_AGENT_ERROR_INTERNAL;
708 ret = g_dbus_proxy_call_sync(proxy,
710 G_DBUS_CALL_FLAGS_NONE, -1,
713 /* dBUS-RPC is failed */
714 ERR("dBUS-RPC is failed");
716 /* dBUS gives error cause */
717 ERR("D-Bus API failure: errCode[%x], message[%s]",
718 error->code, error->message);
720 g_clear_error(&error);
722 return BT_HF_AGENT_ERROR_INTERNAL;
725 g_variant_unref(ret);
727 return BT_HF_AGENT_ERROR_NONE;
730 static void __bt_hf_agent_release_queue(void)
733 bt_hf_agent_send_at_info *cmd;
736 len = g_slist_length(bt_hf_info.cmd_send_queue);
737 for (i = 0; i < len; ++i) {
738 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
739 if (cmd && cmd->context) {
740 DBG("Pending context found for %.6s[%d]",
741 cmd->at_cmd, cmd->id);
742 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_INTERNAL);
743 g_dbus_method_invocation_return_gerror(cmd->context, err);
746 if (cmd && cmd->timer_id)
747 g_source_remove(cmd->timer_id);
749 g_slist_free(bt_hf_info.cmd_send_queue);
750 bt_hf_info.cmd_send_queue = NULL;
754 static gboolean __bt_hf_monitor_timer_cb(gpointer data)
757 bt_hf_agent_send_at_info *cmd = data;
758 ERR_C("Monitor timer came becuase of timeout for sendflag %d, %s",
759 send_flag, cmd->at_cmd);
760 /* In the case of ATD, we have to inform the remote to end the call */
761 if (strstr(cmd->at_cmd, "ATD") || strstr(cmd->at_cmd, "BLDN")) {
762 INFO_C("Sending CHUP for remote call termination");
763 __bt_hf_send_only_without_queue(&bt_hf_info, BT_HF_END_CALL,
764 strlen(BT_HF_END_CALL));
765 /* Here there is a high posisbility that we do not get response
766 * for CHUP. Hence we need to decrement send_flag to process further
767 * incomming packets because we already incremented it in the CHUP case. */
771 /* In the case of ATD, prev_cmd will be always ATD, because we will not
772 * allow further commands. For safer side again set prev_cmd as ATD */
773 strncpy(prev_cmd, "ATD\0", BT_HF_CMD_BUF_SIZE - 1);
775 hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
783 gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
784 int count, gboolean pending_flag)
787 if (bt_hf_info.slc == FALSE)
791 DBG("*** Add Pending queue request for = %s **** ", at);
793 DBG("Add Pending queue respnse for = %s ", at);
795 bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
797 memcpy(cmd->at_cmd, at, count);
799 cmd->context = context;
800 cmd->pending = pending_flag;
801 bt_hf_info.cmd_send_queue = g_slist_append(bt_hf_info.cmd_send_queue,
803 len = g_slist_length(bt_hf_info.cmd_send_queue);
804 for (i = 0; i < len; ++i) {
805 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
806 DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id);
809 /* We need to have base timeout + tolerance value to process other request */
810 if (strstr(at, "ATD") || strstr(at, "BLDN")) {
811 /* Android 15 seconds timeout in case of ATD timeout in flight mode */
812 cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len,
813 __bt_hf_monitor_timer_cb, cmd);
815 cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len,
816 __bt_hf_monitor_timer_cb, cmd);
822 Below methods exposed to Applicatoins
824 static gboolean __bt_hf_agent_emit_signal(GDBusConnection *connection,
825 const char *path, const char *interface,
826 const char *signal_name, GVariant *param)
828 GError *error = NULL;
830 ret = g_dbus_connection_emit_signal(connection,
832 interface, signal_name,
836 /* dBUS gives error cause */
837 ERR("D-Bus API failure: errCode[%x], message[%s]",
838 error->code, error->message);
839 g_clear_error(&error);
842 INFO_C("Emit Signal [%s]", signal_name);
847 static gboolean __bt_hf_agent_emit_property_changed(
848 GDBusConnection *connection,
850 const char *interface,
856 GError *error = NULL;
858 ret = g_dbus_connection_emit_signal(connection,
859 NULL, path, interface,
861 g_variant_new("s(v)", name, property),
865 /* dBUS gives error cause */
866 ERR("D-Bus API failure: errCode[%x], message[%s]",
867 error->code, error->message);
868 g_clear_error(&error);
876 Below methods exposed to Bluez
879 static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
880 guint index, gint value)
882 GDBusConnection *conn;
884 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
886 ERR("Indicator is NULL");
893 conn = __bt_hf_get_gdbus_connection();
895 ERR("Unable to get connection");
899 INFO("Indicator name is %s, value = [%d]", name, value);
900 if (!strcmp(name, "\"call\"")) {
901 bt_hf_info->ciev_call_status = value;
903 __bt_hf_agent_emit_signal(conn,
904 BT_HF_AGENT_OBJECT_PATH,
905 BT_HF_SERVICE_INTERFACE,
906 "CallStarted", NULL);
907 bt_hf_info->is_dialing = FALSE;
908 bt_hf_info->call_active = TRUE;
909 } else if (bt_hf_info->call_active) {
910 __bt_hf_agent_emit_signal(conn,
911 BT_HF_AGENT_OBJECT_PATH,
912 BT_HF_SERVICE_INTERFACE,
914 bt_hf_info->call_active = FALSE;
917 } else if (!strcmp(name, "\"callsetup\"")) {
918 bt_hf_info->ciev_call_setup_status = value;
919 if (value == 0 && bt_hf_info->is_dialing) {
920 __bt_hf_agent_emit_signal(conn,
921 BT_HF_AGENT_OBJECT_PATH,
922 BT_HF_SERVICE_INTERFACE,
925 bt_hf_info->is_dialing = FALSE;
926 } else if (!bt_hf_info->is_dialing && value > 0)
927 bt_hf_info->is_dialing = TRUE;
929 if (bt_hf_info->ciev_call_status == 0 &&
930 bt_hf_info->ciev_call_setup_status == 0)
931 __bt_hf_agent_emit_signal(gdbus_conn,
932 BT_HF_AGENT_OBJECT_PATH,
933 BT_HF_SERVICE_INTERFACE,
936 } else if (!strcmp(name, "\"callheld\"")) {
937 if (value == 0) { /* No calls held*/
938 __bt_hf_agent_emit_signal(conn,
939 BT_HF_AGENT_OBJECT_PATH,
940 BT_HF_SERVICE_INTERFACE,
943 } else if (value == 1) {
944 /*Call is placed on hold or active/held calls swapped */
945 __bt_hf_agent_emit_signal(conn,
946 BT_HF_AGENT_OBJECT_PATH,
947 BT_HF_SERVICE_INTERFACE,
948 "CallsSwapped", NULL);
949 bt_hf_info->is_dialing = FALSE;
951 /*Call on hold, no active call*/
952 __bt_hf_agent_emit_signal(conn,
953 BT_HF_AGENT_OBJECT_PATH,
954 BT_HF_SERVICE_INTERFACE,
956 bt_hf_info->is_dialing = FALSE;
958 } else if (!strcmp(name, "\"service\""))
959 __bt_hf_agent_emit_property_changed(conn,
960 BT_HF_AGENT_OBJECT_PATH,
961 BT_HF_SERVICE_INTERFACE,
962 "RegistrationStatus",
963 g_variant_new("(q)", value));
964 else if (!strcmp(name, "\"signal\""))
965 __bt_hf_agent_emit_property_changed(conn,
966 BT_HF_AGENT_OBJECT_PATH,
967 BT_HF_SERVICE_INTERFACE, "SignalStrength",
968 g_variant_new("(q)", value));
969 else if (!strcmp(name, "\"roam\""))
970 __bt_hf_agent_emit_property_changed(conn,
971 BT_HF_AGENT_OBJECT_PATH,
972 BT_HF_SERVICE_INTERFACE, "RoamingStatus",
973 g_variant_new("(q)", value));
974 else if (!strcmp(name, "\"battchg\""))
975 __bt_hf_agent_emit_property_changed(conn,
976 BT_HF_AGENT_OBJECT_PATH,
977 BT_HF_SERVICE_INTERFACE, "BatteryCharge",
978 g_variant_new("(q)", value));
982 static gboolean __bt_hf_agent_launch_call_app(const char *launch_type,
989 app_manager_is_running(CALL_APP_ID, &is_running);
993 DBG_SECURE("Launch type = %s, number(%s)", launch_type, number);
997 ERR("bundle_create() Failed");
1001 bundle_add(b, "launch-type", launch_type);
1003 if (strlen(number) != 0)
1004 bundle_add(b, "number", number);
1006 bundle_add(b, "carrier-type", "BT");
1007 DBG("For 3G, carrier-type: BT has been added");
1009 aul_launch_app(CALL_APP_ID, b);
1017 static void __bt_hf_agent_handle_voice_activation(gint value)
1019 GDBusConnection *conn;
1021 conn = __bt_hf_get_gdbus_connection();
1023 ERR("Unable to get connection");
1027 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1028 BT_HF_SERVICE_INTERFACE,
1030 g_variant_new("(i)", value));
1035 static void __bt_hf_agent_handle_speaker_gain(gint value)
1037 GDBusConnection *conn;
1039 conn = __bt_hf_get_gdbus_connection();
1041 ERR("Unable to get connection");
1045 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1046 BT_HF_SERVICE_INTERFACE, "VolumeSpeaker",
1047 g_variant_new("(i)", value));
1052 static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info,
1055 GDBusConnection *conn;
1060 char fmt_str[BT_HF_FMT_STR_SIZE];
1061 int len = strlen(buf);
1063 DBG("__bt_hf_agent_handle_ccwa +");
1064 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1065 ERR("buf len %d is too long", len);
1069 if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
1070 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds",
1071 BT_HF_CALLER_NUM_SIZE - 1);
1072 if ((ptr = strstr(ccwa, "\"")) != NULL) {
1074 sep = strchr(number, '"');
1079 conn = __bt_hf_get_gdbus_connection();
1081 ERR("Unable to get connection");
1085 __bt_hf_agent_emit_signal(conn,
1086 BT_HF_AGENT_OBJECT_PATH,
1087 BT_HF_SERVICE_INTERFACE, "CallWaiting",
1088 g_variant_new("(s)", ccwa));
1090 ERR_SECURE("CCWA '%s' is Call Wating", buf);
1094 DBG("__bt_hf_agent_handle_ccwa -");
1098 static GSList *__bt_hf_prepare_call_list(const char *buf)
1100 GSList *call_list = NULL;
1106 char delim_sep[] = "\r\n";
1107 char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1109 hf_call_list_info_t *call_info;
1112 strncpy(temp_buf, buf, BT_HF_DATA_BUF_SIZE - 1);
1114 str = strtok_r(temp_buf, delim_sep, &sp);
1115 while (str != NULL) {
1116 if (!(strstr(str, "+CLCC:"))) {
1117 str = strtok_r(NULL, delim_sep, &sp);
1121 call_info = g_new0(hf_call_list_info_t, 1);
1123 /* str format : "+CLCC: %1d,%1d, %1d, %1d, %1d" */
1124 if ((ptr = strchr(str, ':')) != NULL) {
1125 call_info->idx = strtol(ptr + 1, &stop, 10);
1126 call_info->dir = strtol(stop + 1, &stop, 10);
1127 call_info->status = strtol(stop + 1, &stop, 10);
1128 call_info->mode = strtol(stop + 1, &stop, 10);
1129 call_info->multi_party = strtol(stop + 1, &stop, 10);
1131 DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n",
1132 call_info->idx, call_info->dir, call_info->status,
1133 call_info->mode, call_info->multi_party);
1136 ptr = strstr(str, "\"");
1138 temp = strstr(ptr + 1, "\"");
1141 DBG_SECURE("\tPhone Number = [%s]\n", ptr + 1);
1142 call_info->number = g_strdup(ptr + 1);
1144 if (strstr(temp + 1, ",")) {
1146 DBG("\tType = [%s]\n", temp);
1147 call_info->type = atoi(temp);
1151 /*In case of no phone no. in CLCC respnse, we should launch call application
1152 * with NULL string. By doing so "unknown" shall be displayed*/
1153 DBG("Phone number does not exist\n");
1154 call_info->number = g_strdup("");
1157 call_list = g_slist_append(call_list, call_info);
1158 str = strtok_r(NULL, delim_sep, &sp);
1164 static GSList *__bt_hf_get_call_list(bt_hf_agent_info_t *bt_hf_info)
1166 char buf[BT_HF_DATA_BUF_SIZE] = {0,};
1167 GSList *call_list = NULL;
1171 /* Send CLCC when the callsetup */
1172 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLLIST, buf,
1173 sizeof(BT_HF_CALLLIST) - 1);
1174 DBG_SECURE("Receive CLCC response buffer = '%s'", buf);
1176 call_list = __bt_hf_prepare_call_list(buf);
1181 static void __bt_hf_call_info_free(void *data)
1185 hf_call_list_info_t *call_info = data;
1186 g_free(call_info->number);
1192 static void __bt_hf_free_call_list(GSList *call_list)
1196 g_slist_free_full(call_list, __bt_hf_call_info_free);
1201 static void __bt_hf_launch_call_using_call_list(GSList *call_list,
1202 bt_hf_agent_info_t *bt_hf_info)
1205 const char *launch_type_str;
1206 hf_call_list_info_t *call_info;
1209 if (call_list == NULL)
1212 len = g_slist_length(call_list);
1215 call_info = g_slist_nth_data(call_list, len);
1217 /* Launch based on below conditions
1218 * DC - Active call which is initiated from H
1219 * MR - Alerting call which is initiated from H
1220 * MT - Incoming call */
1221 if (call_info->status == BT_HF_CALL_STAT_ACTIVE) {
1222 launch_type_str = "DC";
1224 if (call_info->dir == BT_HF_CALL_DIR_INCOMING)
1225 launch_type_str = "MT";
1227 launch_type_str = "MR";
1230 if (__bt_hf_agent_launch_call_app(launch_type_str,
1231 call_info->number) == FALSE)
1232 DBG("call app launching failed");
1237 static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list)
1243 hf_call_list_info_t *call_info;
1245 GVariantBuilder *builder;
1248 builder = g_variant_builder_new(G_VARIANT_TYPE("a(siiii)"));
1250 call_count = g_slist_length(call_list);
1251 DBG("Total call count = '%d'", call_count);
1253 while (call_count--) {
1254 call_info = g_slist_nth_data(call_list, call_count);
1255 INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d",
1256 call_info->idx, call_info->dir, call_info->status,
1257 call_info->mode, call_info->multi_party);
1258 caller = call_info->number;
1260 g_variant_builder_add(builder, "(siiii)",
1261 caller, call_info->dir, call_info->status,
1262 call_info->multi_party, call_info->idx);
1264 var_data = g_variant_new("(ia(siiii))",
1265 g_slist_length(call_list), builder);
1267 g_variant_builder_unref(builder);
1272 static void __bt_hf_clear_prev_sent_cmd(void)
1274 if (prev_cmd[0] != 0)
1275 ERR("No sent command");
1277 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
1282 static void __bt_hf_agent_send_call_status_info(GSList *call_list)
1284 GDBusConnection *conn;
1287 var_data = __bt_hf_agent_get_call_status_info(call_list);
1288 conn = __bt_hf_get_gdbus_connection();
1290 ERR("Unable to get connection");
1295 __bt_hf_agent_emit_signal(conn,
1296 BT_HF_AGENT_OBJECT_PATH,
1297 BT_HF_SERVICE_INTERFACE,
1302 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info)
1306 __bt_hf_lock_display(0);
1308 bt_hf_info->context = NULL;
1310 /* Send CLCC. The response will be handled in the handler */
1311 ret = __bt_hf_send_only(bt_hf_info, BT_HF_CALLLIST,
1312 sizeof(BT_HF_CALLLIST) - 1);
1314 ERR("Failed to send CLCC");
1316 __bt_hf_unlock_display();
1319 static void __bt_hf_agent_request_call_list_info(bt_hf_agent_info_t *bt_hf_info,
1323 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
1325 ERR("Indicator is NULL");
1329 DBG("name : %s", name);
1331 if ((strcmp(name, "\"callsetup\"") != 0) &&
1332 (strcmp(name, "\"call\"") != 0) &&
1333 (strcmp(name, "\"callheld\"") != 0))
1336 __bt_hf_lock_display(0);
1338 __bt_hf_agent_handle_call_list(bt_hf_info);
1340 __bt_hf_unlock_display();
1344 static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only)
1346 gchar buf[BT_HF_DATA_BUF_SIZE];
1347 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1350 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_AVAILABLE_CODEC,
1351 BT_HF_CODEC_ID_CVSD, BT_HF_CODEC_ID_MSBC);
1353 bt_hf_info->context = NULL;
1355 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1358 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
1361 if (!ret || !strstr(buf, "OK"))
1367 static int _hf_agent_codec_setup(const char *addr, guint codec_id)
1372 ERR("g_obj_path is NULL\n");
1373 return BT_HF_AGENT_ERROR_INTERNAL;
1377 case BT_HF_CODEC_ID_CVSD:
1378 INFO("Set NB parameters");
1379 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1380 g_variant_new("(ss)", "Handsfree", addr),
1381 BT_ADAPTER_INTERFACE,
1384 case BT_HF_CODEC_ID_MSBC:
1385 INFO("Set WBS parameters");
1386 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1387 g_variant_new("(ss)", "Handsfree", addr),
1388 BT_ADAPTER_INTERFACE,
1389 "SetWbsParameters");
1392 ret = BT_HF_AGENT_ERROR_INTERNAL;
1393 ERR("Invalid Codec\n");
1398 ERR("Failed to setup the Codec\n");
1400 current_codec_id = codec_id;
1405 static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info,
1408 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1411 if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) {
1412 INFO("Codec id doesn't match, so send available codec again");
1413 ret = __bt_hf_send_available_codec(bt_hf_info, 1);
1415 ERR("Failed to send avalable codec");
1419 /* HF should be ready accpet SCO connection before sending theresponse for
1420 "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */
1421 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id);
1423 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id);
1425 bt_hf_info->context = NULL;
1427 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1429 ERR("Failed to select the Codec");
1432 void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
1436 char s[BT_HF_DATA_BUF_SIZE] = {0, };
1437 gboolean hide = FALSE;
1439 gboolean has_clcc = FALSE;
1440 gboolean has_clip = FALSE;
1441 gboolean has_ccwa = FALSE;
1444 strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
1446 has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
1447 if (has_clcc == TRUE)
1449 has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
1450 if (has_clip == TRUE)
1452 has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
1455 /* +XSAT: 11,DISC */
1456 xsat_ptr = strstr(s, "11,DISC,");
1458 xsat_ptr = xsat_ptr + 8;
1460 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
1466 /* AT+XSAT=11,Q_CT,X,XXXX */
1467 xsat_ptr = strstr(s, "11,Q_CT,");
1469 xsat_ptr = xsat_ptr + 8;
1471 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
1472 if (x > 1) /* ignore 0 and 1 position */
1479 while (s[i] != '\0') {
1480 if (s[i] == '\r' || s[i] == '\n') {
1484 hide = hide ? FALSE : TRUE;
1485 else if ((has_clcc || has_clip || has_ccwa) && hide) {
1493 INFO("%s Buffer = %s, Length = %d ", message, s, strlen(s));
1498 static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1505 char fmt_str[BT_HF_FMT_STR_SIZE];
1507 DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
1509 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n",
1510 BT_HF_INDICATOR_DESCR_SIZE + 4 - 1);
1511 if ((ptr = strchr(buf, ':')) != NULL) {
1512 indicator = ptr + 1;
1513 sep = strchr(indicator, ',');
1516 index = atoi(indicator);
1518 __bt_hf_agent_handle_ind_change(bt_hf_info, index, value);
1520 if (bt_hf_info->ciev_call_status == 0 &&
1521 bt_hf_info->ciev_call_setup_status == 0)
1522 INFO("No active call");
1524 /* Request CLCC based on indicator change for call/callsetup/callHeld */
1525 __bt_hf_agent_request_call_list_info(bt_hf_info, index);
1527 DBG("--------- __bt_hf_agent_handler_ciev ------------");
1531 static void __bt_hf_agent_handle_ven_samsung(bt_hf_agent_info_t *bt_hf_info,
1532 gint app_id, const char *msg)
1534 /* Whomesoever wants need to handle it */
1535 char *sig_name = "SamsungXSAT";
1536 GDBusConnection *conn;
1538 conn = __bt_hf_get_gdbus_connection();
1540 ERR("Unable to get connection");
1544 __bt_hf_agent_emit_signal(conn,
1545 BT_HF_AGENT_OBJECT_PATH,
1546 BT_HF_SERVICE_INTERFACE,
1548 g_variant_new("(is)", app_id, msg));
1551 static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1553 DBG("++++++++ __bt_hf_agent_handler_ring ++++++++");
1554 DBG("---------__bt_hf_agent_handler_ring --------");
1559 static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1561 DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++");
1562 DBG("---------__bt_hf_agent_handler_clip --------");
1567 static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1569 DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++");
1573 if ((ptr = strstr(buf, "BVRA:")) != NULL) {
1574 value = strtol(ptr + 5, &stop, 10);
1575 __bt_hf_agent_handle_voice_activation(value);
1578 DBG("---------__bt_hf_agent_handler_bvra --------");
1582 static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1587 DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-");
1588 if ((ptr = strstr(buf, "BCS:")) != NULL) {
1589 codec_id = strtol(ptr + 4, &stop, 10);
1590 __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id);
1593 DBG("---------__bt_hf_agent_handler_bcs --------");
1597 static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1602 DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
1603 if ((ptr = strstr(buf, "VGS:")) != NULL) {
1604 value = strtol(ptr + 4, &stop, 10);
1605 __bt_hf_agent_handle_speaker_gain(value);
1608 DBG("---------__bt_hf_agent_handler_vgs --------");
1613 static int __bt_hf_agent_handler_ccwa(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1615 DBG("+++++++++ __bt_hf_agent_handler_ccwa ++++++++");
1616 __bt_hf_agent_handle_ccwa(bt_hf_info, buf);
1617 DBG("---------__bt_hf_agent_handler_ccwa --------");
1623 static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
1628 char fmt_str[BT_HF_CMD_BUF_SIZE];
1630 char *save_ptr = NULL;
1633 DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
1634 snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n",
1635 (int)(sizeof(msg) - 1));
1636 ptr = strstr(buf, "XSAT:");
1638 app_id = strtol(ptr + 5, &stop, 10);
1641 msg = strtok_r(stop + 1, "\\", &save_ptr);
1643 if (app_id || msg) {
1644 if (app_id == 2 && strstr(msg, "READTXPOWER")) {
1645 char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, };
1646 char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr);
1647 snprintf(cmd_buf, sizeof(cmd_buf), "AT+XSAT: 2,%d", power);
1648 bt_hf_agent_send_at_cmd(NULL, cmd_buf);
1650 __bt_hf_agent_handle_ven_samsung(bt_hf_info, app_id, msg);
1654 DBG("---------__bt_hf_agent_handler_xsat --------");
1659 static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info,
1662 DBG("+++++++++ __bt_hf_agent_handler_cme_error ++++++++");
1664 GDBusConnection *conn;
1666 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1667 conn = __bt_hf_get_gdbus_connection();
1669 ERR("Unable to get connection");
1673 __bt_hf_agent_emit_signal(conn,
1674 BT_HF_AGENT_OBJECT_PATH,
1675 BT_HF_SERVICE_INTERFACE,
1680 __bt_hf_clear_prev_sent_cmd();
1685 static int __bt_hf_agent_handler_response_ok(bt_hf_agent_info_t *bt_hf_info,
1688 DBG("+++++++++ __bt_hf_agent_handler_response_ok ++++++++");
1690 __bt_hf_clear_prev_sent_cmd();
1695 static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info,
1698 DBG("+++++++++ __bt_hf_agent_handler_response_err ++++++++");
1699 GDBusConnection *conn;
1701 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1702 conn = __bt_hf_get_gdbus_connection();
1704 ERR("Unable to get connection");
1708 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1709 BT_HF_SERVICE_INTERFACE,
1713 __bt_hf_clear_prev_sent_cmd();
1718 static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info,
1722 GDBusConnection *conn;
1724 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1725 conn = __bt_hf_get_gdbus_connection();
1727 ERR("Unable to get connection");
1731 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1732 BT_HF_SERVICE_INTERFACE,
1737 __bt_hf_clear_prev_sent_cmd();
1743 static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char *buffer)
1746 GSList *call_list = NULL;
1747 DBG("+++++++++ __bt_hf_agent_handler_clcc ++++++++");
1748 DBG_SECURE("Receive CLCC response buffer = '%s'", buffer);
1750 __bt_hf_lock_display(0);
1752 call_list = __bt_hf_prepare_call_list(buffer);
1754 if (call_list == NULL)
1757 __bt_hf_launch_call_using_call_list(call_list, bt_hf_info);
1759 __bt_hf_agent_send_call_status_info(call_list);
1761 __bt_hf_free_call_list(call_list);
1764 __bt_hf_unlock_display();
1765 DBG("---------__bt_hf_agent_handler_clcc --------");
1769 static struct hf_event hf_event_callbacks[] = {
1770 { "\r\n+CIEV:", __bt_hf_agent_handler_ciev },
1771 { "\r\nRING", __bt_hf_agent_handler_ring },
1772 { "\r\n+CLIP:", __bt_hf_agent_handler_clip },
1773 { "\r\n+BVRA:", __bt_hf_agent_handler_bvra },
1774 { "\r\n+BCS:", __bt_hf_agent_handler_bcs },
1775 { "\r\n+VGS:", __bt_hf_agent_handler_vgs },
1776 { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa },
1777 { "\r\n+XSAT:", __bt_hf_agent_handler_xsat },
1778 {"\r\n+CLCC:", __bt_hf_agent_handler_clcc },
1782 static struct hf_event hf_event_resp_callbacks[] = {
1783 { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error },
1784 { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok },
1785 { "ERROR", __bt_hf_agent_handler_response_err },
1786 { "SERR", __bt_hf_agent_handler_response_serr },
1790 bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info)
1794 bt_hf_agent_send_at_info *cmd;
1795 len = g_slist_length(bt_hf_info->cmd_send_queue);
1796 for (i = 0; i < len; ++i) {
1797 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i);
1798 DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id);
1800 len = g_slist_length(bt_hf_info->cmd_send_queue);
1801 DBG("Context queue length = %d", len);
1805 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
1807 bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
1808 DBG("NEXT[%d] Found %s, context = 0x%x, pending = %d", cmd->id,
1809 cmd->at_cmd, cmd->context, cmd->pending);
1813 DBG("**** Not found any pending command on list length %d ****", len);
1818 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1820 struct hf_event *ev;
1822 bt_hf_agent_send_at_info *cmd = NULL;
1824 __bt_hf_agent_print_at_buffer("Processing [Rx cmd]:", buf);
1826 for (ev = hf_event_resp_callbacks; ev->cmd; ev++) {
1827 if (strstr(buf, ev->cmd)) {
1830 DBG("Send flag value = %d(after)", send_flag);
1831 ret = ev->callback(bt_hf_info, buf);
1838 for (ev = hf_event_callbacks; ev->cmd; ev++) {
1839 if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) {
1840 ret = ev->callback(bt_hf_info, buf);
1848 cmd = __bt_hf_agent_find_next(bt_hf_info);
1850 if (cmd && cmd->context) {
1851 DBG("Pending context found for %.6s[%d]", cmd->at_cmd, cmd->id);
1852 g_dbus_method_invocation_return_value(cmd->context, NULL);
1854 g_source_remove(cmd->timer_id);
1860 cmd = __bt_hf_agent_find_next(bt_hf_info);
1862 if (cmd && cmd->pending && send_flag == 0) {
1863 DBG("Pending only found of %.6s[%d]", cmd->at_cmd, cmd->id);
1864 __bt_hf_send_only_without_queue(bt_hf_info,
1865 cmd->at_cmd, cmd->count);
1866 cmd->pending = FALSE;
1867 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
1869 DBG("Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
1872 DBG("Pending free for %.6s[%d] - send_flag = %d",
1873 cmd->at_cmd, cmd->id, send_flag);
1875 g_source_remove(cmd->timer_id);
1881 /* Need to process further pending */
1882 cmd = __bt_hf_agent_find_next(bt_hf_info);
1884 if (cmd->pending && send_flag == 0) {
1885 DBG("2nd Pending only found of %.6s[%d]",
1886 cmd->at_cmd, cmd->id);
1887 __bt_hf_send_only_without_queue(bt_hf_info,
1888 cmd->at_cmd, cmd->count);
1889 cmd->pending = FALSE;
1891 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
1893 DBG("2nd Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
1899 static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf)
1903 int cmd_buf_len = 0;
1904 char *pos_start, *pos_end;
1905 const char *datap = buf;
1907 cmd_buf_len = strlen(cmd_buf);
1908 buf_length = strlen(buf);
1909 DBG("buf_length = %d, cmd_buf_len = %d", buf_length, cmd_buf_len);
1911 if (buf_length > 0 && strstr(datap, "+CLCC")) {
1912 pos_start = strstr(datap, "\r\n");
1913 if (pos_start == NULL) {
1914 ERR("Invalid AT command signature..\n");
1918 pos_end = g_strrstr(datap, "+CLCC");
1919 if (pos_end == NULL) {
1920 ERR("Invalid AT command signature..\n");
1923 pos_end = strstr(pos_end, "\r\n");
1924 cmd_length = (pos_end - pos_start) + 2;
1925 INFO("CLCC balance Cmd Length = %d\n", cmd_length);
1926 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
1927 cmd_buf[cmd_buf_len + cmd_length] = '\0';
1929 if (strstr(cmd_buf, "\r\nOK\r\n")) {
1930 pos_end = strstr(datap, "\r\nOK\r\n");
1931 cmd_length = (pos_end - pos_start);
1932 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
1933 cmd_buf[cmd_buf_len + cmd_length] = '\0';
1934 INFO("New CLCC balance Cmd Length = %d", cmd_length);
1941 static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1945 char *pos_start, *pos_end;
1947 gchar cmd_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1948 const char *datap = buf;
1950 __bt_hf_agent_print_at_buffer("[HF AT CMD] Recv >>>>>:", buf);
1952 buf_length = strlen(buf);
1954 while (buf_length > 0) {
1955 pos_start = strstr(datap, "\r\n");
1956 if (pos_start == NULL) {
1957 ERR("Invalid AT command start signature..\n");
1962 pos_end = strstr(datap, "\r\n");
1963 if (pos_end == NULL) {
1964 ERR("Invalid AT command end signature..\n");
1967 cmd_length = (pos_end - pos_start) + 2;
1968 DBG("Cmd Length = %d\n", cmd_length);
1970 memcpy(cmd_buf, pos_start, cmd_length);
1971 cmd_buf[cmd_length] = '\0';
1973 buf_length = buf_length - cmd_length;
1974 datap = datap + cmd_length - 2;
1976 /* We need to pass all the CLCC's together to its handler */
1977 if (strstr(cmd_buf, "+CLCC")) {
1978 tmp = hf_handle_append_clcc_buff(cmd_buf, datap);
1980 buf_length = buf_length - tmp;
1982 hf_handle_rx_at_cmd(bt_hf_info, cmd_buf);
1983 DBG("Pending buf_length = %d\n", buf_length);
1988 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
1989 bt_hf_agent_info_t *bt_hf_info)
1991 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
1993 GError *gerr = NULL;
1994 gboolean recvd_ok = FALSE;
1995 gboolean recvd_error = FALSE;
1996 gboolean recvd_sec_error = FALSE;
1998 if (cond & (G_IO_ERR | G_IO_HUP)) {
1999 ERR("ERR or HUP on RFCOMM socket");
2000 INFO_C("### Disconnected [HF role] [Terminated by remote dev]");
2001 is_hf_connected = FALSE;
2002 bt_hf_info->slc = FALSE;
2003 __bt_hf_agent_release();
2007 if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, &gerr)
2008 != G_IO_STATUS_NORMAL) {
2010 ERR("Read failed, cond = [%d], Err msg = [%s]",
2011 cond, gerr->message);
2017 recvd_ok = NULL != strstr(buf, BT_HF_OK_RESPONSE);
2018 recvd_error = NULL != strstr(buf, BT_HF_ERROR_RESPONSE);
2019 recvd_sec_error = NULL != strstr(buf, BT_HF_SEC_ERROR_RESPONSE);
2020 DBG("<-------Received data --send flag status = %d ----->", send_flag);
2022 /* Once service level connection is established we need to handle
2023 * all the intermediate AT commands */
2024 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2028 strncat(global_buff, buf,
2029 (BT_AT_COMMAND_BUFFER_MAX - 1) - strlen(global_buff));
2030 if (!(recvd_ok || recvd_error || recvd_sec_error)) {
2031 __bt_hf_agent_print_at_buffer("Concat ()", global_buff);
2033 DBG("*** Received terminator.. process Rx buffer ***");
2034 hf_handle_rx_at_buff(bt_hf_info, global_buff);
2035 memset(global_buff, 0, sizeof(global_buff));
2038 INFO("*** Received Direct AT buffer packet handling ****");
2039 hf_handle_rx_at_buff(bt_hf_info, buf);
2044 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info)
2046 bt_hf_info->watch_id = g_io_add_watch(bt_hf_info->io_chan,
2047 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2048 (GIOFunc) __bt_hf_agent_data_cb, bt_hf_info);
2051 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info)
2053 if (bt_hf_info->watch_id > 0) {
2054 g_source_remove(bt_hf_info->watch_id);
2055 bt_hf_info->watch_id = 0;
2059 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
2066 status = g_io_channel_write_chars(io, data, count, &written,
2068 if (status != G_IO_STATUS_NORMAL)
2077 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
2078 gchar *data, gsize count)
2080 GIOChannel *io_chan = bt_hf_info->io_chan;
2081 if (!__bt_hf_channel_write(io_chan, data, count))
2084 g_io_channel_flush(io_chan, NULL);
2086 if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
2087 INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
2088 count, count - 6, "ATDXXXXXXX");
2089 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
2091 INFO("No queue....Send only buffer size =[%d] - Send <<<<<| %s",
2096 /* DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2097 * send_flag, count, data); */
2102 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
2105 gboolean pending = FALSE;
2106 GIOChannel *io_chan = bt_hf_info->io_chan;
2111 __bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
2116 if (!__bt_hf_channel_write(io_chan, data, count))
2119 g_io_channel_flush(io_chan, NULL);
2121 if (count > 2 && data[2] == 'D') /* ATDXXXXX */
2122 INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
2123 count, count - 6, "ATDXXXXXXX");
2125 INFO("Send only buffer size =[%d] - Send <<<<<| %s", count, data);
2128 DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2129 send_flag, count, data);
2133 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
2134 gchar *data, gchar *response, gsize count)
2136 GIOChannel *io_chan = bt_hf_info->io_chan;
2138 gboolean recvd_ok = FALSE;
2139 gboolean recvd_error = FALSE;
2140 gboolean recvd_sec_error = FALSE;
2141 gchar *resp_buf = response;
2142 gsize toread = BT_HF_DATA_BUF_SIZE - 1;
2147 GDBusConnection *conn;
2149 /* Should not send cmds if DUT send a command and wait the response */
2150 if (prev_cmd[0] != 0) {
2151 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
2155 memset(resp_buf, 0, BT_HF_DATA_BUF_SIZE);
2157 if (!__bt_hf_channel_write(io_chan, data, count))
2160 g_io_channel_flush(io_chan, NULL);
2162 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send <<<<<:", data);
2164 fd = g_io_channel_unix_get_fd(io_chan);
2166 p.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
2168 /* Maximun 8 seconds of poll or 8 minus no of cmd received */
2169 for (i = 1; i <= MAX_WAITING_DELAY; i++) {
2170 DBG("Loop Counter = %d", i);
2172 err = poll(&p, 1, 1000);
2174 ERR("Loop Counter = %d, >>>> Poll error happen", i);
2176 } else if (err == 0) {
2177 INFO("Loop Counter = %d, >>>> Poll Timeout", i);
2180 if (p.revents & (POLLERR | POLLHUP | POLLNVAL)) {
2181 ERR("Loop Counter = %d, >> Poll ERR/HUP/INV (%d)",
2184 conn = __bt_hf_get_gdbus_connection();
2186 ERR("Unable to get connection");
2190 __bt_hf_agent_emit_signal(conn,
2191 BT_HF_AGENT_OBJECT_PATH,
2192 BT_HF_SERVICE_INTERFACE,
2194 g_variant_new("(s)",
2195 bt_hf_info->remote_addr));
2197 bt_hf_info->state = BT_HF_STATE_DISCONNECTED;
2201 if (p.revents & POLLIN) {
2202 rd_size = read(fd, resp_buf, toread);
2203 resp_buf[rd_size] = '\0';
2204 DBG_SECURE("size = %d, Buffer=[%s]", rd_size, resp_buf);
2205 recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
2206 recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
2207 recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
2209 resp_buf += rd_size;
2212 if (recvd_ok || recvd_error || recvd_sec_error) {
2213 DBG("Break Loop Counter = %d", i);
2219 /* Once service level connection is established we need to handle
2220 * all the intermediate AT commands */
2221 if (bt_hf_info->state == BT_HF_STATE_CONNECTED)
2222 hf_handle_rx_at_buff(bt_hf_info, response);
2226 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indices)
2228 struct indicator *ind;
2229 gchar *cur = names - 1;
2230 GSList *list = indices;
2233 DBG("Indicator buffer = %s", names);
2234 __bt_hf_agent_print_at_buffer("Indicator names :", names);
2235 while (cur != NULL) {
2237 next = strstr(cur, ",(");
2238 ind = g_new0(struct indicator, 1);
2239 g_strlcpy(ind->descr, cur, BT_HF_INDICATOR_DESCR_SIZE);
2240 ind->descr[(intptr_t) next - (intptr_t) cur] = '\0';
2241 list = g_slist_append(list, (gpointer) ind);
2242 cur = strstr(next + 1, ",(");
2247 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices)
2250 struct indicator *ind;
2251 GSList *runner = indices;
2253 gchar *cur = values - 1;
2255 DBG("Indicator string = %s", values);
2256 __bt_hf_agent_print_at_buffer("Indicator values :", values);
2257 while (cur != NULL) {
2259 val = strtol(cur, &stop, 10);
2260 cur = strchr(cur, ',');
2261 ind = g_slist_nth_data(runner, 0);
2263 runner = g_slist_next(runner);
2268 static guint __bt_hf_get_hold_mpty_features(gchar *features)
2272 if (strstr(features, "0"))
2273 result |= BT_HF_CHLD_0;
2275 if (strstr(features, "1"))
2276 result |= BT_HF_CHLD_1;
2278 if (strstr(features, "1x"))
2279 result |= BT_HF_CHLD_1x;
2281 if (strstr(features, "2"))
2282 result |= BT_HF_CHLD_2;
2284 if (strstr(features, "2x"))
2285 result |= BT_HF_CHLD_2x;
2287 if (strstr(features, "3"))
2288 result |= BT_HF_CHLD_3;
2290 if (strstr(features, "4"))
2291 result |= BT_HF_CHLD_4;
2296 static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2298 bt_hf_agent_info_t *bt_hf_info = user_data;
2299 GDBusConnection *conn;
2302 if (cond & G_IO_NVAL)
2305 if (cond & (G_IO_HUP | G_IO_ERR)) {
2306 g_io_channel_shutdown(chan, TRUE, NULL);
2307 close(bt_hf_info->cli_sco_fd);
2308 g_io_channel_unref(chan);
2309 DBG("Emit AudioDisconnected Signal");
2311 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2313 conn = __bt_hf_get_gdbus_connection();
2315 ERR("Unable to get connection");
2318 __bt_hf_agent_emit_signal(conn,
2319 BT_HF_AGENT_OBJECT_PATH,
2320 BT_HF_SERVICE_INTERFACE,
2321 "AudioDisconnected", NULL);
2329 static gboolean __bt_agent_query_and_update_call_list(gpointer data)
2332 bt_hf_agent_info_t *bt_hf_info = data;
2334 if (bt_hf_info->cli_sco_fd >= 0)
2335 __bt_hf_agent_handle_call_list(bt_hf_info);
2337 INFO("SCO Audio is already disconnected");
2344 static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2346 bt_hf_agent_info_t *bt_hf_info = user_data;
2350 GDBusConnection *conn;
2352 INFO("Incoming SCO....");
2354 if (cond & G_IO_NVAL)
2357 sco_skt = g_io_channel_unix_get_fd(chan);
2359 if (cond & (G_IO_HUP | G_IO_ERR)) {
2364 cli_sco_sock = accept(sco_skt, NULL, NULL);
2365 if (cli_sco_sock < 0)
2368 bt_hf_info->cli_sco_fd = cli_sco_sock;
2370 sco_io = g_io_channel_unix_new(cli_sco_sock);
2371 g_io_channel_set_close_on_unref(sco_io, TRUE);
2372 g_io_channel_set_encoding(sco_io, NULL, NULL);
2373 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2374 g_io_channel_set_buffered(sco_io, FALSE);
2376 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2377 __bt_hf_agent_sco_conn_cb, bt_hf_info);
2379 /* S-Voice app requires the AudioConnected signal earlier */
2380 DBG("Emit AudioConnected Signal");
2382 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
2384 conn = __bt_hf_get_gdbus_connection();
2386 ERR("Unable to get connection");
2390 __bt_hf_agent_emit_signal(conn,
2391 BT_HF_AGENT_OBJECT_PATH,
2392 BT_HF_SERVICE_INTERFACE,
2393 "AudioConnected", NULL);
2395 /* In the case of incoming call, the call app is already launched,
2396 * hence AudioConnected signal is enough to update the call status.
2397 * In the case of outgoing call we need to lauch the callapp.
2400 g_idle_add(__bt_agent_query_and_update_call_list, bt_hf_info);
2405 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
2406 const char *address)
2411 ret_if(address == NULL);
2412 ret_if(addr == NULL);
2414 for (i = 0; i < 6; i++) {
2415 addr[5 - i] = strtol(address, &ptr, 16);
2416 if (ptr[0] != '\0') {
2425 static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
2427 struct sockaddr_sco addr;
2429 bdaddr_t bd_addr = {{0},};
2432 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2436 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
2438 ERR("Can't create socket:\n");
2442 /* Bind to local address */
2443 memset(&addr, 0, sizeof(addr));
2444 addr.sco_family = AF_BLUETOOTH;
2446 DBG("Bind to address %s", bt_hf_info->remote_addr);
2448 _bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
2449 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2451 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2452 ERR("Can't bind socket:\n");
2456 if (listen(sco_skt, 1)) {
2457 ERR("Can not listen on the socket:\n");
2461 sco_io = g_io_channel_unix_new(sco_skt);
2462 g_io_channel_set_close_on_unref(sco_io, TRUE);
2463 g_io_channel_set_encoding(sco_io, NULL, NULL);
2464 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2465 g_io_channel_set_buffered(sco_io, FALSE);
2467 bt_hf_info->sco_fd = sco_skt;
2468 bt_hf_info->sco_io_chan = sco_io;
2470 bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
2471 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
2473 g_io_channel_unref(sco_io);
2482 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
2484 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2487 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
2488 sizeof(BT_HF_INDICATORS_SUPP) - 1);
2489 if (!ret || !strstr(buf, "+CIND:"))
2492 bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
2497 static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
2502 if (bt_hf_info == NULL || cmd == NULL) {
2503 ERR("Invalid parameter");
2507 ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
2509 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
2510 ret = g_strlcat(cmd, "0,", cmd_size);
2511 if (ret >= cmd_size) {
2512 ERR("Too many indices");
2518 cmd[ret - 1] = '\0';
2519 DBG("BIA Str : %s", cmd);
2521 ret = g_strlcat(cmd, "\r", cmd_size);
2522 if (ret >= cmd_size) {
2523 ERR("Too many indices");
2530 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
2532 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2538 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
2539 sizeof(BT_HF_INDICATORS_VAL) - 1);
2540 if (!ret || !strstr(buf, "+CIND:"))
2543 /* if buf has other command prefix, skip it */
2544 str = strstr(buf, "+CIND");
2548 bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
2550 /* Parse the updated value */
2551 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
2552 struct indicator *ind = l->data;
2554 DBG("Index is NULL");
2558 if (0 == g_strcmp0(ind->descr, "\"call\"")) {
2559 DBG("CIND Match found index = %d, %s, value = %d",
2560 index, ind->descr, ind->value);
2561 bt_hf_info->ciev_call_status = ind->value;
2562 if (ind->value > 0) {
2563 bt_hf_info->is_dialing = FALSE;
2564 bt_hf_info->call_active = TRUE;
2566 } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
2567 DBG("CIND Match found index = %d, %s, value = %d",
2568 index, ind->descr, ind->value);
2569 bt_hf_info->ciev_call_setup_status = ind->value;
2570 if (!bt_hf_info->is_dialing && ind->value > 0)
2571 bt_hf_info->is_dialing = TRUE;
2578 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
2580 gchar buf[BT_HF_DATA_BUF_SIZE];
2581 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
2585 guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
2586 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
2587 BT_HF_FEATURE_CLI_PRESENTATION |
2588 BT_HF_FEATURE_VOICE_RECOGNITION |
2589 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
2590 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
2592 if (TIZEN_PROFILE_WEARABLE)
2593 feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
2595 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
2596 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
2601 buf_ptr = strstr(buf, "\r\n+BRSF:");
2602 if (buf_ptr == NULL)
2605 buf_ptr = strstr(buf_ptr, "BRSF:");
2606 bt_hf_info->ag_features = strtol(buf_ptr + 5, &stop, 10);
2609 if (!ret || !bt_hf_info->ag_features)
2611 INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
2613 if (TIZEN_PROFILE_WEARABLE) {
2614 if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
2615 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
2616 if (ret != BT_HF_AGENT_ERROR_NONE)
2617 ERR("Unable to set the default WBC codec");
2619 ret = __bt_hf_send_available_codec(bt_hf_info, 0);
2624 /* Default codec is NB */
2625 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
2626 if (ret != BT_HF_AGENT_ERROR_NONE)
2627 ERR("Unable to set the default NBC codec");
2630 ret = __bt_get_supported_indicators(bt_hf_info);
2635 ret = __bt_get_current_indicators(bt_hf_info);
2639 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
2640 sizeof(BT_HF_INDICATORS_ENABLE) - 1);
2641 if (!ret || !strstr(buf, "OK"))
2644 if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
2645 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
2646 buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
2647 if (!ret || !strstr(buf, "+CHLD:")) {
2648 ERR("Unable to get the CHLD Supported info");
2651 bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
2654 bt_hf_info->hold_multiparty_features = 0;
2656 INFO("Service layer connection successfully established...!");
2658 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
2659 sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
2660 __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
2661 sizeof(BT_HF_CARRIER_FORMAT) - 1);
2662 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
2663 sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
2665 if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
2666 __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
2667 sizeof(BT_HF_NREC) - 1);
2669 if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
2670 __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
2671 buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
2673 if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
2674 __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
2676 ERR("__bt_get_bia_cmd is failed");
2678 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
2679 sizeof(BT_HF_XSAT) - 1);
2681 DBG("sent BT_HF_XSAT");
2683 ERR("BT_HF_XSAT sending failed");
2685 /* send Bluetooth Samsung Support Feature cmd */
2686 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
2687 sizeof(BT_HF_BSSF) - 1);
2689 INFO("SLC completed with all commands");
2691 ERR("BT_HF_BSSF sending failed");
2693 bt_hf_info->slc = TRUE;
2696 memset(global_buff, 0, sizeof(global_buff));
2700 static void __bt_hf_agent_sigterm_handler(int signo)
2702 ERR_C("***** Signal handler came with signal %d *****", signo);
2703 GDBusConnection *conn;
2705 conn = __bt_hf_get_gdbus_connection();
2707 ERR("Unable to get connection");
2711 __bt_hf_agent_emit_signal(conn,
2712 BT_HF_AGENT_OBJECT_PATH,
2713 BT_HF_SERVICE_INTERFACE,
2715 DBG("CallEnded Signal done");
2717 g_main_loop_quit(gmain_loop);
2721 INFO_C("Terminating HF agent");
2726 static void __bt_convert_addr_type_to_rev_string(char *address,
2727 unsigned char *addr)
2729 ret_if(address == NULL);
2730 ret_if(addr == NULL);
2732 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
2733 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
2734 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
2738 static gboolean __bt_hf_agent_release_after(gpointer user_data)
2740 if (__bt_hf_agent_release() == FALSE)
2741 ERR("Unable to release hf connection");
2746 static gboolean __bt_agent_request_service_level_conn(gpointer data)
2749 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2750 GDBusConnection *conn;
2753 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
2755 if (!__bt_establish_service_level_conn(&bt_hf_info)) {
2756 ERR("Service Level Connection is fail");
2758 conn = __bt_hf_get_gdbus_connection();
2760 remote_addr = bt_hf_info.remote_addr;
2761 __bt_hf_agent_emit_signal(conn,
2762 BT_HF_AGENT_OBJECT_PATH,
2763 BT_HF_SERVICE_INTERFACE,
2765 g_variant_new("(s)", remote_addr));
2767 bt_hf_info.state = BT_HF_STATE_CONNECTED;
2769 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2770 DBG("BT device state is : 0x%X", bt_device_state);
2771 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2772 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2773 ERR("vconf_set_int failed");
2775 ERR("vconf_get_int failed");
2778 g_idle_add(__bt_hf_agent_release_after, NULL);
2783 bt_hf_info.state = BT_HF_STATE_CONNECTED;
2785 __bt_hf_agent_sco_accept(&bt_hf_info);
2787 __bt_hf_agent_start_watch(&bt_hf_info);
2789 remote_addr = bt_hf_info.remote_addr;
2791 INFO_SECURE("Address is : %s", remote_addr);
2792 INFO_C("### Connected [HF role]");
2794 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2795 DBG("BT device state is : 0x%X", bt_device_state);
2796 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2798 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2799 ERR("vconf_set_int failed");
2801 ERR("vconf_get_int failed");
2804 conn = __bt_hf_get_gdbus_connection();
2806 ERR("Unable to get connection");
2810 __bt_hf_agent_emit_signal(conn,
2811 BT_HF_AGENT_OBJECT_PATH,
2812 BT_HF_SERVICE_INTERFACE,
2814 g_variant_new("(s)", remote_addr));
2816 /* Request the call list and launch call app if required */
2817 __bt_hf_agent_handle_call_list(&bt_hf_info);
2824 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
2828 struct sockaddr_remote address;
2829 socklen_t address_len;
2830 bt_hf_info.path = g_strdup(obj_path);
2832 INFO_C("**** New HFP connection ****");
2834 is_hf_connected = TRUE;
2836 address_len = sizeof(address);
2837 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2838 ERR("BD_ADDR is NULL");
2840 DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
2842 bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
2843 flags = g_io_channel_get_flags(bt_hf_info.io_chan);
2845 flags &= ~G_IO_FLAG_NONBLOCK;
2846 flags &= G_IO_FLAG_MASK;
2847 g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
2848 g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
2849 g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
2851 bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2852 __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
2853 address.remote_bdaddr.b);
2855 g_idle_add(__bt_agent_request_service_level_conn, NULL);
2860 static void __bt_hf_agent_indicator_free(gpointer mem)
2865 static gboolean __bt_hf_agent_release(void)
2867 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2868 GDBusConnection *conn;
2870 if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
2871 ERR("hf is already disconnected");
2875 if (bt_hf_info.indies) {
2876 g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
2877 bt_hf_info.indies = NULL;
2880 if (bt_hf_info.io_chan) {
2881 g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
2882 g_io_channel_unref(bt_hf_info.io_chan);
2883 bt_hf_info.io_chan = NULL;
2886 if (bt_hf_info.sco_watch_id > 0) {
2887 g_source_remove(bt_hf_info.sco_watch_id);
2888 bt_hf_info.sco_watch_id = 0;
2891 bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
2893 __bt_hf_agent_release_queue();
2895 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
2896 DBG("BT device state is : 0x%X", bt_device_state);
2897 bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
2899 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
2900 ERR("vconf_set_int failed");
2902 ERR("vconf_get_int failed");
2905 __bt_hf_agent_stop_watch(&bt_hf_info);
2906 conn = __bt_hf_get_gdbus_connection();
2908 ERR("Unable to get connection");
2912 __bt_hf_agent_emit_signal(conn,
2913 BT_HF_AGENT_OBJECT_PATH,
2914 BT_HF_SERVICE_INTERFACE,
2916 g_variant_new("(s)", bt_hf_info.remote_addr));
2918 g_free(bt_hf_info.path);
2919 bt_hf_info.path = NULL;
2921 g_free(bt_hf_info.remote_addr);
2922 bt_hf_info.remote_addr = NULL;
2924 is_hf_connected = FALSE;
2929 static gboolean __bt_hf_agent_connection_release(void)
2931 return __bt_hf_agent_release();
2934 static int __bt_hf_register_profile(const char *uuid, uint16_t version,
2935 const char *name, const char *object, uint16_t features)
2940 GError *error = NULL;
2941 GVariantBuilder *builder;
2944 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
2945 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
2948 return BT_HF_AGENT_ERROR_INTERNAL;
2950 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2952 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2954 g_variant_builder_add(builder, "{sv}",
2955 "Name", g_variant_new("s",
2957 g_variant_builder_add(builder, "{sv}",
2958 "Version", g_variant_new("q", version));
2960 g_variant_builder_add(builder, "{sv}",
2961 "features", g_variant_new("q", features));
2963 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
2964 g_variant_new("(osa{sv})", path,
2965 HFP_HF_UUID, builder),
2966 G_DBUS_CALL_FLAGS_NONE, -1,
2969 g_variant_builder_unref(builder);
2972 /* dBUS-RPC is failed */
2973 ERR("dBUS-RPC is failed");
2974 if (error != NULL) {
2975 /* dBUS gives error cause */
2976 ERR("D-Bus API failure: errCode[%x], message[%s]",
2977 error->code, error->message);
2978 g_clear_error(&error);
2981 return BT_HF_AGENT_ERROR_INTERNAL;
2983 g_variant_unref(ret);
2987 return BT_HF_AGENT_ERROR_NONE;
2990 static void __bt_hf_agent_register(void)
2995 uint16_t version = hf_ver;
2996 uint16_t features = bt_hf_info.feature;
2998 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
2999 name = g_strdup("Hands-Free");
3001 ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
3004 ERR("Error in register");
3013 static void __bt_hf_agent_unregister(void)
3017 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3020 __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
3021 g_variant_new("(o)", path),
3022 BLUEZ_HF_INTERFACE_NAME,
3034 static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
3035 const gchar *sender_name,
3036 const gchar *object_path,
3037 const gchar *interface_name,
3038 const gchar *signal_name,
3039 GVariant *parameters,
3045 GVariant *optional_param;
3047 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3049 g_variant_get(parameters, "(&o@a{sa{sv}})",
3050 &path, &optional_param);
3052 ERR("Invalid adapter path");
3056 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3057 g_obj_path = g_strdup(path);
3058 INFO("Adapter Path = [%s]", path);
3059 __bt_hf_agent_register();
3061 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
3062 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
3064 __bt_hf_agent_unregister();
3069 static void __bt_hf_agent_dbus_init(void)
3071 GDBusConnection *conn;
3075 conn = __bt_hf_get_gdbus_connection();
3077 ERR("Error in creating the gdbus connection\n");
3080 if (!__bt_hf_register_profile_methods()) {
3081 ERR("Error in register_profile_methods\n");
3085 interface_added_sig_id = g_dbus_connection_signal_subscribe(conn,
3086 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0,
3087 __bt_hf_agent_filter_cb, NULL, NULL);
3089 interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
3090 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
3091 __bt_hf_agent_filter_cb, NULL, NULL);
3097 static void __bt_hf_agent_dbus_deinit(void)
3100 if (service_gproxy) {
3101 g_object_unref(service_gproxy);
3102 service_gproxy = NULL;
3106 if (interface_added_sig_id > 0)
3107 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3108 interface_added_sig_id);
3110 if (interface_removed_sig_id > 0)
3111 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3112 interface_removed_sig_id);
3114 interface_added_sig_id = 0;
3115 interface_removed_sig_id = 0;
3117 g_object_unref(gdbus_conn);
3123 static int _hf_agent_answer_call(GDBusMethodInvocation *context)
3128 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3129 ERR("HF not Connected");
3130 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3132 bt_hf_info.context = context;
3134 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
3135 sizeof(BT_HF_ANSWER_CALL) - 1);
3137 return BT_HF_AGENT_ERROR_INTERNAL;
3140 return BT_HF_AGENT_ERROR_NONE;
3144 static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
3149 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3150 ERR("HF not Connected");
3151 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3154 bt_hf_info.context = context;
3156 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
3157 sizeof(BT_HF_END_CALL) - 1);
3159 return BT_HF_AGENT_ERROR_INTERNAL;
3162 return BT_HF_AGENT_ERROR_NONE;
3165 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
3168 char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
3170 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3171 ERR("HF not Connected");
3172 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3175 bt_hf_info.context = context;
3177 if (strlen(no) > 0) {
3178 snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
3180 if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
3181 && bt_hf_info.ciev_call_setup_status == 0) {
3182 INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
3183 ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
3187 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3190 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3191 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
3194 return BT_HF_AGENT_ERROR_INTERNAL;
3196 return BT_HF_AGENT_ERROR_NONE;
3199 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3200 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
3202 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
3203 sizeof(BT_HF_REDIAL) - 1);
3205 return BT_HF_AGENT_ERROR_INTERNAL;
3207 return BT_HF_AGENT_ERROR_NONE;
3210 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
3215 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3216 ERR("HF not Connected");
3217 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3220 snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
3222 bt_hf_info.context = context;
3224 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3226 return BT_HF_AGENT_ERROR_INTERNAL;
3229 return BT_HF_AGENT_ERROR_NONE;
3232 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
3237 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3238 ERR("HF not Connected");
3239 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3242 if (gain > BT_HF_MAX_SPEAKER_GAIN)
3243 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3245 snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
3247 bt_hf_info.context = context;
3249 ret = __bt_hf_send_only(&bt_hf_info, buf,
3252 return BT_HF_AGENT_ERROR_INTERNAL;
3254 return BT_HF_AGENT_ERROR_NONE;
3258 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
3263 if (strlen(dtmf) <= 0)
3264 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3266 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3267 ERR("HF not Connected");
3268 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3271 snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
3273 bt_hf_info.context = context;
3275 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3277 return BT_HF_AGENT_ERROR_INTERNAL;
3280 return BT_HF_AGENT_ERROR_NONE;
3284 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
3288 if (strlen(cmd) <= 0)
3289 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3291 bt_hf_info.context = context;
3293 ret = __bt_hf_send_only(&bt_hf_info, cmd,
3296 return BT_HF_AGENT_ERROR_INTERNAL;
3298 return BT_HF_AGENT_ERROR_NONE;
3301 static gboolean bt_hf_agent_sco_disconnect(void)
3304 GDBusConnection *conn;
3306 close(bt_hf_info.cli_sco_fd);
3307 bt_hf_info.cli_sco_fd = -1;
3309 DBG("Emit AudioDisconnected Signal");
3310 conn = __bt_hf_get_gdbus_connection();
3312 ERR("Unable to get connection");
3316 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
3318 __bt_hf_agent_emit_signal(conn,
3319 BT_HF_AGENT_OBJECT_PATH,
3320 BT_HF_SERVICE_INTERFACE,
3321 "AudioDisconnected", NULL);
3326 static GVariant *bt_hf_agent_request_call_list(void)
3328 GSList *call_list = NULL;
3332 call_list = __bt_hf_get_call_list(&bt_hf_info);
3334 INFO("call list is NULL");
3338 var_data = __bt_hf_agent_get_call_status_info(call_list);
3339 __bt_hf_free_call_list(call_list);
3345 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
3349 char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
3354 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3356 if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
3357 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3359 /* Should not send cmds if DUT has sent a command and waiting for response */
3360 if (prev_cmd[0] != 0) {
3361 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
3362 return BT_HF_AGENT_ERROR_INTERNAL;
3365 strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
3366 strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
3368 bt_hf_info.context = context;
3370 ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
3372 return BT_HF_AGENT_ERROR_INTERNAL;
3375 return BT_HF_AGENT_ERROR_NONE;
3378 static uint32_t __bt_hf_agent_get_hf_features(void)
3380 uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
3381 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
3382 BT_HF_FEATURE_CLI_PRESENTATION |
3383 BT_HF_FEATURE_VOICE_RECOGNITION |
3384 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3385 BT_HF_FEATURE_ENHANCED_CALL_STATUS |
3386 BT_HF_FEATURE_CODEC_NEGOTIATION;
3388 if (TIZEN_PROFILE_WEARABLE)
3389 hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
3391 hf_ver = HFP_VERSION_1_6;
3398 struct sigaction sa;
3399 uint32_t hf_features;
3401 INFO_C("### Starting Bluetooth HF agent");
3403 hf_features = __bt_hf_agent_get_hf_features();
3404 bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
3406 memset(&sa, 0, sizeof(sa));
3407 sa.sa_flags = SA_NOCLDSTOP;
3408 sa.sa_handler = __bt_hf_agent_sigterm_handler;
3409 sigaction(SIGTERM, &sa, NULL);
3411 /* Temporarily, block the below signal for debugging */
3412 // sigaction(SIGSEGV, &sa, NULL);
3413 // sigaction(SIGABRT, &sa, NULL);
3414 gmain_loop = g_main_loop_new(NULL, FALSE);
3416 if (gmain_loop == NULL) {
3417 ERR("GMainLoop create failed\n");
3418 return EXIT_FAILURE;
3421 __bt_hf_agent_dbus_init();
3422 g_main_loop_run(gmain_loop);
3424 __bt_hf_agent_dbus_deinit();
3427 g_main_loop_unref(gmain_loop);
3429 INFO_C("### Terminating Bluetooth HF agent");