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_ALIAS_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 = NULL;
68 static GDBusProxy *profile_gproxy = NULL;
69 static guint interface_added_sig_id;
70 static guint interface_removed_sig_id;
75 int clcc_retry_count = 0;
76 guint clcc_async_timer = 0;
77 int clcc_async_retry_count = 0;
78 #define CLCC_RETRY_COUNT 10
79 #define CLCC_RETRY_TIMER 100 /* 100 msec */
81 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
82 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
84 /*Below Inrospection data is exposed to bluez from agent*/
85 static const gchar hf_agent_bluez_introspection_xml[] =
87 " <interface name='org.bluez.Profile1'>"
88 " <method name='NewConnection'>"
89 " <arg type='o' name='device' direction='in'/>"
90 " <arg type='h' name='fd' direction='in'/>"
91 " <arg type='a{sv}' name='options' direction='in'/>"
93 " <method name='RequestDisconnection'>"
94 " <arg type='o' name='device' direction='in'/>"
99 /*Below Inrospection data is exposed to application from agent*/
100 static const gchar hf_agent_introspection_xml[] =
102 " <interface name='org.tizen.HfApp'>"
103 " <method name='AnswerCall'>"
105 " <method name='TerminateCall'>"
107 " <method name='InitiateCall'>"
108 " <arg type='s' name='phoneno' direction='in'/>"
110 " <method name='VoiceRecognition'>"
111 " <arg type='i' name='status' direction='in'/>"
113 " <method name='ScoConnect'>"
115 " <method name='ScoDisconnect'>"
117 " <method name='SpeakerGain'>"
118 " <arg type='u' name='gain' direction='in'/>"
120 " <method name='SendDtmf'>"
121 " <arg type='s' name='dtmf' direction='in'/>"
123 " <method name='SendAtCmd'>"
124 " <arg type='s' name='atcmd' direction='in'/>"
126 " <method name='ReleaseAndAccept'>"
128 " <method name='CallSwap'>"
130 " <method name='ReleaseAllCall'>"
132 " <method name='JoinCall'>"
134 " <method name='GetCurrentCodec'>"
135 " <arg type='i' name='codec' direction='out'/>"
137 " <method name='RequestCallList'>"
138 " <arg type='i' name='count' direction='out'/>"
139 " <arg type='a(siiii)' name='callList' direction='out'/>"
141 " <method name='RequestCallListAsync'>"
143 " <method name='GetAudioConnected'>"
144 " <arg type='i' name='status' direction='out'/>"
146 " <method name='IsHfConnected'>"
147 " <arg type='b' name='status' direction='out'/>"
149 " <method name='IsInbandRingtoneSupported'>"
150 " <arg type='b' name='status' direction='out'/>"
155 static bt_hf_agent_info_t bt_hf_info = {0,};
156 static gboolean is_hf_connected = FALSE;
157 static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD;
158 static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
160 static char global_buff[BT_AT_COMMAND_BUFFER_MAX] = {0,};
163 static char prev_cmd[BT_HF_CMD_BUF_SIZE];
173 } hf_call_list_info_t;
175 #define BT_HF_SIG_NUM 3
176 static struct sigaction bt_hf_sigoldact[BT_HF_SIG_NUM];
177 static int bt_hf_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
179 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error);
181 static gboolean __bt_hf_agent_emit_property_changed(
182 GDBusConnection *connection,
184 const char *interface,
188 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
189 bt_hf_agent_info_t *bt_hf_info);
190 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info);
191 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info);
192 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
194 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
195 gchar *data, gsize count);
197 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
199 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
200 gchar *data, gchar *response, gsize count);
201 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indies);
202 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indies);
203 static guint __bt_hf_get_hold_mpty_features(gchar *features);
204 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info);
205 static void __bt_hf_agent_sigterm_handler(int signo);
206 static gboolean __bt_hf_agent_release(void);
208 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info);
209 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info);
210 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path);
211 static gboolean __bt_hf_agent_connection_release(void);
212 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info);
215 gchar descr[BT_HF_INDICATOR_DESCR_SIZE];
219 static int _hf_agent_answer_call(GDBusMethodInvocation *context);
221 static int _hf_agent_terminate_call(GDBusMethodInvocation *context);
223 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no);
225 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context,
228 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd);
230 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context,
231 unsigned int status);
233 static gboolean bt_hf_agent_sco_connect(void);
235 static gboolean bt_hf_agent_sco_disconnect(void);
237 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf);
239 static GVariant *bt_hf_agent_request_call_list(void);
241 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd);
243 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf);
245 static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
246 const gchar *msg, gpointer user_data)
251 static void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
255 char s[BT_HF_DATA_BUF_SIZE] = {0, };
256 gboolean hide = FALSE;
258 gboolean has_clcc = FALSE;
259 gboolean has_clip = FALSE;
260 gboolean has_ccwa = FALSE;
263 strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
265 has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
266 if (has_clcc == TRUE)
268 has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
269 if (has_clip == TRUE)
271 has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
275 xsat_ptr = strstr(s, "11,DISC,");
277 xsat_ptr = xsat_ptr + 8;
279 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
285 /* AT+XSAT=11,Q_CT,X,XXXX */
286 xsat_ptr = strstr(s, "11,Q_CT,");
288 xsat_ptr = xsat_ptr + 8;
290 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
291 if (x > 1) /* ignore 0 and 1 position */
298 while (s[i] != '\0') {
299 if (s[i] == '\r' || s[i] == '\n') {
303 hide = hide ? FALSE : TRUE;
304 else if ((has_clcc || has_clip || has_ccwa) && hide) {
312 INFO("%s Buffer = %s, Length = %zd ", message, s, strlen(s));
317 static GQuark __bt_hf_agent_error_quark(void)
321 static GQuark quark = 0;
323 quark = g_quark_from_static_string("hf-agent");
328 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error)
330 ERR("error[%d]", error);
333 case BT_HF_AGENT_ERROR_NOT_AVAILABLE:
334 return g_error_new(BT_HF_AGENT_ERROR, error,
335 BT_ERROR_NOT_AVAILABLE);
336 case BT_HF_AGENT_ERROR_NOT_CONNECTED:
337 return g_error_new(BT_HF_AGENT_ERROR, error,
338 BT_ERROR_NOT_CONNECTED);
339 case BT_HF_AGENT_ERROR_CONNECTION_FAILED:
340 return g_error_new(BT_HF_AGENT_ERROR, error,
341 BT_ERROR_NOT_CONNECTION_FAILED);
342 case BT_HF_AGENT_ERROR_BUSY:
343 return g_error_new(BT_HF_AGENT_ERROR, error,
345 case BT_HF_AGENT_ERROR_INVALID_PARAM:
346 return g_error_new(BT_HF_AGENT_ERROR, error,
347 BT_ERROR_INVALID_PARAM);
348 case BT_HF_AGENT_ERROR_ALREADY_EXIST:
349 return g_error_new(BT_HF_AGENT_ERROR, error,
350 BT_ERROR_ALREADY_EXIST);
351 case BT_HF_AGENT_ERROR_ALREADY_CONNECTED:
352 return g_error_new(BT_HF_AGENT_ERROR, error,
353 BT_ERROR_ALREADY_CONNECTED);
354 case BT_HF_AGENT_ERROR_NO_MEMORY:
355 return g_error_new(BT_HF_AGENT_ERROR, error,
357 case BT_HF_AGENT_ERROR_NO_DATA:
358 return g_error_new(BT_HF_AGENT_ERROR, error,
360 case BT_HF_AGENT_ERROR_I_O_ERROR:
361 return g_error_new(BT_HF_AGENT_ERROR, error,
363 case BT_HF_AGENT_ERROR_APPLICATION:
364 return g_error_new(BT_HF_AGENT_ERROR, error,
365 BT_ERROR_OPERATION_NOT_AVAILABLE);
366 case BT_HF_AGENT_ERROR_NOT_ALLOWED:
367 return g_error_new(BT_HF_AGENT_ERROR, error,
368 BT_ERROR_OPERATION_NOT_ALLOWED);
369 case BT_HF_AGENT_ERROR_NOT_SUPPORTED:
370 return g_error_new(BT_HF_AGENT_ERROR, error,
371 BT_ERROR_OPERATION_NOT_SUPPORTED);
372 case BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
373 return g_error_new(BT_HF_AGENT_ERROR, error,
374 BT_ERROR_INVALID_FILE_DESCRIPTOR);
375 case BT_HF_AGENT_ERROR_INTERNAL:
377 return g_error_new(BT_HF_AGENT_ERROR, error,
382 static void __bt_hf_lock_display(int timeout)
386 ret = device_power_request_lock(POWER_LOCK_DISPLAY, timeout);
388 DBG("Lock PM state as current state!");
390 ERR("deviced error!");
393 static void __bt_hf_unlock_display()
397 ret = device_power_release_lock(POWER_LOCK_DISPLAY);
399 DBG("UnLock PM state");
401 ERR("deviced error!");
404 static gboolean __clcc_timer_func(gpointer data)
411 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
412 DBG("NOT CONNECTED");
413 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_NOT_CONNECTED);
414 g_dbus_method_invocation_return_gerror((GDBusMethodInvocation *) data, err);
420 if (send_flag && clcc_retry_count > 0) {
422 DBG("Still pending. try later (remained [%d] times)", clcc_retry_count);
428 call_var = bt_hf_agent_request_call_list();
430 INFO("NOT AVAILABLE");
431 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_NOT_AVAILABLE);
432 g_dbus_method_invocation_return_gerror((GDBusMethodInvocation *) data, err);
437 INFO("return call list info");
438 g_dbus_method_invocation_return_value((GDBusMethodInvocation *) data, call_var);
442 static gboolean __clcc_async_timer_func(gpointer data)
446 if (send_flag && clcc_async_retry_count > 0) {
447 clcc_async_retry_count--;
448 ERR("Still pending. try later (remained [%d] times)", clcc_async_retry_count);
452 clcc_async_timer = 0;
454 __bt_hf_agent_handle_call_list(&bt_hf_info);
455 g_dbus_method_invocation_return_value((GDBusMethodInvocation*)data, NULL);
457 INFO("update_call_list succeeded");
462 static void __hf_agent_method(GDBusConnection *connection,
465 const gchar *interface_name,
466 const gchar *method_name,
467 GVariant *parameters,
468 GDBusMethodInvocation *context,
473 INFO("method %s", method_name);
477 if (g_strcmp0(method_name, "NewConnection") == 0) {
481 GUnixFDList *fd_list;
482 const gchar *object_path;
485 g_variant_get(parameters, "(oha{sv})",
486 &object_path, &index, &options);
488 msg = g_dbus_method_invocation_get_message(context);
489 fd_list = g_dbus_message_get_unix_fd_list(msg);
490 if (fd_list == NULL) {
491 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
495 fd = g_unix_fd_list_get(fd_list, index, NULL);
497 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
501 DBG("FD is = [%d], Object path = [%s]", fd, object_path);
503 if (!__bt_hf_agent_connection(fd, object_path)) {
504 ret = BT_HF_AGENT_ERROR_INTERNAL;
508 g_dbus_method_invocation_return_value(context, NULL);
509 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
510 if (!__bt_hf_agent_connection_release()) {
511 ret = BT_HF_AGENT_ERROR_INTERNAL;
514 INFO_C("Disconnected [HF role] [Terminated by local host]");
515 g_dbus_method_invocation_return_value(context, NULL);
516 } else if (g_strcmp0(method_name, "Release") == 0) {
517 if (!__bt_hf_agent_connection_release()) {
518 ret = BT_HF_AGENT_ERROR_INTERNAL;
522 g_dbus_method_invocation_return_value(context, NULL);
523 } else if (g_strcmp0(method_name, "AnswerCall") == 0) {
524 DBG("Going to call AnswerCall");
525 ret = _hf_agent_answer_call(context);
529 } else if (g_strcmp0(method_name, "TerminateCall") == 0) {
530 DBG("Going to call TerminateCall");
531 ret = _hf_agent_terminate_call(context);
535 } else if (g_strcmp0(method_name, "InitiateCall") == 0) {
536 char *phoneno = NULL;
538 g_variant_get(parameters, "(&s)", &phoneno);
540 DBG_SECURE("Going to call InitiateCall, Number is = [%s]\n", phoneno);
541 ret = _hf_agent_dial_no(NULL, phoneno);
545 g_dbus_method_invocation_return_value(context, NULL);
547 } else if (g_strcmp0(method_name, "VoiceRecognition") == 0) {
550 g_variant_get(parameters, "(i)", &status);
552 DBG("Going to call VoiceRecognition, Status [%d]", status);
553 ret = _hf_agent_voice_recognition(context, status);
557 } else if (g_strcmp0(method_name, "ScoConnect") == 0) {
558 DBG("Going to call ScoConnect");
559 if (!bt_hf_agent_sco_connect()) {
560 ret = BT_HF_AGENT_ERROR_INTERNAL;
564 g_dbus_method_invocation_return_value(context, NULL);
565 } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) {
566 DBG("Going to call ScoDisconnect");
567 if (!bt_hf_agent_sco_disconnect()) {
568 ret = BT_HF_AGENT_ERROR_INTERNAL;
572 g_dbus_method_invocation_return_value(context, NULL);
573 } else if (g_strcmp0(method_name, "SpeakerGain") == 0) {
574 unsigned int gain = 0;
576 g_variant_get(parameters, "(u)", &gain);
578 DBG("Going to call SpeakerGain, gain is = [%d]\n", gain);
579 ret = _hf_agent_set_speaker_gain(context, gain);
583 } else if (g_strcmp0(method_name, "SendDtmf") == 0) {
586 g_variant_get(parameters, "(&s)", &dtmf);
588 DBG("Going to call SendDtmf, dtmf is = [%s]\n", dtmf);
589 ret = _hf_agent_send_dtmf(NULL, dtmf);
592 g_dbus_method_invocation_return_value(context, NULL);
594 } else if (g_strcmp0(method_name, "SendAtCmd") == 0) {
597 g_variant_get(parameters, "(&s)", &cmd);
599 DBG("Going to call SendAtCmd\n");
600 ret = bt_hf_agent_send_at_cmd(NULL, cmd);
603 g_dbus_method_invocation_return_value(context, NULL);
605 } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) {
606 DBG("Going to call ReleaseAndAccept");
607 ret = _hf_agent_send_3way_cmd(context,
608 BT_HF_RELEASE_AND_ACCEPT);
612 } else if (g_strcmp0(method_name, "CallSwap") == 0) {
613 DBG("Going to call CallSwap");
614 ret = _hf_agent_send_3way_cmd(context,
615 BT_HF_ACCEPT_AND_HOLD);
619 } else if (g_strcmp0(method_name, "ReleaseAllCall") == 0) {
620 DBG("Going to call ReleaseAllCall");
621 ret = _hf_agent_send_3way_cmd(context, BT_HF_RELEASE_ALL);
625 } else if (g_strcmp0(method_name, "JoinCall") == 0) {
626 DBG("Going to call JoinCall");
627 ret = _hf_agent_send_3way_cmd(context, BT_HF_JOIN_CALL);
631 } else if (g_strcmp0(method_name, "GetCurrentCodec") == 0) {
632 DBG("Going to call GetCurrentCodec");
633 INFO("Current codec : %d", current_codec_id);
634 g_dbus_method_invocation_return_value(context,
635 g_variant_new("(i)", current_codec_id));
636 } else if (g_strcmp0(method_name, "RequestCallList") == 0) {
639 INFO("Going to call RequestCallList (send_flag[%d])", send_flag);
642 INFO("Send_flag is true. Try to send CLCC later");
643 clcc_retry_count = CLCC_RETRY_COUNT;
644 clcc_timer = g_timeout_add(CLCC_RETRY_TIMER, __clcc_timer_func, context);
646 call_var = bt_hf_agent_request_call_list();
648 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
651 g_dbus_method_invocation_return_value(context, call_var);
653 } else if (g_strcmp0(method_name, "RequestCallListAsync") == 0) {
654 INFO("Going to call RequestCallListAsync (send_flag[%d])", send_flag);
656 if (clcc_async_timer > 0) {
657 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
660 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
661 ret = BT_HF_AGENT_ERROR_NOT_CONNECTED;
664 if (bt_hf_info.ciev_call_status == 0 &&
665 bt_hf_info.ciev_call_setup_status == 0) {
666 ret = BT_HF_AGENT_ERROR_NO_DATA;
671 INFO("Send_flag is true. Try to send CLCC later");
672 clcc_async_retry_count = CLCC_RETRY_COUNT;
673 clcc_async_timer = g_timeout_add(CLCC_RETRY_TIMER, __clcc_async_timer_func, context);
675 __bt_hf_agent_handle_call_list(&bt_hf_info);
676 g_dbus_method_invocation_return_value(context, NULL);
678 } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) {
679 DBG("Going to call GetAudioConnected");
680 g_dbus_method_invocation_return_value(context,
681 g_variant_new("(i)", sco_audio_connected));
682 } else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
683 DBG("Going to call IsHfConnected");
684 INFO("is_hf_connected : %s", is_hf_connected ? "Connected" : "Disconnected");
686 g_dbus_method_invocation_return_value(context,
687 g_variant_new("(b)", is_hf_connected));
688 } else if (g_strcmp0(method_name, "IsInbandRingtoneSupported") == 0) {
689 gboolean is_supported = FALSE;
691 if (is_hf_connected == FALSE) {
692 ret = BT_HF_AGENT_ERROR_NOT_CONNECTED;
696 if (bt_hf_info.inband_ringtone_support)
699 is_supported = FALSE;
701 INFO("IsInbandRingtoneSupported : %s", is_supported ?
702 "Supported" : "NotSupported");
703 g_dbus_method_invocation_return_value(context,
704 g_variant_new("(b)", is_supported));
711 err = __bt_hf_agent_set_error(ret);
712 g_dbus_method_invocation_return_gerror(context, err);
717 static const GDBusInterfaceVTable method_table = {
723 static GDBusNodeInfo *__bt_hf_create_method_node_info
724 (const gchar *introspection_data)
726 if (introspection_data == NULL)
729 return g_dbus_node_info_new_for_xml(introspection_data, NULL);
732 static GDBusConnection *__bt_hf_get_gdbus_connection(void)
734 GDBusConnection *local_system_gconn = NULL;
737 if (gdbus_conn == NULL) {
738 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
741 ERR("Unable to connect to dbus: %s", err->message);
746 } else if (g_dbus_connection_is_closed(gdbus_conn)) {
747 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
749 if (!local_system_gconn) {
750 ERR("Unable to connect to dbus: %s", err->message);
754 gdbus_conn = local_system_gconn;
760 static gboolean __bt_hf_register_profile_methods(void)
763 GError *error = NULL;
766 GDBusNodeInfo *node_info;
768 GDBusConnection *conn;
770 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
772 G_BUS_NAME_OWNER_FLAGS_NONE,
776 DBG("owner_id is [%d]", owner_id);
778 node_info = __bt_hf_create_method_node_info(
779 hf_agent_bluez_introspection_xml);
780 if (node_info == NULL)
783 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
784 DBG("path is [%s]", path);
786 conn = __bt_hf_get_gdbus_connection();
788 ERR("Unable to get connection");
793 object_id = g_dbus_connection_register_object(conn, path,
794 node_info->interfaces[0],
797 if (object_id == 0) {
798 ERR("Failed to register: %s", error->message);
800 g_dbus_node_info_unref(node_info);
805 g_dbus_node_info_unref(node_info);
807 node_info = __bt_hf_create_method_node_info(hf_agent_introspection_xml);
808 if (node_info == NULL)
811 path = g_strdup(BT_HF_AGENT_OBJECT_PATH);
812 DBG("path is [%s]", path);
814 object_id = g_dbus_connection_register_object(conn, path,
815 node_info->interfaces[0],
818 if (object_id == 0) {
820 ERR("Failed to register: %s", error->message);
823 g_dbus_node_info_unref(node_info);
828 g_dbus_node_info_unref(node_info);
834 static GDBusProxy *__bt_hf_gdbus_init_profile_proxy(void)
840 GDBusConnection *conn;
842 conn = __bt_hf_get_gdbus_connection();
844 ERR("Unable to get connection");
848 proxy = g_dbus_proxy_new_sync(conn,
849 G_DBUS_PROXY_FLAGS_NONE, NULL,
850 BLUEZ_SERVICE_NAME, "/org/bluez",
851 BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err);
855 ERR("Unable to create proxy: %s", err->message);
861 profile_gproxy = proxy;
867 static GDBusProxy *__bt_hf_gdbus_get_profile_proxy(void)
869 return (profile_gproxy) ? profile_gproxy :
870 __bt_hf_gdbus_init_profile_proxy();
873 static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service,
874 const gchar *path, const gchar *interface)
880 GDBusConnection *conn;
882 conn = __bt_hf_get_gdbus_connection();
884 ERR("Unable to get connection");
888 proxy = g_dbus_proxy_new_sync(conn,
889 G_DBUS_PROXY_FLAGS_NONE, NULL,
891 interface, NULL, &err);
895 ERR("Unable to create proxy: %s", err->message);
905 static char __bt_hf_agent_get_tx_power(char *address)
909 GError *error = NULL;
910 char result = READ_TX_POWER_MIN; /* default minimum */
912 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, g_obj_path,
913 BLUEZ_HF_INTERFACE_NAME);
915 ERR("Proxy is NULL");
919 ret = g_dbus_proxy_call_sync(proxy,
920 "GetTxPowerLevel", g_variant_new("(s)", address),
921 G_DBUS_CALL_FLAGS_NONE, -1,
924 ERR("DBus is failed");
926 /* Dbus gives error cause */
927 ERR("D-Bus API failure: errCode[%x], message[%s]",
928 error->code, error->message);
929 g_clear_error(&error);
931 g_object_unref(proxy);
934 g_variant_get(ret, "(y)", &result);
935 DBG("TX power level = %d", result);
936 g_variant_unref(ret);
937 g_object_unref(proxy);
942 static int __bt_hf_agent_gdbus_method_send(const char *service,
943 GVariant *path, const char *interface,
950 GError *error = NULL;
952 proxy = __bt_hf_gdbus_get_service_proxy(service, g_obj_path, interface);
954 return BT_HF_AGENT_ERROR_INTERNAL;
956 ret = g_dbus_proxy_call_sync(proxy,
958 G_DBUS_CALL_FLAGS_NONE, -1,
961 /* dBUS-RPC is failed */
962 ERR("dBUS-RPC is failed");
964 /* dBUS gives error cause */
965 ERR("D-Bus API failure: errCode[%x], message[%s]",
966 error->code, error->message);
968 g_clear_error(&error);
970 g_object_unref(proxy);
971 return BT_HF_AGENT_ERROR_INTERNAL;
974 g_variant_unref(ret);
975 g_object_unref(proxy);
977 return BT_HF_AGENT_ERROR_NONE;
980 static void __bt_hf_agent_release_queue(void)
983 bt_hf_agent_send_at_info *cmd;
986 len = g_slist_length(bt_hf_info.cmd_send_queue);
987 for (i = 0; i < len; ++i) {
988 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
989 if (cmd && cmd->context) {
990 DBG("Pending context found for %.6s[%d]",
991 cmd->at_cmd, cmd->id);
992 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_INTERNAL);
993 g_dbus_method_invocation_return_gerror(cmd->context, err);
996 if (cmd && cmd->timer_id)
997 g_source_remove(cmd->timer_id);
999 g_slist_free(bt_hf_info.cmd_send_queue);
1000 bt_hf_info.cmd_send_queue = NULL;
1004 static gboolean __bt_hf_monitor_timer_cb(gpointer data)
1007 bt_hf_agent_send_at_info *cmd = data;
1008 ERR_C("Monitor timer came becuase of timeout for sendflag %d, %s",
1009 send_flag, cmd->at_cmd);
1010 /* In the case of ATD, we have to inform the remote to end the call */
1011 if (strstr(cmd->at_cmd, "ATD") || strstr(cmd->at_cmd, "BLDN")) {
1012 INFO_C("Sending CHUP for remote call termination");
1013 __bt_hf_send_only_without_queue(&bt_hf_info, BT_HF_END_CALL,
1014 strlen(BT_HF_END_CALL));
1015 /* Here there is a high posisbility that we do not get response
1016 * for CHUP. Hence we need to decrement send_flag to process further
1017 * incomming packets because we already incremented it in the CHUP case. */
1021 /* In the case of ATD, prev_cmd will be always ATD, because we will not
1022 * allow further commands. For safer side again set prev_cmd as ATD */
1023 strncpy(prev_cmd, "ATD\0", BT_HF_CMD_BUF_SIZE - 1);
1025 hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
1033 gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
1034 int count, gboolean pending_flag)
1036 int i, len, timer_id;
1037 if (bt_hf_info.slc == FALSE)
1040 DBG("Add Pending queue. (pending_flag is %s)",
1041 pending_flag ? "TRUE" : "FALSE");
1043 bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
1045 ERR("failed to allocate cmd");
1050 memcpy(cmd->at_cmd, at, count);
1052 cmd->context = context;
1053 cmd->pending = pending_flag;
1054 bt_hf_info.cmd_send_queue = g_slist_append(bt_hf_info.cmd_send_queue,
1056 len = g_slist_length(bt_hf_info.cmd_send_queue);
1057 for (i = 0; i < len; ++i) {
1058 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
1060 DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id);
1063 /* We need to have base timeout + tolerance value to process other request */
1064 if (strstr(at, "ATD") || strstr(at, "BLDN")) {
1065 /* Android 15 seconds timeout in case of ATD timeout in flight mode */
1066 timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len,
1067 __bt_hf_monitor_timer_cb, cmd);
1069 cmd->timer_id = timer_id;
1071 timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len,
1072 __bt_hf_monitor_timer_cb, cmd);
1074 cmd->timer_id = timer_id;
1080 Below methods exposed to Applicatoins
1082 static gboolean __bt_hf_agent_emit_signal(GDBusConnection *connection,
1083 const char *path, const char *interface,
1084 const char *signal_name, GVariant *param)
1086 GError *error = NULL;
1088 ret = g_dbus_connection_emit_signal(connection,
1090 interface, signal_name,
1093 if (error != NULL) {
1094 /* dBUS gives error cause */
1095 ERR("D-Bus API failure: errCode[%x], message[%s]",
1096 error->code, error->message);
1097 g_clear_error(&error);
1100 INFO_C("Emit Signal [%s]", signal_name);
1105 static gboolean __bt_hf_agent_emit_property_changed(
1106 GDBusConnection *connection,
1108 const char *interface,
1114 GError *error = NULL;
1116 ret = g_dbus_connection_emit_signal(connection,
1117 NULL, path, interface,
1119 g_variant_new("(sv)", name, property),
1122 if (error != NULL) {
1123 /* dBUS gives error cause */
1124 ERR("D-Bus API failure: errCode[%x], message[%s]",
1125 error->code, error->message);
1126 g_clear_error(&error);
1134 Below methods exposed to Bluez
1137 static gboolean __bt_hf_agent_launch_call_app(void)
1143 app_manager_is_running(CALL_ALIAS_APP_ID, &is_running);
1145 DBG("Call app is already started");
1149 b = bundle_create();
1151 ERR("bundle_create() Failed");
1155 bundle_add(b, "launch-type", "BT_LAUNCH");
1157 bundle_add(b, "carrier-type", "BT");
1158 DBG("For 3G, carrier-type: BT has been added");
1159 aul_launch_app_async(CALL_ALIAS_APP_ID, b);
1162 INFO("-aul_launch_app_async -");
1167 static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
1168 guint index, gint value)
1170 GDBusConnection *conn;
1172 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
1174 ERR("Indicator is NULL");
1181 conn = __bt_hf_get_gdbus_connection();
1183 ERR("Unable to get connection");
1187 INFO("Indicator name is %s, value = [%d]", name, value);
1188 if (!strcmp(name, "\"call\"")) {
1189 bt_hf_info->ciev_call_status = value;
1191 __bt_hf_agent_emit_signal(conn,
1192 BT_HF_AGENT_OBJECT_PATH,
1193 BT_HF_SERVICE_INTERFACE,
1194 "CallStarted", NULL);
1195 bt_hf_info->is_dialing = FALSE;
1196 bt_hf_info->call_active = TRUE;
1197 } else if (bt_hf_info->call_active) {
1198 __bt_hf_agent_emit_signal(conn,
1199 BT_HF_AGENT_OBJECT_PATH,
1200 BT_HF_SERVICE_INTERFACE,
1202 bt_hf_info->call_active = FALSE;
1204 if (bt_hf_info->ciev_call_setup_status == 0) {
1205 __bt_hf_agent_emit_signal(gdbus_conn,
1206 BT_HF_AGENT_OBJECT_PATH,
1207 BT_HF_SERVICE_INTERFACE,
1212 } else if (!strcmp(name, "\"callsetup\"")) {
1213 bt_hf_info->ciev_call_setup_status = value;
1214 if (value == 0 && bt_hf_info->is_dialing) {
1215 bt_hf_info->is_dialing = FALSE;
1216 __bt_hf_agent_emit_signal(conn,
1217 BT_HF_AGENT_OBJECT_PATH,
1218 BT_HF_SERVICE_INTERFACE,
1221 } else if (!bt_hf_info->is_dialing && value > 0) {
1222 bt_hf_info->is_dialing = TRUE;
1225 if (bt_hf_info->ciev_call_setup_status == 1) {
1226 __bt_hf_agent_emit_signal(gdbus_conn,
1227 BT_HF_AGENT_OBJECT_PATH,
1228 BT_HF_SERVICE_INTERFACE,
1229 "CallSetupIncoming", NULL);
1230 if (__bt_hf_agent_launch_call_app() == FALSE)
1231 DBG("call app launching failed");
1232 } else if (bt_hf_info->ciev_call_setup_status == 2) {
1233 __bt_hf_agent_emit_signal(gdbus_conn,
1234 BT_HF_AGENT_OBJECT_PATH,
1235 BT_HF_SERVICE_INTERFACE,
1236 "CallSetupDialing", NULL);
1237 } else if (bt_hf_info->ciev_call_setup_status == 3) {
1238 __bt_hf_agent_emit_signal(gdbus_conn,
1239 BT_HF_AGENT_OBJECT_PATH,
1240 BT_HF_SERVICE_INTERFACE,
1241 "CallSetupAlerting", NULL);
1242 } else if (bt_hf_info->ciev_call_status == 0 &&
1243 bt_hf_info->ciev_call_setup_status == 0) {
1244 __bt_hf_agent_emit_signal(gdbus_conn,
1245 BT_HF_AGENT_OBJECT_PATH,
1246 BT_HF_SERVICE_INTERFACE,
1249 } else if (!strcmp(name, "\"callheld\"")) {
1250 if (value == 0) { /* No calls held*/
1251 __bt_hf_agent_emit_signal(conn,
1252 BT_HF_AGENT_OBJECT_PATH,
1253 BT_HF_SERVICE_INTERFACE,
1256 } else if (value == 1) {
1257 /*Call is placed on hold or active/held calls swapped */
1258 __bt_hf_agent_emit_signal(conn,
1259 BT_HF_AGENT_OBJECT_PATH,
1260 BT_HF_SERVICE_INTERFACE,
1261 "CallsSwapped", NULL);
1263 /*Call on hold, no active call*/
1264 __bt_hf_agent_emit_signal(conn,
1265 BT_HF_AGENT_OBJECT_PATH,
1266 BT_HF_SERVICE_INTERFACE,
1267 "CallOnHold", NULL);
1269 } else if (!strcmp(name, "\"service\"")) {
1270 if (value < 0 || value > 1)
1271 ERR("Out of range");
1273 __bt_hf_agent_emit_property_changed(conn,
1274 BT_HF_AGENT_OBJECT_PATH,
1275 BT_HF_SERVICE_INTERFACE,
1276 "RegistrationStatus",
1277 g_variant_new("q", value));
1278 } else if (!strcmp(name, "\"signal\"")) {
1279 if (value < 0 || value > 5)
1280 ERR("Out of range");
1282 __bt_hf_agent_emit_property_changed(conn,
1283 BT_HF_AGENT_OBJECT_PATH,
1284 BT_HF_SERVICE_INTERFACE, "SignalStrength",
1285 g_variant_new("q", value));
1286 } else if (!strcmp(name, "\"roam\"")) {
1287 if (value < 0 || value > 1)
1288 ERR("Out of range");
1290 __bt_hf_agent_emit_property_changed(conn,
1291 BT_HF_AGENT_OBJECT_PATH,
1292 BT_HF_SERVICE_INTERFACE, "RoamingStatus",
1293 g_variant_new("q", value));
1294 } else if (!strcmp(name, "\"battchg\"")) {
1295 if (value < 0 || value > 5)
1296 ERR("Out of range");
1298 __bt_hf_agent_emit_property_changed(conn,
1299 BT_HF_AGENT_OBJECT_PATH,
1300 BT_HF_SERVICE_INTERFACE, "BatteryCharge",
1301 g_variant_new("q", value));
1305 static void __bt_hf_agent_handle_voice_activation(gint value)
1307 GDBusConnection *conn;
1309 conn = __bt_hf_get_gdbus_connection();
1311 ERR("Unable to get connection");
1315 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1316 BT_HF_SERVICE_INTERFACE,
1318 g_variant_new("(i)", value));
1323 static void __bt_hf_agent_handle_speaker_gain(gint value)
1325 GDBusConnection *conn;
1327 conn = __bt_hf_get_gdbus_connection();
1329 ERR("Unable to get connection");
1333 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1334 BT_HF_SERVICE_INTERFACE, "VolumeSpeaker",
1335 g_variant_new("(i)", value));
1340 static int __bt_hf_agent_handle_clip(bt_hf_agent_info_t *bt_hf_info,
1343 GDBusConnection *conn;
1345 gchar number[BT_HF_CALLER_NUM_SIZE];
1347 char fmt_str[BT_HF_FMT_STR_SIZE];
1348 int len = strlen(buf);
1350 DBG("__bt_hf_agent_handle_clip +");
1351 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1352 ERR("buf len %d is too long", len);
1356 if ((clip = strstr(buf, "\r\n+CLIP"))) {
1357 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CLIP: \"%%%ds", (int)(sizeof(number) - 1));
1358 if (sscanf(clip, fmt_str, number) == 1) {
1359 sep = strchr(number, '"');
1364 conn = __bt_hf_get_gdbus_connection();
1366 ERR("Unable to get connection");
1370 __bt_hf_agent_emit_signal(conn,
1371 BT_HF_AGENT_OBJECT_PATH,
1372 BT_HF_SERVICE_INTERFACE, "Ring",
1373 g_variant_new("(s)", clip));
1375 ERR_SECURE("CLIP '%s' is Call Incoming", buf);
1379 DBG("__bt_hf_agent_handle_clip -");
1383 static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info,
1386 GDBusConnection *conn;
1388 gchar number[BT_HF_CALLER_NUM_SIZE];
1390 char fmt_str[BT_HF_FMT_STR_SIZE];
1391 int len = strlen(buf);
1393 DBG("__bt_hf_agent_handle_ccwa +");
1394 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1395 ERR("buf len %d is too long", len);
1399 if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
1400 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds",
1401 (int)(sizeof(number) - 1));
1402 if (sscanf(ccwa, fmt_str, number) == 1) {
1403 sep = strchr(number, '"');
1408 conn = __bt_hf_get_gdbus_connection();
1410 ERR("Unable to get connection");
1414 __bt_hf_agent_emit_signal(conn,
1415 BT_HF_AGENT_OBJECT_PATH,
1416 BT_HF_SERVICE_INTERFACE, "CallWaiting",
1417 g_variant_new("(s)", ccwa));
1419 ERR_SECURE("CCWA '%s' is Call Wating", buf);
1423 DBG("__bt_hf_agent_handle_ccwa -");
1427 static void __bt_hf_agent_handle_bsir(bt_hf_agent_info_t *bt_hf_info,
1430 INFO("new value : %d", value);
1433 bt_hf_info->inband_ringtone_support = TRUE;
1435 bt_hf_info->inband_ringtone_support = FALSE;
1440 static GSList *__bt_hf_prepare_call_list(const char *buf)
1442 GSList *call_list = NULL;
1447 char delim_sep[] = "\r\n";
1448 char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1450 hf_call_list_info_t *call_info;
1453 strncpy(temp_buf, buf, BT_HF_DATA_BUF_SIZE - 1);
1455 str = strtok_r(temp_buf, delim_sep, &sp);
1456 while (str != NULL) {
1457 if (!(strstr(str, "+CLCC:"))) {
1458 str = strtok_r(NULL, delim_sep, &sp);
1462 call_info = g_new0(hf_call_list_info_t, 1);
1464 sscanf(str, "+CLCC: %1d,%1d, %1d, %1d, %1d",
1465 &call_info->idx, &call_info->dir,
1466 &call_info->status, &call_info->mode,
1467 &call_info->multi_party);
1468 DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n",
1469 call_info->idx, call_info->dir, call_info->status,
1470 call_info->mode, call_info->multi_party);
1472 ptr = strstr(str, "\"");
1474 temp = strstr(ptr + 1, "\"");
1477 DBG_SECURE("\tPhone Number = [%s]\n", ptr + 1);
1478 call_info->number = g_strdup(ptr + 1);
1480 if (strstr(temp + 1, ",")) {
1482 DBG("\tType = [%s]\n", temp);
1483 call_info->type = atoi(temp);
1487 /*In case of no phone no. in CLCC respnse, we should launch call application
1488 * with NULL string. By doing so "unknown" shall be displayed*/
1489 DBG("Phone number does not exist\n");
1490 call_info->number = g_strdup("");
1493 call_list = g_slist_append(call_list, call_info);
1494 str = strtok_r(NULL, delim_sep, &sp);
1500 static GSList *__bt_hf_get_call_list(bt_hf_agent_info_t *bt_hf_info)
1502 char buf[BT_HF_DATA_BUF_SIZE] = {0,};
1503 GSList *call_list = NULL;
1507 /* Send CLCC when the callsetup */
1508 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLLIST, buf,
1509 sizeof(BT_HF_CALLLIST) - 1);
1510 DBG_SECURE("Receive CLCC response buffer = '%s'", buf);
1512 call_list = __bt_hf_prepare_call_list(buf);
1517 static void __bt_hf_call_info_free(void *data)
1521 hf_call_list_info_t *call_info = data;
1522 g_free(call_info->number);
1528 static void __bt_hf_free_call_list(GSList *call_list)
1532 g_slist_free_full(call_list, __bt_hf_call_info_free);
1537 static void __bt_hf_launch_call_using_call_list(GSList *call_list)
1542 if (call_list == NULL)
1545 len = g_slist_length(call_list);
1547 if (len > 0 && __bt_hf_agent_launch_call_app() == FALSE)
1548 DBG("call app launching failed");
1553 static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list)
1559 hf_call_list_info_t *call_info;
1561 GVariantBuilder *builder;
1564 builder = g_variant_builder_new(G_VARIANT_TYPE("a(siiii)"));
1566 call_count = g_slist_length(call_list);
1567 DBG("Total call count = '%d'", call_count);
1569 while (call_count--) {
1570 call_info = g_slist_nth_data(call_list, call_count);
1572 INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d",
1573 call_info->idx, call_info->dir, call_info->status,
1574 call_info->mode, call_info->multi_party);
1575 caller = call_info->number;
1577 g_variant_builder_add(builder, "(siiii)",
1578 caller, call_info->dir, call_info->status,
1579 call_info->multi_party, call_info->idx);
1582 var_data = g_variant_new("(ia(siiii))",
1583 g_slist_length(call_list), builder);
1585 g_variant_builder_unref(builder);
1590 static void __bt_hf_clear_prev_sent_cmd(void)
1592 if (prev_cmd[0] != 0)
1593 ERR("No sent command");
1595 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
1600 static void __bt_hf_agent_send_call_status_info(GSList *call_list)
1602 GDBusConnection *conn;
1605 conn = __bt_hf_get_gdbus_connection();
1607 ERR("Unable to get connection");
1609 var_data = __bt_hf_agent_get_call_status_info(call_list);
1610 __bt_hf_agent_emit_signal(conn,
1611 BT_HF_AGENT_OBJECT_PATH,
1612 BT_HF_SERVICE_INTERFACE,
1618 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info)
1622 __bt_hf_lock_display(0);
1624 bt_hf_info->context = NULL;
1626 /* Send CLCC. The response will be handled in the handler */
1627 ret = __bt_hf_send_only(bt_hf_info, BT_HF_CALLLIST,
1628 sizeof(BT_HF_CALLLIST) - 1);
1630 ERR("Failed to send CLCC");
1632 __bt_hf_unlock_display();
1635 static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only)
1637 gchar buf[BT_HF_DATA_BUF_SIZE];
1638 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1641 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_AVAILABLE_CODEC,
1642 BT_HF_CODEC_ID_CVSD, BT_HF_CODEC_ID_MSBC);
1644 bt_hf_info->context = NULL;
1646 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1649 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
1652 if (!ret || !strstr(buf, "OK"))
1658 static int _hf_agent_codec_setup(const char *addr, guint codec_id)
1663 ERR("g_obj_path is NULL\n");
1664 return BT_HF_AGENT_ERROR_INTERNAL;
1668 case BT_HF_CODEC_ID_CVSD:
1669 INFO("Set NB parameters");
1670 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1671 g_variant_new("(ss)", "Handsfree", addr),
1672 BT_ADAPTER_INTERFACE,
1675 case BT_HF_CODEC_ID_MSBC:
1676 INFO("Set WBS parameters");
1677 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1678 g_variant_new("(ss)", "Handsfree", addr),
1679 BT_ADAPTER_INTERFACE,
1680 "SetWbsParameters");
1683 ret = BT_HF_AGENT_ERROR_INTERNAL;
1684 ERR("Invalid Codec\n");
1689 ERR("Failed to setup the Codec\n");
1691 current_codec_id = codec_id;
1696 static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info,
1699 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1703 if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) {
1704 INFO("Codec id doesn't match, so send available codec again");
1705 ret = __bt_hf_send_available_codec(bt_hf_info, 1);
1707 ERR("Failed to send avalable codec");
1711 /* HF should be ready accpet SCO connection before sending theresponse for
1712 "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */
1713 retval = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id);
1715 ERR("_hf_agent_codec_setup : Failed [%d]", retval);
1718 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id);
1720 bt_hf_info->context = NULL;
1721 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1723 ERR("__bt_hf_send_only : FALSE");
1727 static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1729 gchar indicator[BT_HF_INDICATOR_DESCR_SIZE + 4];
1733 char fmt_str[BT_HF_FMT_STR_SIZE];
1735 DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
1737 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n",
1738 BT_HF_INDICATOR_DESCR_SIZE + 4 - 1);
1739 if (sscanf(buf, fmt_str, indicator) == 1) {
1740 sep = strchr(indicator, ',');
1743 index = atoi(indicator);
1745 __bt_hf_agent_handle_ind_change(bt_hf_info, index, value);
1747 DBG("--------- __bt_hf_agent_handler_ciev ------------");
1751 static void __bt_hf_agent_handle_ven_samsung(bt_hf_agent_info_t *bt_hf_info,
1752 gint app_id, const char *msg)
1754 /* Whomesoever wants need to handle it */
1755 char *sig_name = "SamsungXSAT";
1756 GDBusConnection *conn;
1758 conn = __bt_hf_get_gdbus_connection();
1760 ERR("Unable to get connection");
1764 __bt_hf_agent_emit_signal(conn,
1765 BT_HF_AGENT_OBJECT_PATH,
1766 BT_HF_SERVICE_INTERFACE,
1768 g_variant_new("(is)", app_id, msg));
1771 static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1773 DBG("++++++++ __bt_hf_agent_handler_ring ++++++++");
1774 DBG("---------__bt_hf_agent_handler_ring --------");
1779 static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1781 DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++");
1782 __bt_hf_agent_handle_clip(bt_hf_info, buf);
1783 DBG("---------__bt_hf_agent_handler_clip --------");
1788 static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1790 DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++");
1792 if (sscanf(buf, "\r\n+BVRA:%1d\r\n", &value) == 1)
1793 __bt_hf_agent_handle_voice_activation(value);
1795 DBG("---------__bt_hf_agent_handler_bvra --------");
1799 static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1802 DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-");
1803 if (sscanf(buf, "\r\n+BCS:%3d\r\n", &codec_id))
1804 __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id);
1806 DBG("---------__bt_hf_agent_handler_bcs --------");
1810 static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1814 DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
1816 ret = sscanf(buf, "\r\n+VGS:%2d\r\n", &value);
1817 else if (buf[6] == '=')
1818 ret = sscanf(buf, "\r\n+VGS=%2d\r\n", &value);
1820 __bt_hf_agent_handle_speaker_gain(value);
1822 DBG("---------__bt_hf_agent_handler_vgs --------");
1827 static int __bt_hf_agent_handler_ccwa(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1829 DBG("+++++++++ __bt_hf_agent_handler_ccwa ++++++++");
1830 __bt_hf_agent_handle_ccwa(bt_hf_info, buf);
1831 DBG("---------__bt_hf_agent_handler_ccwa --------");
1837 static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
1841 char msg[BT_HF_DATA_BUF_SIZE];
1842 char fmt_str[BT_HF_CMD_BUF_SIZE];
1844 DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
1845 snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n",
1846 (int)(sizeof(msg) - 1));
1847 if (sscanf(buf, fmt_str, &app_id, msg)) {
1848 if (app_id == 2 && strstr(msg, "READTXPOWER")) {
1849 char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, };
1850 char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr);
1851 snprintf(cmd_buf, sizeof(cmd_buf), "AT+XSAT: 2,%d", power);
1852 bt_hf_agent_send_at_cmd(NULL, cmd_buf);
1854 __bt_hf_agent_handle_ven_samsung(bt_hf_info, app_id, msg);
1858 DBG("---------__bt_hf_agent_handler_xsat --------");
1863 static int __bt_hf_agent_handler_bsir(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1865 DBG("+++++++++ __bt_hf_agent_handler_bsir +++++++++");
1867 if (sscanf(buf, "\r\n+BSIR:%1d\r\n", &value) == 1)
1868 __bt_hf_agent_handle_bsir(bt_hf_info, value);
1870 DBG("---------__bt_hf_agent_handler_bsir --------");
1874 static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info,
1877 DBG("+++++++++ __bt_hf_agent_handler_cme_error ++++++++");
1879 GDBusConnection *conn;
1881 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1882 conn = __bt_hf_get_gdbus_connection();
1884 ERR("Unable to get connection");
1888 __bt_hf_agent_emit_signal(conn,
1889 BT_HF_AGENT_OBJECT_PATH,
1890 BT_HF_SERVICE_INTERFACE,
1895 __bt_hf_clear_prev_sent_cmd();
1900 static int __bt_hf_agent_handler_response_ok(bt_hf_agent_info_t *bt_hf_info,
1903 DBG("+++++++++ __bt_hf_agent_handler_response_ok ++++++++");
1905 __bt_hf_clear_prev_sent_cmd();
1910 static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info,
1913 DBG("+++++++++ __bt_hf_agent_handler_response_err ++++++++");
1914 GDBusConnection *conn;
1916 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1917 conn = __bt_hf_get_gdbus_connection();
1919 ERR("Unable to get connection");
1923 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1924 BT_HF_SERVICE_INTERFACE,
1928 __bt_hf_clear_prev_sent_cmd();
1933 static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info,
1937 GDBusConnection *conn;
1939 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1940 conn = __bt_hf_get_gdbus_connection();
1942 ERR("Unable to get connection");
1946 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1947 BT_HF_SERVICE_INTERFACE,
1952 __bt_hf_clear_prev_sent_cmd();
1958 static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char *buffer)
1961 GSList *call_list = NULL;
1962 DBG("+++++++++ __bt_hf_agent_handler_clcc ++++++++");
1963 DBG_SECURE("Receive CLCC response buffer = '%s'", buffer);
1965 __bt_hf_lock_display(0);
1967 call_list = __bt_hf_prepare_call_list(buffer);
1969 if (call_list == NULL)
1972 __bt_hf_launch_call_using_call_list(call_list);
1974 __bt_hf_agent_send_call_status_info(call_list);
1976 __bt_hf_free_call_list(call_list);
1979 __bt_hf_unlock_display();
1980 DBG("---------__bt_hf_agent_handler_clcc --------");
1984 static bt_hf_event hf_event_callbacks[] = {
1985 { "\r\n+CIEV:", __bt_hf_agent_handler_ciev },
1986 { "\r\nRING", __bt_hf_agent_handler_ring },
1987 { "\r\n+CLIP:", __bt_hf_agent_handler_clip },
1988 { "\r\n+BVRA:", __bt_hf_agent_handler_bvra },
1989 { "\r\n+BCS:", __bt_hf_agent_handler_bcs },
1990 { "\r\n+VGS", __bt_hf_agent_handler_vgs },
1991 { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa },
1992 { "\r\n+XSAT:", __bt_hf_agent_handler_xsat },
1993 {"\r\n+CLCC:", __bt_hf_agent_handler_clcc },
1994 {"\r\n+BSIR:", __bt_hf_agent_handler_bsir },
1998 static bt_hf_event hf_event_resp_callbacks[] = {
1999 { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error },
2000 { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok },
2001 { "ERROR", __bt_hf_agent_handler_response_err },
2002 { "SERR", __bt_hf_agent_handler_response_serr },
2006 bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info)
2010 bt_hf_agent_send_at_info *cmd;
2011 len = g_slist_length(bt_hf_info->cmd_send_queue);
2012 for (i = 0; i < len; ++i) {
2013 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i);
2015 DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id);
2017 len = g_slist_length(bt_hf_info->cmd_send_queue);
2018 DBG("Context queue length = %d", len);
2022 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
2024 bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
2025 DBG("NEXT[%d] Found %s, context = 0x%p, pending = %d", cmd->id,
2026 cmd->at_cmd, cmd->context, cmd->pending);
2030 DBG("**** Not found any pending command on list length %d ****", len);
2035 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf)
2039 bt_hf_agent_send_at_info *cmd = NULL;
2041 __bt_hf_agent_print_at_buffer("Processing [Rx cmd]:", buf);
2043 for (ev = hf_event_resp_callbacks; ev->cmd; ev++) {
2044 if (strstr(buf, ev->cmd)) {
2047 DBG("Send flag value = %d(after)", send_flag);
2048 ret = ev->callback(bt_hf_info, buf);
2055 for (ev = hf_event_callbacks; ev->cmd; ev++) {
2056 if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) {
2057 ret = ev->callback(bt_hf_info, buf);
2065 cmd = __bt_hf_agent_find_next(bt_hf_info);
2067 if (cmd && cmd->context) {
2068 DBG("Pending context found for %.6s[%d]", cmd->at_cmd, cmd->id);
2069 g_dbus_method_invocation_return_value(cmd->context, NULL);
2071 g_source_remove(cmd->timer_id);
2077 cmd = __bt_hf_agent_find_next(bt_hf_info);
2079 if (cmd && cmd->pending && send_flag == 0) {
2080 DBG("Pending only found of %.6s[%d]", cmd->at_cmd, cmd->id);
2081 __bt_hf_send_only_without_queue(bt_hf_info,
2082 cmd->at_cmd, cmd->count);
2083 cmd->pending = FALSE;
2084 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
2086 DBG("Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
2089 DBG("Pending free for %.6s[%d] - send_flag = %d",
2090 cmd->at_cmd, cmd->id, send_flag);
2092 g_source_remove(cmd->timer_id);
2098 /* Need to process further pending */
2099 cmd = __bt_hf_agent_find_next(bt_hf_info);
2101 if (cmd->pending && send_flag == 0) {
2102 DBG("2nd Pending only found of %.6s[%d]",
2103 cmd->at_cmd, cmd->id);
2104 __bt_hf_send_only_without_queue(bt_hf_info,
2105 cmd->at_cmd, cmd->count);
2106 cmd->pending = FALSE;
2108 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
2110 DBG("2nd Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
2116 static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf)
2120 int cmd_buf_len = 0;
2121 char *pos_start, *pos_end;
2122 const char *datap = buf;
2124 cmd_buf_len = strlen(cmd_buf);
2125 buf_length = strlen(buf);
2126 DBG("buf_length = %d, cmd_buf_len = %d", buf_length, cmd_buf_len);
2128 if (buf_length > 0 && strstr(datap, "+CLCC")) {
2129 pos_start = strstr(datap, "\r\n");
2130 if (pos_start == NULL) {
2131 ERR("Invalid AT command signature..\n");
2135 pos_end = g_strrstr(datap, "+CLCC");
2136 if (pos_end == NULL) {
2137 ERR("Invalid AT command signature..\n");
2140 pos_end = strstr(pos_end, "\r\n");
2141 cmd_length = (pos_end - pos_start) + 2;
2142 INFO("CLCC balance Cmd Length = %d\n", cmd_length);
2143 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
2144 cmd_buf[cmd_buf_len + cmd_length] = '\0';
2146 if (strstr(cmd_buf, "\r\nOK\r\n")) {
2147 pos_end = strstr(datap, "\r\nOK\r\n");
2148 cmd_length = (pos_end - pos_start);
2149 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
2150 cmd_buf[cmd_buf_len + cmd_length] = '\0';
2151 INFO("New CLCC balance Cmd Length = %d", cmd_length);
2158 static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf)
2162 char *pos_start, *pos_end;
2164 gchar cmd_buf[BT_HF_DATA_BUF_SIZE] = {0,};
2165 const char *datap = buf;
2167 __bt_hf_agent_print_at_buffer("[HF AT CMD] Recv >>>>>:", buf);
2169 buf_length = strlen(buf);
2171 while (buf_length > 0) {
2172 pos_start = strstr(datap, "\r\n");
2173 if (pos_start == NULL) {
2174 ERR("Invalid AT command start signature..\n");
2179 pos_end = strstr(datap, "\r\n");
2180 if (pos_end == NULL) {
2181 ERR("Invalid AT command end signature..\n");
2184 cmd_length = (pos_end - pos_start) + 2;
2185 DBG("Cmd Length = %d\n", cmd_length);
2187 if (cmd_length > BT_HF_DATA_BUF_SIZE - 1)
2189 memcpy(cmd_buf, pos_start, cmd_length);
2190 cmd_buf[cmd_length] = '\0';
2192 buf_length = buf_length - cmd_length;
2193 datap = datap + cmd_length - 2;
2195 /* We need to pass all the CLCC's together to its handler */
2196 if (strstr(cmd_buf, "+CLCC")) {
2197 tmp = hf_handle_append_clcc_buff(cmd_buf, datap);
2199 buf_length = buf_length - tmp;
2201 hf_handle_rx_at_cmd(bt_hf_info, cmd_buf);
2202 DBG("Pending buf_length = %d\n", buf_length);
2207 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
2208 bt_hf_agent_info_t *bt_hf_info)
2210 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2212 GError *gerr = NULL;
2213 gboolean recvd_ok = FALSE;
2214 gboolean recvd_error = FALSE;
2215 gboolean recvd_sec_error = FALSE;
2217 if (cond & (G_IO_ERR | G_IO_HUP)) {
2218 ERR("ERR or HUP on RFCOMM socket");
2219 INFO_C("### Disconnected [HF role] [Terminated by remote dev]");
2220 is_hf_connected = FALSE;
2221 bt_hf_info->slc = FALSE;
2222 __bt_hf_agent_release();
2226 if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, &gerr)
2227 != G_IO_STATUS_NORMAL) {
2229 ERR("Read failed, cond = [%d], Err msg = [%s]",
2230 cond, gerr->message);
2236 recvd_ok = NULL != strstr(buf, BT_HF_OK_RESPONSE);
2237 recvd_error = NULL != strstr(buf, BT_HF_ERROR_RESPONSE);
2238 recvd_sec_error = NULL != strstr(buf, BT_HF_SEC_ERROR_RESPONSE);
2239 DBG("<-------Received data --send flag status = %d ----->", send_flag);
2241 /* Once service level connection is established we need to handle
2242 * all the intermediate AT commands */
2243 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2247 strncat(global_buff, buf,
2248 (BT_AT_COMMAND_BUFFER_MAX - 1) - strlen(global_buff));
2249 if (!(recvd_ok || recvd_error || recvd_sec_error)) {
2250 __bt_hf_agent_print_at_buffer("Concat ()", global_buff);
2252 DBG("*** Received terminator.. process Rx buffer ***");
2253 hf_handle_rx_at_buff(bt_hf_info, global_buff);
2254 memset(global_buff, 0, sizeof(global_buff));
2257 INFO("*** Received Direct AT buffer packet handling ****");
2258 hf_handle_rx_at_buff(bt_hf_info, buf);
2263 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info)
2265 bt_hf_info->watch_id = g_io_add_watch(bt_hf_info->io_chan,
2266 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2267 (GIOFunc) __bt_hf_agent_data_cb, bt_hf_info);
2270 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info)
2272 if (bt_hf_info->watch_id > 0) {
2273 g_source_remove(bt_hf_info->watch_id);
2274 bt_hf_info->watch_id = 0;
2278 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
2285 status = g_io_channel_write_chars(io, data, count, &written,
2287 if (status != G_IO_STATUS_NORMAL)
2296 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
2297 gchar *data, gsize count)
2299 GIOChannel *io_chan = bt_hf_info->io_chan;
2300 if (!__bt_hf_channel_write(io_chan, data, count))
2303 g_io_channel_flush(io_chan, NULL);
2305 if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
2306 INFO("[HF AT CMD] Send only without queue <<<<<: Buffer = %s, Length = %zd ",
2307 "ATDXXXXXXX", count);
2308 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
2310 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send only without queue <<<<<:",
2315 /* DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2316 * send_flag, count, data); */
2321 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
2324 gboolean pending = FALSE;
2325 GIOChannel *io_chan = bt_hf_info->io_chan;
2330 __bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
2335 if (!__bt_hf_channel_write(io_chan, data, count))
2338 g_io_channel_flush(io_chan, NULL);
2340 if (count > 2 && data[2] == 'D') /* ATDXXXXX */
2341 INFO("[HF AT CMD] Send only <<<<<: Buffer = %s, Length = %zd ",
2342 "ATDXXXXXXX", count);
2344 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send only <<<<<:",
2348 DBG("Ref %d(after) on Send only buffer size =[%zd] - Send <<<<<",
2353 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
2354 gchar *data, gchar *response, gsize count)
2356 GIOChannel *io_chan = bt_hf_info->io_chan;
2358 gboolean recvd_ok = FALSE;
2359 gboolean recvd_error = FALSE;
2360 gboolean recvd_sec_error = FALSE;
2361 gchar *resp_buf = response;
2362 gsize toread = BT_HF_DATA_BUF_SIZE - 1;
2367 GDBusConnection *conn;
2369 /* Should not send cmds if DUT send a command and wait the response */
2370 if (prev_cmd[0] != 0) {
2371 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
2375 memset(resp_buf, 0, BT_HF_DATA_BUF_SIZE);
2377 if (!__bt_hf_channel_write(io_chan, data, count))
2380 g_io_channel_flush(io_chan, NULL);
2382 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send <<<<<:", data);
2384 fd = g_io_channel_unix_get_fd(io_chan);
2386 p.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
2388 /* Maximun 8 seconds of poll or 8 minus no of cmd received */
2389 for (i = 1; i <= MAX_WAITING_DELAY; i++) {
2390 DBG("Loop Counter = %d", i);
2392 err = poll(&p, 1, 1000);
2394 ERR("Loop Counter = %d, >>>> Poll error happen", i);
2396 } else if (err == 0) {
2397 INFO("Loop Counter = %d, >>>> Poll Timeout", i);
2400 if (p.revents & (POLLERR | POLLHUP | POLLNVAL)) {
2401 ERR("Loop Counter = %d, >> Poll ERR/HUP/INV (%d)",
2404 conn = __bt_hf_get_gdbus_connection();
2406 ERR("Unable to get connection");
2410 __bt_hf_agent_emit_signal(conn,
2411 BT_HF_AGENT_OBJECT_PATH,
2412 BT_HF_SERVICE_INTERFACE,
2414 g_variant_new("(s)",
2415 bt_hf_info->remote_addr));
2417 bt_hf_info->state = BT_HF_STATE_DISCONNECTED;
2421 if (p.revents & POLLIN) {
2422 rd_size = read(fd, resp_buf, toread);
2423 resp_buf[rd_size] = '\0';
2424 DBG_SECURE("size = %zd, Buffer=[%s]", rd_size, resp_buf);
2425 recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
2426 recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
2427 recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
2429 resp_buf += rd_size;
2432 if (recvd_ok || recvd_error || recvd_sec_error) {
2433 DBG("Break Loop Counter = %d", i);
2439 /* Once service level connection is established we need to handle
2440 * all the intermediate AT commands */
2441 if (bt_hf_info->state == BT_HF_STATE_CONNECTED)
2442 hf_handle_rx_at_buff(bt_hf_info, response);
2446 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indices)
2448 struct indicator *ind;
2449 gchar *cur = names - 1;
2450 GSList *list = indices;
2453 DBG("Indicator buffer = %s", names);
2454 __bt_hf_agent_print_at_buffer("Indicator names :", names);
2455 while (cur != NULL) {
2457 next = strstr(cur, ",(");
2458 ind = g_new0(struct indicator, 1);
2459 g_strlcpy(ind->descr, cur, BT_HF_INDICATOR_DESCR_SIZE);
2460 ind->descr[(intptr_t) next - (intptr_t) cur] = '\0';
2461 list = g_slist_append(list, (gpointer) ind);
2462 cur = strstr(next + 1, ",(");
2467 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices)
2470 struct indicator *ind;
2471 GSList *runner = indices;
2473 gchar *cur = values - 1;
2474 DBG("Indicator string = %s", values);
2475 __bt_hf_agent_print_at_buffer("Indicator values :", values);
2476 while (cur != NULL) {
2478 sscanf(cur, "%1d", &val);
2479 cur = strchr(cur, ',');
2480 ind = g_slist_nth_data(runner, 0);
2483 runner = g_slist_next(runner);
2490 static guint __bt_hf_get_hold_mpty_features(gchar *features)
2494 if (strstr(features, "0"))
2495 result |= BT_HF_CHLD_0;
2497 if (strstr(features, "1"))
2498 result |= BT_HF_CHLD_1;
2500 if (strstr(features, "1x"))
2501 result |= BT_HF_CHLD_1x;
2503 if (strstr(features, "2"))
2504 result |= BT_HF_CHLD_2;
2506 if (strstr(features, "2x"))
2507 result |= BT_HF_CHLD_2x;
2509 if (strstr(features, "3"))
2510 result |= BT_HF_CHLD_3;
2512 if (strstr(features, "4"))
2513 result |= BT_HF_CHLD_4;
2518 static gboolean __bt_hf_agent_sco_disconnect_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2520 bt_hf_agent_info_t *bt_hf_info = user_data;
2521 GDBusConnection *conn;
2524 if (cond & G_IO_NVAL)
2527 if (cond & (G_IO_HUP | G_IO_ERR)) {
2528 g_io_channel_shutdown(chan, TRUE, NULL);
2529 close(bt_hf_info->cli_sco_fd);
2530 bt_hf_info->cli_sco_fd = -1;
2531 g_io_channel_unref(chan);
2532 DBG("Emit AudioDisconnected Signal");
2534 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2536 conn = __bt_hf_get_gdbus_connection();
2538 ERR("Unable to get connection");
2541 __bt_hf_agent_emit_signal(conn,
2542 BT_HF_AGENT_OBJECT_PATH,
2543 BT_HF_SERVICE_INTERFACE,
2544 "AudioDisconnected", NULL);
2552 static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2554 bt_hf_agent_info_t *bt_hf_info = user_data;
2558 GDBusConnection *conn;
2560 INFO("Incoming SCO....");
2562 if (cond & G_IO_NVAL)
2565 sco_skt = g_io_channel_unix_get_fd(chan);
2567 if (cond & (G_IO_HUP | G_IO_ERR)) {
2572 cli_sco_sock = accept(sco_skt, NULL, NULL);
2573 if (cli_sco_sock < 0)
2576 bt_hf_info->cli_sco_fd = cli_sco_sock;
2578 sco_io = g_io_channel_unix_new(cli_sco_sock);
2579 g_io_channel_set_close_on_unref(sco_io, TRUE);
2580 g_io_channel_set_encoding(sco_io, NULL, NULL);
2581 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2582 g_io_channel_set_buffered(sco_io, FALSE);
2584 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2585 __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
2587 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2588 ERR("HFP is not yet connected");
2590 /* S-Voice app requires the AudioConnected signal earlier */
2591 DBG("Emit AudioConnected Signal");
2593 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
2595 conn = __bt_hf_get_gdbus_connection();
2597 ERR("Unable to get connection");
2601 __bt_hf_agent_emit_signal(conn,
2602 BT_HF_AGENT_OBJECT_PATH,
2603 BT_HF_SERVICE_INTERFACE,
2604 "AudioConnected", NULL);
2606 /* In the case of incoming call, the call app is already launched,
2607 * hence AudioConnected signal is enough to update the call status.
2608 * In the case of outgoing call we need to lauch the callapp.
2611 __bt_hf_agent_launch_call_app();
2616 static void __bt_convert_addr_string_to_type_rev(unsigned char *addr,
2617 const char *address)
2622 ret_if(address == NULL);
2623 ret_if(addr == NULL);
2625 for (i = 0; i < BT_ADDRESS_LENGTH_MAX; i++) {
2626 addr[5 - i] = strtol(address, &ptr, 16);
2627 if (ptr[0] != '\0') {
2636 static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
2638 struct sockaddr_sco addr;
2640 bdaddr_t bd_addr = {{0},};
2644 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
2646 ERR("Can't create socket:\n");
2650 /* Bind to local address */
2651 memset(&addr, 0, sizeof(addr));
2652 addr.sco_family = AF_BLUETOOTH;
2654 DBG("Bind to address %s", bt_hf_info->remote_addr);
2656 __bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
2657 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2659 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2660 ERR("Can't bind socket:\n");
2664 if (listen(sco_skt, 1)) {
2665 ERR("Can not listen on the socket:\n");
2669 sco_io = g_io_channel_unix_new(sco_skt);
2670 g_io_channel_set_close_on_unref(sco_io, TRUE);
2671 g_io_channel_set_encoding(sco_io, NULL, NULL);
2672 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2673 g_io_channel_set_buffered(sco_io, FALSE);
2675 bt_hf_info->sco_fd = sco_skt;
2676 bt_hf_info->sco_io_chan = sco_io;
2678 bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
2679 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
2681 g_io_channel_unref(sco_io);
2690 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
2692 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2695 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
2696 sizeof(BT_HF_INDICATORS_SUPP) - 1);
2697 if (!ret || !strstr(buf, "+CIND:"))
2700 bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
2705 static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
2710 if (bt_hf_info == NULL || cmd == NULL) {
2711 ERR("Invalid parameter");
2715 ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
2717 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
2718 ret = g_strlcat(cmd, "0,", cmd_size);
2719 if (ret >= cmd_size) {
2720 ERR("Too many indices");
2726 cmd[ret - 1] = '\0';
2727 DBG("BIA Str : %s", cmd);
2729 ret = g_strlcat(cmd, "\r", cmd_size);
2730 if (ret >= cmd_size) {
2731 ERR("Too many indices");
2738 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
2740 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2746 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
2747 sizeof(BT_HF_INDICATORS_VAL) - 1);
2748 if (!ret || !strstr(buf, "+CIND:"))
2751 /* if buf has other command prefix, skip it */
2752 str = strstr(buf, "+CIND");
2756 bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
2758 /* Parse the updated value */
2759 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
2760 struct indicator *ind = l->data;
2762 DBG("Index is NULL");
2766 if (0 == g_strcmp0(ind->descr, "\"call\"")) {
2767 DBG("CIND Match found index = %d, %s, value = %d",
2768 index, ind->descr, ind->value);
2769 bt_hf_info->ciev_call_status = ind->value;
2770 if (ind->value > 0) {
2771 bt_hf_info->is_dialing = FALSE;
2772 bt_hf_info->call_active = TRUE;
2774 } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
2775 DBG("CIND Match found index = %d, %s, value = %d",
2776 index, ind->descr, ind->value);
2777 bt_hf_info->ciev_call_setup_status = ind->value;
2778 if (!bt_hf_info->is_dialing && ind->value > 0)
2779 bt_hf_info->is_dialing = TRUE;
2786 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
2788 gchar buf[BT_HF_DATA_BUF_SIZE];
2789 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
2792 guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
2793 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
2794 BT_HF_FEATURE_CLI_PRESENTATION |
2795 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
2796 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
2798 if (TIZEN_PROFILE_WEARABLE)
2799 feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
2801 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
2802 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
2807 buf_ptr = strstr(buf, "\r\n+BRSF:");
2808 if (buf_ptr == NULL)
2811 if (!ret || sscanf(buf_ptr, "\r\n+BRSF:%5d", &bt_hf_info->ag_features) != 1)
2813 INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
2815 if (TIZEN_PROFILE_WEARABLE) {
2816 if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
2817 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
2818 if (ret != BT_HF_AGENT_ERROR_NONE)
2819 ERR("Unable to set the default WBC codec");
2821 ret = __bt_hf_send_available_codec(bt_hf_info, 0);
2826 /* Default codec is NB */
2827 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
2828 if (ret != BT_HF_AGENT_ERROR_NONE)
2829 ERR("Unable to set the default NBC codec");
2832 ret = __bt_get_supported_indicators(bt_hf_info);
2837 ret = __bt_get_current_indicators(bt_hf_info);
2841 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
2842 sizeof(BT_HF_INDICATORS_ENABLE) - 1);
2843 if (!ret || !strstr(buf, "OK"))
2846 if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
2847 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
2848 buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
2849 if (!ret || !strstr(buf, "+CHLD:")) {
2850 ERR("Unable to get the CHLD Supported info");
2853 bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
2856 bt_hf_info->hold_multiparty_features = 0;
2858 if (bt_hf_info->ag_features & BT_AG_FEATURE_INBAND_RINGTONE)
2859 bt_hf_info->inband_ringtone_support = TRUE;
2861 bt_hf_info->inband_ringtone_support = FALSE;
2863 INFO("Service layer connection successfully established...!");
2865 bt_hf_info->slc = TRUE;
2868 memset(global_buff, 0, sizeof(global_buff));
2872 static void __bt_establish_initialization(bt_hf_agent_info_t *bt_hf_info)
2874 gchar buf[BT_HF_DATA_BUF_SIZE];
2875 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
2878 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
2879 sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
2880 __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
2881 sizeof(BT_HF_CARRIER_FORMAT) - 1);
2882 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
2883 sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
2885 if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
2886 __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
2887 sizeof(BT_HF_NREC) - 1);
2889 if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
2890 __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
2891 buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
2893 if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
2894 __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
2896 ERR("__bt_get_bia_cmd is failed");
2898 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
2899 sizeof(BT_HF_XSAT) - 1);
2901 DBG("sent BT_HF_XSAT");
2903 ERR("BT_HF_XSAT sending failed");
2905 if (TIZEN_PROFILE_WEARABLE) {
2906 /* send Bluetooth Samsung Support Feature cmd */
2907 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
2908 sizeof(BT_HF_BSSF) - 1);
2910 /* If we got a 'OK' reply, peer AG is samsung device.
2911 * Otherwise, non-samsung device */
2912 if (ret && strstr(buf, "OK"))
2913 bt_hf_info->is_companion_dev = TRUE;
2915 bt_hf_info->is_companion_dev = FALSE;
2918 INFO("SLC completed with [%s] device",
2919 bt_hf_info->is_companion_dev ? "SS Companion" : "Other");
2921 ERR("BT_HF_BSSF sending failed");
2925 static void __bt_hf_agent_sigterm_handler(int signo)
2927 GDBusConnection *conn;
2930 ERR_C("***** Signal handler came with signal %d *****", signo);
2932 conn = __bt_hf_get_gdbus_connection();
2934 ERR("Unable to get G-DBus connection");
2937 INFO("Getting gdbus connection done");
2939 __bt_hf_agent_emit_signal(conn,
2940 BT_HF_AGENT_OBJECT_PATH,
2941 BT_HF_SERVICE_INTERFACE,
2943 INFO("CallEnded Signal done");
2945 g_dbus_connection_flush(conn, NULL, NULL, NULL);
2946 INFO("Flush g_dbus_connection");
2950 g_main_loop_quit(gmain_loop);
2954 INFO_C("Terminating HF agent");
2958 if (signo == SIGTERM)
2961 for (i = 0; i < BT_HF_SIG_NUM; i++)
2962 sigaction(bt_hf_sig_to_handle[i], &(bt_hf_sigoldact[i]), NULL);
2967 static void __bt_convert_addr_type_to_rev_string(char *address,
2968 unsigned char *addr)
2970 ret_if(address == NULL);
2971 ret_if(addr == NULL);
2973 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
2974 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
2975 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
2979 static gboolean __bt_hf_agent_release_after(gpointer user_data)
2981 if (__bt_hf_agent_release() == FALSE)
2982 ERR("Unable to release hf connection");
2987 static gboolean __bt_agent_request_service_level_conn(gpointer data)
2990 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
2991 GDBusConnection *conn;
2994 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
2996 __bt_hf_agent_sco_accept(&bt_hf_info);
2998 if (!__bt_establish_service_level_conn(&bt_hf_info)) {
2999 ERR("Service Level Connection is fail");
3001 conn = __bt_hf_get_gdbus_connection();
3003 remote_addr = bt_hf_info.remote_addr;
3004 __bt_hf_agent_emit_signal(conn,
3005 BT_HF_AGENT_OBJECT_PATH,
3006 BT_HF_SERVICE_INTERFACE,
3008 g_variant_new("(s)", remote_addr));
3010 bt_hf_info.state = BT_HF_STATE_CONNECTED;
3012 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3013 DBG("BT device state is : 0x%X", bt_device_state);
3014 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3015 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3016 ERR("vconf_set_int failed");
3018 ERR("vconf_get_int failed");
3021 g_idle_add(__bt_hf_agent_release_after, NULL);
3026 bt_hf_info.state = BT_HF_STATE_CONNECTED;
3028 __bt_hf_agent_start_watch(&bt_hf_info);
3030 remote_addr = bt_hf_info.remote_addr;
3032 INFO_SECURE("Address is : %s", remote_addr);
3033 INFO_C("### Connected [HF role]");
3035 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3036 DBG("BT device state is : 0x%X", bt_device_state);
3037 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3039 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3040 ERR("vconf_set_int failed");
3042 ERR("vconf_get_int failed");
3045 conn = __bt_hf_get_gdbus_connection();
3047 ERR("Unable to get connection");
3051 __bt_hf_agent_emit_signal(conn,
3052 BT_HF_AGENT_OBJECT_PATH,
3053 BT_HF_SERVICE_INTERFACE,
3055 g_variant_new("(s)", remote_addr));
3057 /* Establish the initialization */
3058 __bt_establish_initialization(&bt_hf_info);
3065 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
3069 struct sockaddr_remote address;
3070 socklen_t address_len;
3071 bt_hf_info.path = g_strdup(obj_path);
3073 INFO_C("**** New HFP connection ****");
3075 is_hf_connected = TRUE;
3077 address_len = sizeof(address);
3078 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
3079 ERR("BD_ADDR is NULL");
3081 DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
3083 bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
3084 flags = g_io_channel_get_flags(bt_hf_info.io_chan);
3086 flags &= ~G_IO_FLAG_NONBLOCK;
3087 flags &= G_IO_FLAG_MASK;
3088 g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
3089 g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
3090 g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
3092 bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
3093 __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
3094 address.remote_bdaddr.b);
3096 g_idle_add(__bt_agent_request_service_level_conn, NULL);
3101 static void __bt_hf_agent_indicator_free(gpointer mem)
3106 static gboolean __bt_hf_agent_release(void)
3108 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
3109 GDBusConnection *conn;
3112 g_source_remove(clcc_timer);
3116 if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
3117 ERR("hf is already disconnected");
3121 if (bt_hf_info.indies) {
3122 g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
3123 bt_hf_info.indies = NULL;
3126 if (bt_hf_info.io_chan) {
3127 g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
3128 g_io_channel_unref(bt_hf_info.io_chan);
3129 bt_hf_info.io_chan = NULL;
3132 if (bt_hf_info.sco_watch_id > 0) {
3133 g_source_remove(bt_hf_info.sco_watch_id);
3134 bt_hf_info.sco_watch_id = 0;
3137 bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
3139 __bt_hf_agent_release_queue();
3141 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3142 DBG("BT device state is : 0x%X", bt_device_state);
3143 bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3145 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3146 ERR("vconf_set_int failed");
3148 ERR("vconf_get_int failed");
3151 __bt_hf_agent_stop_watch(&bt_hf_info);
3152 conn = __bt_hf_get_gdbus_connection();
3154 ERR("Unable to get connection");
3158 __bt_hf_agent_emit_signal(conn,
3159 BT_HF_AGENT_OBJECT_PATH,
3160 BT_HF_SERVICE_INTERFACE,
3162 g_variant_new("(s)", bt_hf_info.remote_addr));
3164 g_free(bt_hf_info.path);
3165 bt_hf_info.path = NULL;
3167 g_free(bt_hf_info.remote_addr);
3168 bt_hf_info.remote_addr = NULL;
3170 is_hf_connected = FALSE;
3175 static gboolean __bt_hf_agent_connection_release(void)
3177 return __bt_hf_agent_release();
3180 static int __bt_hf_register_profile(const char *uuid, uint16_t version,
3181 const char *name, const char *object, uint16_t features)
3186 GError *error = NULL;
3187 GVariantBuilder *builder;
3190 proxy = __bt_hf_gdbus_get_profile_proxy();
3193 return BT_HF_AGENT_ERROR_INTERNAL;
3195 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3197 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3199 g_variant_builder_add(builder, "{sv}",
3200 "Name", g_variant_new("s",
3202 g_variant_builder_add(builder, "{sv}",
3203 "Version", g_variant_new("q", version));
3205 g_variant_builder_add(builder, "{sv}",
3206 "features", g_variant_new("q", features));
3208 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3209 g_variant_new("(osa{sv})", path,
3210 HFP_HF_UUID, builder),
3211 G_DBUS_CALL_FLAGS_NONE, -1,
3214 g_variant_builder_unref(builder);
3217 /* dBUS-RPC is failed */
3218 ERR("dBUS-RPC is failed");
3219 if (error != NULL) {
3220 /* dBUS gives error cause */
3221 ERR("D-Bus API failure: errCode[%x], message[%s]",
3222 error->code, error->message);
3223 g_clear_error(&error);
3226 return BT_HF_AGENT_ERROR_INTERNAL;
3228 g_variant_unref(ret);
3232 return BT_HF_AGENT_ERROR_NONE;
3235 static void __bt_hf_agent_register(void)
3240 uint16_t version = hf_ver;
3241 uint16_t features = bt_hf_info.feature;
3243 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3244 name = g_strdup("Hands-Free");
3246 ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
3249 ERR("Error in register");
3258 static void __bt_hf_agent_unregister(void)
3262 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3265 __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
3266 g_variant_new("(o)", path),
3267 BLUEZ_HF_INTERFACE_NAME,
3279 static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
3280 const gchar *sender_name,
3281 const gchar *object_path,
3282 const gchar *interface_name,
3283 const gchar *signal_name,
3284 GVariant *parameters,
3290 GVariant *optional_param;
3292 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3294 g_variant_get(parameters, "(&o@a{sa{sv}})",
3295 &path, &optional_param);
3297 ERR("Invalid adapter path");
3301 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3302 g_obj_path = g_strdup(path);
3303 INFO("Adapter Path = [%s]", path);
3304 __bt_hf_agent_register();
3306 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
3307 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
3309 __bt_hf_agent_unregister();
3314 static int __bt_hf_agent_get_adapter_path(GDBusConnection *conn, char *path)
3317 GDBusProxy *manager_proxy = NULL;
3318 GVariant *result = NULL;
3319 char *adapter_path = NULL;
3322 return BT_HF_AGENT_ERROR_INTERNAL;
3324 manager_proxy = g_dbus_proxy_new_sync(conn,
3325 G_DBUS_PROXY_FLAGS_NONE, NULL,
3328 BT_MANAGER_INTERFACE,
3331 if (!manager_proxy) {
3332 ERR("Unable to create proxy: %s", err->message);
3336 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
3337 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
3340 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
3342 ERR("Fail to get DefaultAdapter");
3347 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
3348 ERR("Incorrect result\n");
3352 g_variant_get(result, "(&o)", &adapter_path);
3354 if (adapter_path == NULL ||
3355 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
3356 ERR("Adapter path is inproper\n");
3361 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
3363 if (g_obj_path == NULL) {
3364 g_obj_path = g_strdup(adapter_path);
3365 INFO("Update g_obj_path [%s]", adapter_path);
3368 g_variant_unref(result);
3369 g_object_unref(manager_proxy);
3374 g_clear_error(&err);
3377 g_variant_unref(result);
3380 g_object_unref(manager_proxy);
3382 return BT_HF_AGENT_ERROR_INTERNAL;
3386 static void __bt_hf_agent_dbus_init(void)
3388 GDBusConnection *conn;
3392 conn = __bt_hf_get_gdbus_connection();
3394 ERR("Error in creating the gdbus connection\n");
3397 if (!__bt_hf_register_profile_methods()) {
3398 ERR("Error in register_profile_methods\n");
3402 if (!__bt_hf_agent_get_adapter_path(gdbus_conn , NULL)) {
3403 __bt_hf_agent_register();
3406 interface_added_sig_id = g_dbus_connection_signal_subscribe(conn,
3407 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0,
3408 __bt_hf_agent_filter_cb, NULL, NULL);
3410 interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
3411 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
3412 __bt_hf_agent_filter_cb, NULL, NULL);
3417 static void __bt_hf_agent_dbus_deinit(void)
3419 if (profile_gproxy) {
3420 g_object_unref(profile_gproxy);
3421 profile_gproxy = NULL;
3425 if (interface_added_sig_id > 0)
3426 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3427 interface_added_sig_id);
3429 if (interface_removed_sig_id > 0)
3430 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3431 interface_removed_sig_id);
3433 interface_added_sig_id = 0;
3434 interface_removed_sig_id = 0;
3436 g_object_unref(gdbus_conn);
3441 static int _hf_agent_answer_call(GDBusMethodInvocation *context)
3446 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3447 ERR("HF not Connected");
3448 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3450 bt_hf_info.context = context;
3452 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
3453 sizeof(BT_HF_ANSWER_CALL) - 1);
3455 return BT_HF_AGENT_ERROR_INTERNAL;
3458 return BT_HF_AGENT_ERROR_NONE;
3462 static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
3467 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3468 ERR("HF not Connected");
3469 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3472 bt_hf_info.context = context;
3474 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
3475 sizeof(BT_HF_END_CALL) - 1);
3477 return BT_HF_AGENT_ERROR_INTERNAL;
3480 return BT_HF_AGENT_ERROR_NONE;
3483 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
3486 int prev_cmd_len = 0;
3487 char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
3489 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3490 ERR("HF not Connected");
3491 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3494 bt_hf_info.context = context;
3496 if (strlen(no) > 0) {
3497 snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
3499 if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
3500 && bt_hf_info.ciev_call_setup_status == 0) {
3501 INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
3502 ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
3506 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3509 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3510 prev_cmd_len = snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
3512 if (prev_cmd_len < 0) {
3513 ERR("Encoding error occured in snprintf");
3514 return BT_HF_AGENT_ERROR_INTERNAL;
3518 return BT_HF_AGENT_ERROR_INTERNAL;
3520 return BT_HF_AGENT_ERROR_NONE;
3523 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3524 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
3526 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
3527 sizeof(BT_HF_REDIAL) - 1);
3529 return BT_HF_AGENT_ERROR_INTERNAL;
3531 return BT_HF_AGENT_ERROR_NONE;
3534 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
3539 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3540 ERR("HF not Connected");
3541 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3544 snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
3546 bt_hf_info.context = context;
3548 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3550 return BT_HF_AGENT_ERROR_INTERNAL;
3553 return BT_HF_AGENT_ERROR_NONE;
3556 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
3561 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3562 ERR("HF not Connected");
3563 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3566 if (gain > BT_HF_MAX_SPEAKER_GAIN)
3567 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3569 snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
3571 bt_hf_info.context = context;
3573 ret = __bt_hf_send_only(&bt_hf_info, buf,
3576 return BT_HF_AGENT_ERROR_INTERNAL;
3578 return BT_HF_AGENT_ERROR_NONE;
3582 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
3587 if (strlen(dtmf) <= 0)
3588 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3590 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3591 ERR("HF not Connected");
3592 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3595 snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
3597 bt_hf_info.context = context;
3599 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3601 return BT_HF_AGENT_ERROR_INTERNAL;
3604 return BT_HF_AGENT_ERROR_NONE;
3608 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
3612 if (strlen(cmd) <= 0)
3613 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3615 bt_hf_info.context = context;
3617 ret = __bt_hf_send_only(&bt_hf_info, cmd,
3620 return BT_HF_AGENT_ERROR_INTERNAL;
3622 return BT_HF_AGENT_ERROR_NONE;
3625 static gboolean bt_hf_agent_sco_connect(void)
3627 struct sockaddr_sco addr;
3628 bdaddr_t bd_addr = {{0},};
3631 GDBusConnection *conn;
3635 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3636 ERR("HF RFCOMM not Connected");
3640 if (bt_hf_info.cli_sco_fd > 0) {
3641 ERR("SCO Already connected..");
3646 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
3648 ERR("Can't create SCO socket");
3652 /* Bind to local address */
3653 memset(&addr, 0, sizeof(addr));
3654 addr.sco_family = AF_BLUETOOTH;
3655 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
3657 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3658 ERR("Can't bind socket");
3662 /* Connect to remote device */
3663 memset(&addr, 0, sizeof(addr));
3664 addr.sco_family = AF_BLUETOOTH;
3665 __bt_convert_addr_string_to_type_rev(addr.sco_bdaddr.b, bt_hf_info.remote_addr);
3666 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3667 ERR("Can't connect");
3671 DBG("SCO Connected");
3673 bt_hf_info.cli_sco_fd = sk;
3675 sco_io = g_io_channel_unix_new(sk);
3676 g_io_channel_set_close_on_unref(sco_io, TRUE);
3677 g_io_channel_set_encoding(sco_io, NULL, NULL);
3678 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
3679 g_io_channel_set_buffered(sco_io, FALSE);
3681 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
3682 __bt_hf_agent_sco_disconnect_cb, &bt_hf_info);
3684 DBG("Emit AudioConnected Signal - Outgoing SCo connection");
3685 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
3687 conn = __bt_hf_get_gdbus_connection();
3689 ERR("Unable to get connection");
3693 __bt_hf_agent_emit_signal(conn,
3694 BT_HF_AGENT_OBJECT_PATH,
3695 BT_HF_SERVICE_INTERFACE,
3696 "AudioConnected", NULL);
3707 static gboolean bt_hf_agent_sco_disconnect(void)
3710 GDBusConnection *conn;
3712 close(bt_hf_info.cli_sco_fd);
3713 bt_hf_info.cli_sco_fd = -1;
3715 DBG("Emit AudioDisconnected Signal");
3716 conn = __bt_hf_get_gdbus_connection();
3718 ERR("Unable to get connection");
3722 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
3724 __bt_hf_agent_emit_signal(conn,
3725 BT_HF_AGENT_OBJECT_PATH,
3726 BT_HF_SERVICE_INTERFACE,
3727 "AudioDisconnected", NULL);
3732 static GVariant *bt_hf_agent_request_call_list(void)
3734 GSList *call_list = NULL;
3738 call_list = __bt_hf_get_call_list(&bt_hf_info);
3740 INFO("call list is NULL");
3744 var_data = __bt_hf_agent_get_call_status_info(call_list);
3745 __bt_hf_free_call_list(call_list);
3751 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
3755 char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
3760 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3762 if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
3763 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3765 strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
3766 strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
3768 bt_hf_info.context = context;
3770 ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
3772 return BT_HF_AGENT_ERROR_INTERNAL;
3775 return BT_HF_AGENT_ERROR_NONE;
3778 static uint32_t __bt_hf_agent_get_hf_features(void)
3780 uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
3781 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
3782 BT_HF_FEATURE_CLI_PRESENTATION |
3783 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3784 BT_HF_FEATURE_ENHANCED_CALL_STATUS |
3785 BT_HF_FEATURE_CODEC_NEGOTIATION;
3787 if (TIZEN_PROFILE_WEARABLE)
3788 hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
3790 hf_ver = HFP_VERSION_1_6;
3798 struct sigaction sa;
3799 uint32_t hf_features;
3801 INFO_C("### Starting Bluetooth HF agent");
3803 #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36
3806 hf_features = __bt_hf_agent_get_hf_features();
3807 bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
3809 memset(&sa, 0, sizeof(sa));
3810 sa.sa_flags = SA_NOCLDSTOP;
3811 sa.sa_handler = __bt_hf_agent_sigterm_handler;
3813 for (i = 0; i < BT_HF_SIG_NUM; i++)
3814 sigaction(bt_hf_sig_to_handle[i], &sa, &(bt_hf_sigoldact[i]));
3816 g_log_set_default_handler(__on_log_glib, NULL);
3818 gmain_loop = g_main_loop_new(NULL, FALSE);
3820 if (gmain_loop == NULL) {
3821 ERR("GMainLoop create failed\n");
3822 return EXIT_FAILURE;
3825 __bt_hf_agent_dbus_init();
3827 g_main_loop_run(gmain_loop);
3829 __bt_hf_agent_dbus_deinit();
3832 g_main_loop_unref(gmain_loop);
3834 INFO_C("### Terminating Bluetooth HF agent");