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"
47 #define HFP_SCO_DATA_BUFFER_SIZE 48
48 #define HFP_FHUB_SAMPLE_RATE 8000
50 #define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3
51 #define CALL_ALIAS_APP_ID "org.tizen.call-ui"
53 #define MAX_WAITING_DELAY 8
54 #define READ_TX_POWER_MIN -30
56 #define BT_ADDRESS_STRING_SIZE 18
57 #define BT_AT_COMMAND_BUFFER_MAX 4000
58 #define BT_HF_ERROR_RESP "\r\nERROR\r\n"
59 #define BT_HF_COMMAND_TIMEOUT 3
61 #define ret_if(expr) \
64 ERR("(%s) return", #expr); \
69 static GMainLoop *gmain_loop = NULL;
70 static char *g_obj_path;
72 static GDBusConnection *gdbus_conn = NULL;
73 static GDBusProxy *profile_gproxy = NULL;
74 static guint interface_added_sig_id;
75 static guint interface_removed_sig_id;
80 int clcc_retry_count = 0;
81 guint clcc_async_timer = 0;
82 int clcc_async_retry_count = 0;
83 #define CLCC_RETRY_COUNT 10
84 #define CLCC_RETRY_TIMER 100 /* 100 msec */
86 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
87 #define PBAP_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb"
88 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
90 /*Below Inrospection data is exposed to bluez from agent*/
91 static const gchar hf_agent_bluez_introspection_xml[] =
93 " <interface name='org.bluez.Profile1'>"
94 " <method name='NewConnection'>"
95 " <arg type='o' name='device' direction='in'/>"
96 " <arg type='h' name='fd' direction='in'/>"
97 " <arg type='a{sv}' name='options' direction='in'/>"
99 " <method name='RequestDisconnection'>"
100 " <arg type='o' name='device' direction='in'/>"
105 /*Below Inrospection data is exposed to application from agent*/
106 static const gchar hf_agent_introspection_xml[] =
108 " <interface name='org.tizen.HfApp'>"
109 " <method name='AnswerCall'>"
111 " <method name='TerminateCall'>"
113 " <method name='InitiateCall'>"
114 " <arg type='s' name='phoneno' direction='in'/>"
116 " <method name='VoiceRecognition'>"
117 " <arg type='i' name='status' direction='in'/>"
119 " <method name='ScoConnect'>"
121 " <method name='ScoDisconnect'>"
123 " <method name='SpeakerGain'>"
124 " <arg type='u' name='gain' direction='in'/>"
126 " <method name='SendDtmf'>"
127 " <arg type='s' name='dtmf' direction='in'/>"
129 " <method name='SendAtCmd'>"
130 " <arg type='s' name='atcmd' direction='in'/>"
132 " <method name='ReleaseAndAccept'>"
134 " <method name='CallSwap'>"
136 " <method name='ReleaseAllCall'>"
138 " <method name='JoinCall'>"
140 " <method name='GetCurrentCodec'>"
141 " <arg type='i' name='codec' direction='out'/>"
143 " <method name='RequestCallList'>"
144 " <arg type='i' name='count' direction='out'/>"
145 " <arg type='a(siiii)' name='callList' direction='out'/>"
147 " <method name='RequestCallListAsync'>"
149 " <method name='GetAudioConnected'>"
150 " <arg type='i' name='status' direction='out'/>"
152 " <method name='IsHfConnected'>"
153 " <arg type='b' name='status' direction='out'/>"
155 " <method name='IsInbandRingtoneSupported'>"
156 " <arg type='b' name='status' direction='out'/>"
158 " <method name='AudioMuteOn'>"
160 " <method name='AudioMuteOff'>"
165 static bt_hf_agent_info_t bt_hf_info = {0,};
166 static gboolean is_hf_connected = FALSE;
167 static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD;
168 static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
170 static char global_buff[BT_AT_COMMAND_BUFFER_MAX] = {0,};
173 static char prev_cmd[BT_HF_CMD_BUF_SIZE];
183 } hf_call_list_info_t;
185 #define BT_HF_SIG_NUM 3
186 static struct sigaction bt_hf_sigoldact[BT_HF_SIG_NUM];
187 static int bt_hf_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
189 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error);
191 static gboolean __bt_hf_agent_emit_property_changed(
192 GDBusConnection *connection,
194 const char *interface,
198 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
199 bt_hf_agent_info_t *bt_hf_info);
200 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info);
201 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info);
202 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
204 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
205 gchar *data, gsize count);
207 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
209 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
210 gchar *data, gchar *response, gsize count);
211 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indies);
212 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indies);
213 static guint __bt_hf_get_hold_mpty_features(gchar *features);
214 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info);
215 static void __bt_hf_agent_sigterm_handler(int signo);
216 static gboolean __bt_hf_agent_release(void);
218 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info);
219 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info);
220 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path);
221 static gboolean __bt_hf_agent_connection_release(void);
222 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info);
225 gchar descr[BT_HF_INDICATOR_DESCR_SIZE];
229 static int _hf_agent_answer_call(GDBusMethodInvocation *context);
231 static int _hf_agent_terminate_call(GDBusMethodInvocation *context);
233 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no);
235 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context,
238 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd);
240 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context,
241 unsigned int status);
243 static gboolean bt_hf_agent_sco_connect(void);
245 static gboolean bt_hf_agent_sco_disconnect(void);
247 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf);
249 static GVariant *bt_hf_agent_request_call_list(void);
251 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd);
253 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf);
255 static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
256 const gchar *msg, gpointer user_data)
261 static void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
265 char s[BT_HF_DATA_BUF_SIZE] = {0, };
266 gboolean hide = FALSE;
268 gboolean has_clcc = FALSE;
269 gboolean has_clip = FALSE;
270 gboolean has_ccwa = FALSE;
273 strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
275 has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
276 if (has_clcc == TRUE)
278 has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
279 if (has_clip == TRUE)
281 has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
285 xsat_ptr = strstr(s, "11,DISC,");
287 xsat_ptr = xsat_ptr + 8;
289 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
295 /* AT+XSAT=11,Q_CT,X,XXXX */
296 xsat_ptr = strstr(s, "11,Q_CT,");
298 xsat_ptr = xsat_ptr + 8;
300 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
301 if (x > 1) /* ignore 0 and 1 position */
308 while (s[i] != '\0') {
309 if (s[i] == '\r' || s[i] == '\n') {
313 hide = hide ? FALSE : TRUE;
314 else if ((has_clcc || has_clip || has_ccwa) && hide) {
322 INFO("%s Buffer = %s, Length = %zd ", message, s, strlen(s));
327 static GQuark __bt_hf_agent_error_quark(void)
331 static GQuark quark = 0;
333 quark = g_quark_from_static_string("hf-agent");
338 static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error)
340 ERR("error[%d]", error);
343 case BT_HF_AGENT_ERROR_NOT_AVAILABLE:
344 return g_error_new(BT_HF_AGENT_ERROR, error,
345 BT_ERROR_NOT_AVAILABLE);
346 case BT_HF_AGENT_ERROR_NOT_CONNECTED:
347 return g_error_new(BT_HF_AGENT_ERROR, error,
348 BT_ERROR_NOT_CONNECTED);
349 case BT_HF_AGENT_ERROR_CONNECTION_FAILED:
350 return g_error_new(BT_HF_AGENT_ERROR, error,
351 BT_ERROR_NOT_CONNECTION_FAILED);
352 case BT_HF_AGENT_ERROR_BUSY:
353 return g_error_new(BT_HF_AGENT_ERROR, error,
355 case BT_HF_AGENT_ERROR_INVALID_PARAM:
356 return g_error_new(BT_HF_AGENT_ERROR, error,
357 BT_ERROR_INVALID_PARAM);
358 case BT_HF_AGENT_ERROR_ALREADY_EXIST:
359 return g_error_new(BT_HF_AGENT_ERROR, error,
360 BT_ERROR_ALREADY_EXIST);
361 case BT_HF_AGENT_ERROR_ALREADY_CONNECTED:
362 return g_error_new(BT_HF_AGENT_ERROR, error,
363 BT_ERROR_ALREADY_CONNECTED);
364 case BT_HF_AGENT_ERROR_NO_MEMORY:
365 return g_error_new(BT_HF_AGENT_ERROR, error,
367 case BT_HF_AGENT_ERROR_NO_DATA:
368 return g_error_new(BT_HF_AGENT_ERROR, error,
370 case BT_HF_AGENT_ERROR_I_O_ERROR:
371 return g_error_new(BT_HF_AGENT_ERROR, error,
373 case BT_HF_AGENT_ERROR_APPLICATION:
374 return g_error_new(BT_HF_AGENT_ERROR, error,
375 BT_ERROR_OPERATION_NOT_AVAILABLE);
376 case BT_HF_AGENT_ERROR_NOT_ALLOWED:
377 return g_error_new(BT_HF_AGENT_ERROR, error,
378 BT_ERROR_OPERATION_NOT_ALLOWED);
379 case BT_HF_AGENT_ERROR_NOT_SUPPORTED:
380 return g_error_new(BT_HF_AGENT_ERROR, error,
381 BT_ERROR_OPERATION_NOT_SUPPORTED);
382 case BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
383 return g_error_new(BT_HF_AGENT_ERROR, error,
384 BT_ERROR_INVALID_FILE_DESCRIPTOR);
385 case BT_HF_AGENT_ERROR_INTERNAL:
387 return g_error_new(BT_HF_AGENT_ERROR, error,
392 static void __bt_hf_lock_display(int timeout)
396 ret = device_power_request_lock(POWER_LOCK_DISPLAY, timeout);
398 DBG("Lock PM state as current state!");
400 ERR("deviced error!");
403 static void __bt_hf_unlock_display()
407 ret = device_power_release_lock(POWER_LOCK_DISPLAY);
409 DBG("UnLock PM state");
411 ERR("deviced error!");
414 static gboolean __clcc_timer_func(gpointer data)
421 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
422 DBG("NOT CONNECTED");
423 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_NOT_CONNECTED);
424 g_dbus_method_invocation_return_gerror((GDBusMethodInvocation *) data, err);
430 if (send_flag && clcc_retry_count > 0) {
432 DBG("Still pending. try later (remained [%d] times)", clcc_retry_count);
438 call_var = bt_hf_agent_request_call_list();
440 INFO("NOT AVAILABLE");
441 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_NOT_AVAILABLE);
442 g_dbus_method_invocation_return_gerror((GDBusMethodInvocation *) data, err);
447 INFO("return call list info");
448 g_dbus_method_invocation_return_value((GDBusMethodInvocation *) data, call_var);
452 static gboolean __clcc_async_timer_func(gpointer data)
456 if (send_flag && clcc_async_retry_count > 0) {
457 clcc_async_retry_count--;
458 ERR("Still pending. try later (remained [%d] times)", clcc_async_retry_count);
462 clcc_async_timer = 0;
464 __bt_hf_agent_handle_call_list(&bt_hf_info);
465 g_dbus_method_invocation_return_value((GDBusMethodInvocation*)data, NULL);
467 INFO("update_call_list succeeded");
472 static void __hf_agent_method(GDBusConnection *connection,
475 const gchar *interface_name,
476 const gchar *method_name,
477 GVariant *parameters,
478 GDBusMethodInvocation *context,
483 INFO("method %s", method_name);
487 if (g_strcmp0(method_name, "NewConnection") == 0) {
491 GUnixFDList *fd_list;
492 const gchar *object_path;
495 g_variant_get(parameters, "(oha{sv})",
496 &object_path, &index, &options);
498 msg = g_dbus_method_invocation_get_message(context);
499 fd_list = g_dbus_message_get_unix_fd_list(msg);
500 if (fd_list == NULL) {
501 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
505 fd = g_unix_fd_list_get(fd_list, index, NULL);
507 ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
511 DBG("FD is = [%d], Object path = [%s]", fd, object_path);
513 if (!__bt_hf_agent_connection(fd, object_path)) {
514 ret = BT_HF_AGENT_ERROR_INTERNAL;
518 g_dbus_method_invocation_return_value(context, NULL);
519 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
520 if (!__bt_hf_agent_connection_release()) {
521 ret = BT_HF_AGENT_ERROR_INTERNAL;
524 INFO_C("Disconnected [HF role] [Terminated by local host]");
525 g_dbus_method_invocation_return_value(context, NULL);
526 } else if (g_strcmp0(method_name, "Release") == 0) {
527 if (!__bt_hf_agent_connection_release()) {
528 ret = BT_HF_AGENT_ERROR_INTERNAL;
532 g_dbus_method_invocation_return_value(context, NULL);
533 } else if (g_strcmp0(method_name, "AnswerCall") == 0) {
534 DBG("Going to call AnswerCall");
535 ret = _hf_agent_answer_call(context);
539 } else if (g_strcmp0(method_name, "TerminateCall") == 0) {
540 DBG("Going to call TerminateCall");
541 ret = _hf_agent_terminate_call(context);
545 } else if (g_strcmp0(method_name, "InitiateCall") == 0) {
546 char *phoneno = NULL;
548 g_variant_get(parameters, "(&s)", &phoneno);
550 DBG_SECURE("Going to call InitiateCall, Number is = [%s]\n", phoneno);
551 ret = _hf_agent_dial_no(NULL, phoneno);
555 g_dbus_method_invocation_return_value(context, NULL);
557 } else if (g_strcmp0(method_name, "VoiceRecognition") == 0) {
560 g_variant_get(parameters, "(i)", &status);
562 DBG("Going to call VoiceRecognition, Status [%d]", status);
563 ret = _hf_agent_voice_recognition(context, status);
567 } else if (g_strcmp0(method_name, "ScoConnect") == 0) {
568 DBG("Going to call ScoConnect");
569 if (!bt_hf_agent_sco_connect()) {
570 ret = BT_HF_AGENT_ERROR_INTERNAL;
574 g_dbus_method_invocation_return_value(context, NULL);
575 } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) {
576 DBG("Going to call ScoDisconnect");
577 if (!bt_hf_agent_sco_disconnect()) {
578 ret = BT_HF_AGENT_ERROR_INTERNAL;
582 g_dbus_method_invocation_return_value(context, NULL);
583 } else if (g_strcmp0(method_name, "SpeakerGain") == 0) {
584 unsigned int gain = 0;
586 g_variant_get(parameters, "(u)", &gain);
588 DBG("Going to call SpeakerGain, gain is = [%d]\n", gain);
589 ret = _hf_agent_set_speaker_gain(context, gain);
593 } else if (g_strcmp0(method_name, "SendDtmf") == 0) {
596 g_variant_get(parameters, "(&s)", &dtmf);
598 DBG("Going to call SendDtmf, dtmf is = [%s]\n", dtmf);
599 ret = _hf_agent_send_dtmf(NULL, dtmf);
602 g_dbus_method_invocation_return_value(context, NULL);
604 } else if (g_strcmp0(method_name, "SendAtCmd") == 0) {
607 g_variant_get(parameters, "(&s)", &cmd);
609 DBG("Going to call SendAtCmd\n");
610 ret = bt_hf_agent_send_at_cmd(NULL, cmd);
613 g_dbus_method_invocation_return_value(context, NULL);
615 } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) {
616 DBG("Going to call ReleaseAndAccept");
617 ret = _hf_agent_send_3way_cmd(context,
618 BT_HF_RELEASE_AND_ACCEPT);
622 } else if (g_strcmp0(method_name, "CallSwap") == 0) {
623 DBG("Going to call CallSwap");
624 ret = _hf_agent_send_3way_cmd(context,
625 BT_HF_ACCEPT_AND_HOLD);
629 } else if (g_strcmp0(method_name, "ReleaseAllCall") == 0) {
630 DBG("Going to call ReleaseAllCall");
631 ret = _hf_agent_send_3way_cmd(context, BT_HF_RELEASE_ALL);
635 } else if (g_strcmp0(method_name, "JoinCall") == 0) {
636 DBG("Going to call JoinCall");
637 ret = _hf_agent_send_3way_cmd(context, BT_HF_JOIN_CALL);
641 } else if (g_strcmp0(method_name, "GetCurrentCodec") == 0) {
642 DBG("Going to call GetCurrentCodec");
643 INFO("Current codec : %d", current_codec_id);
644 g_dbus_method_invocation_return_value(context,
645 g_variant_new("(i)", current_codec_id));
646 } else if (g_strcmp0(method_name, "RequestCallList") == 0) {
649 INFO("Going to call RequestCallList (send_flag[%d])", send_flag);
652 INFO("Send_flag is true. Try to send CLCC later");
653 clcc_retry_count = CLCC_RETRY_COUNT;
654 clcc_timer = g_timeout_add(CLCC_RETRY_TIMER, __clcc_timer_func, context);
656 call_var = bt_hf_agent_request_call_list();
658 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
661 g_dbus_method_invocation_return_value(context, call_var);
663 } else if (g_strcmp0(method_name, "RequestCallListAsync") == 0) {
664 INFO("Going to call RequestCallListAsync (send_flag[%d])", send_flag);
666 if (clcc_async_timer > 0) {
667 ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
670 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
671 ret = BT_HF_AGENT_ERROR_NOT_CONNECTED;
674 if (bt_hf_info.ciev_call_status == 0 &&
675 bt_hf_info.ciev_call_setup_status == 0) {
676 ret = BT_HF_AGENT_ERROR_NO_DATA;
681 INFO("Send_flag is true. Try to send CLCC later");
682 clcc_async_retry_count = CLCC_RETRY_COUNT;
683 clcc_async_timer = g_timeout_add(CLCC_RETRY_TIMER, __clcc_async_timer_func, context);
685 __bt_hf_agent_handle_call_list(&bt_hf_info);
686 g_dbus_method_invocation_return_value(context, NULL);
688 } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) {
689 DBG("Going to call GetAudioConnected");
690 g_dbus_method_invocation_return_value(context,
691 g_variant_new("(i)", sco_audio_connected));
692 } else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
693 DBG("Going to call IsHfConnected");
694 INFO("is_hf_connected : %s", is_hf_connected ? "Connected" : "Disconnected");
696 g_dbus_method_invocation_return_value(context,
697 g_variant_new("(b)", is_hf_connected));
698 } else if (g_strcmp0(method_name, "IsInbandRingtoneSupported") == 0) {
699 gboolean is_supported = FALSE;
701 if (is_hf_connected == FALSE) {
702 ret = BT_HF_AGENT_ERROR_NOT_CONNECTED;
706 if (bt_hf_info.inband_ringtone_support)
709 is_supported = FALSE;
711 INFO("IsInbandRingtoneSupported : %s", is_supported ?
712 "Supported" : "NotSupported");
713 g_dbus_method_invocation_return_value(context,
714 g_variant_new("(b)", is_supported));
715 } else if (g_strcmp0(method_name, "AudioMuteOn") == 0) {
716 DBG("Going to MUTE audio");
717 bt_hf_info.is_audio_input_mute = TRUE;
718 g_dbus_method_invocation_return_value(context, NULL);
719 } else if (g_strcmp0(method_name, "AudioMuteOff") == 0) {
720 DBG("Going to UNMUTE audio");
721 bt_hf_info.is_audio_input_mute = FALSE;
722 g_dbus_method_invocation_return_value(context, NULL);
729 err = __bt_hf_agent_set_error(ret);
730 g_dbus_method_invocation_return_gerror(context, err);
735 static const GDBusInterfaceVTable method_table = {
741 static GDBusNodeInfo *__bt_hf_create_method_node_info
742 (const gchar *introspection_data)
744 if (introspection_data == NULL)
747 return g_dbus_node_info_new_for_xml(introspection_data, NULL);
750 static GDBusConnection *__bt_hf_get_gdbus_connection(void)
752 GDBusConnection *local_system_gconn = NULL;
755 if (gdbus_conn == NULL) {
756 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
759 ERR("Unable to connect to dbus: %s", err->message);
764 } else if (g_dbus_connection_is_closed(gdbus_conn)) {
765 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
767 if (!local_system_gconn) {
768 ERR("Unable to connect to dbus: %s", err->message);
772 gdbus_conn = local_system_gconn;
778 static gboolean __bt_hf_register_profile_methods(void)
781 GError *error = NULL;
784 GDBusNodeInfo *node_info;
786 GDBusConnection *conn;
788 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
790 G_BUS_NAME_OWNER_FLAGS_NONE,
794 DBG("owner_id is [%d]", owner_id);
796 node_info = __bt_hf_create_method_node_info(
797 hf_agent_bluez_introspection_xml);
798 if (node_info == NULL)
801 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
802 DBG("path is [%s]", path);
804 conn = __bt_hf_get_gdbus_connection();
806 ERR("Unable to get connection");
811 object_id = g_dbus_connection_register_object(conn, path,
812 node_info->interfaces[0],
815 if (object_id == 0) {
816 ERR("Failed to register: %s", error->message);
818 g_dbus_node_info_unref(node_info);
823 g_dbus_node_info_unref(node_info);
825 node_info = __bt_hf_create_method_node_info(hf_agent_introspection_xml);
826 if (node_info == NULL)
829 path = g_strdup(BT_HF_AGENT_OBJECT_PATH);
830 DBG("path is [%s]", path);
832 object_id = g_dbus_connection_register_object(conn, path,
833 node_info->interfaces[0],
836 if (object_id == 0) {
838 ERR("Failed to register: %s", error->message);
841 g_dbus_node_info_unref(node_info);
846 g_dbus_node_info_unref(node_info);
852 static GDBusProxy *__bt_hf_gdbus_init_profile_proxy(void)
858 GDBusConnection *conn;
860 conn = __bt_hf_get_gdbus_connection();
862 ERR("Unable to get connection");
866 proxy = g_dbus_proxy_new_sync(conn,
867 G_DBUS_PROXY_FLAGS_NONE, NULL,
868 BLUEZ_SERVICE_NAME, "/org/bluez",
869 BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err);
873 ERR("Unable to create proxy: %s", err->message);
879 profile_gproxy = proxy;
885 static GDBusProxy *__bt_hf_gdbus_get_profile_proxy(void)
887 return (profile_gproxy) ? profile_gproxy :
888 __bt_hf_gdbus_init_profile_proxy();
891 static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service,
892 const gchar *path, const gchar *interface)
898 GDBusConnection *conn;
900 conn = __bt_hf_get_gdbus_connection();
902 ERR("Unable to get connection");
906 proxy = g_dbus_proxy_new_sync(conn,
907 G_DBUS_PROXY_FLAGS_NONE, NULL,
909 interface, NULL, &err);
913 ERR("Unable to create proxy: %s", err->message);
923 static char __bt_hf_agent_get_tx_power(char *address)
927 GError *error = NULL;
928 char result = READ_TX_POWER_MIN; /* default minimum */
930 proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, g_obj_path,
931 BLUEZ_HF_INTERFACE_NAME);
933 ERR("Proxy is NULL");
937 ret = g_dbus_proxy_call_sync(proxy,
938 "GetTxPowerLevel", g_variant_new("(s)", address),
939 G_DBUS_CALL_FLAGS_NONE, -1,
942 ERR("DBus is failed");
944 /* Dbus gives error cause */
945 ERR("D-Bus API failure: errCode[%x], message[%s]",
946 error->code, error->message);
947 g_clear_error(&error);
949 g_object_unref(proxy);
952 g_variant_get(ret, "(y)", &result);
953 DBG("TX power level = %d", result);
954 g_variant_unref(ret);
955 g_object_unref(proxy);
960 static int __bt_hf_agent_gdbus_method_send(const char *service,
961 GVariant *path, const char *interface,
968 GError *error = NULL;
970 proxy = __bt_hf_gdbus_get_service_proxy(service, g_obj_path, interface);
972 return BT_HF_AGENT_ERROR_INTERNAL;
974 ret = g_dbus_proxy_call_sync(proxy,
976 G_DBUS_CALL_FLAGS_NONE, -1,
979 /* dBUS-RPC is failed */
980 ERR("dBUS-RPC is failed");
982 /* dBUS gives error cause */
983 ERR("D-Bus API failure: errCode[%x], message[%s]",
984 error->code, error->message);
986 g_clear_error(&error);
988 g_object_unref(proxy);
989 return BT_HF_AGENT_ERROR_INTERNAL;
992 g_variant_unref(ret);
993 g_object_unref(proxy);
995 return BT_HF_AGENT_ERROR_NONE;
998 static void __bt_hf_agent_release_queue(void)
1001 bt_hf_agent_send_at_info *cmd;
1004 len = g_slist_length(bt_hf_info.cmd_send_queue);
1005 for (i = 0; i < len; ++i) {
1006 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
1007 if (cmd && cmd->context) {
1008 DBG("Pending context found for %.6s[%d]",
1009 cmd->at_cmd, cmd->id);
1010 err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_INTERNAL);
1011 g_dbus_method_invocation_return_gerror(cmd->context, err);
1014 if (cmd && cmd->timer_id)
1015 g_source_remove(cmd->timer_id);
1017 g_slist_free(bt_hf_info.cmd_send_queue);
1018 bt_hf_info.cmd_send_queue = NULL;
1022 static gboolean __bt_hf_monitor_timer_cb(gpointer data)
1025 bt_hf_agent_send_at_info *cmd = data;
1026 ERR_C("Monitor timer came becuase of timeout for sendflag %d, %s",
1027 send_flag, cmd->at_cmd);
1028 /* In the case of ATD, we have to inform the remote to end the call */
1029 if (strstr(cmd->at_cmd, "ATD") || strstr(cmd->at_cmd, "BLDN")) {
1030 INFO_C("Sending CHUP for remote call termination");
1031 __bt_hf_send_only_without_queue(&bt_hf_info, BT_HF_END_CALL,
1032 strlen(BT_HF_END_CALL));
1033 /* Here there is a high posisbility that we do not get response
1034 * for CHUP. Hence we need to decrement send_flag to process further
1035 * incomming packets because we already incremented it in the CHUP case. */
1039 /* In the case of ATD, prev_cmd will be always ATD, because we will not
1040 * allow further commands. For safer side again set prev_cmd as ATD */
1041 strncpy(prev_cmd, "ATD\0", BT_HF_CMD_BUF_SIZE - 1);
1043 hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
1051 gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
1052 int count, gboolean pending_flag)
1054 int i, len, timer_id;
1055 if (bt_hf_info.slc == FALSE)
1058 DBG("Add Pending queue. (pending_flag is %s)",
1059 pending_flag ? "TRUE" : "FALSE");
1061 bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
1063 ERR("failed to allocate cmd");
1068 memcpy(cmd->at_cmd, at, count);
1070 cmd->context = context;
1071 cmd->pending = pending_flag;
1072 bt_hf_info.cmd_send_queue = g_slist_append(bt_hf_info.cmd_send_queue,
1074 len = g_slist_length(bt_hf_info.cmd_send_queue);
1075 for (i = 0; i < len; ++i) {
1076 cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
1078 DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id);
1081 /* We need to have base timeout + tolerance value to process other request */
1082 if (strstr(at, "ATD") || strstr(at, "BLDN")) {
1083 /* Android 15 seconds timeout in case of ATD timeout in flight mode */
1084 timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len,
1085 __bt_hf_monitor_timer_cb, cmd);
1087 cmd->timer_id = timer_id;
1089 timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len,
1090 __bt_hf_monitor_timer_cb, cmd);
1092 cmd->timer_id = timer_id;
1098 Below methods exposed to Applicatoins
1100 static gboolean __bt_hf_agent_emit_signal(GDBusConnection *connection,
1101 const char *path, const char *interface,
1102 const char *signal_name, GVariant *param)
1104 GError *error = NULL;
1106 ret = g_dbus_connection_emit_signal(connection,
1108 interface, signal_name,
1111 if (error != NULL) {
1112 /* dBUS gives error cause */
1113 ERR("D-Bus API failure: errCode[%x], message[%s]",
1114 error->code, error->message);
1115 g_clear_error(&error);
1118 INFO_C("Emit Signal [%s]", signal_name);
1123 static gboolean __bt_hf_agent_emit_property_changed(
1124 GDBusConnection *connection,
1126 const char *interface,
1132 GError *error = NULL;
1134 ret = g_dbus_connection_emit_signal(connection,
1135 NULL, path, interface,
1137 g_variant_new("(sv)", name, property),
1140 if (error != NULL) {
1141 /* dBUS gives error cause */
1142 ERR("D-Bus API failure: errCode[%x], message[%s]",
1143 error->code, error->message);
1144 g_clear_error(&error);
1152 Below methods exposed to Bluez
1155 static gboolean __bt_hf_agent_launch_call_app(void)
1161 app_manager_is_running(CALL_ALIAS_APP_ID, &is_running);
1163 DBG("Call app is already started");
1167 b = bundle_create();
1169 ERR("bundle_create() Failed");
1173 bundle_add(b, "launch-type", "BT_LAUNCH");
1175 bundle_add(b, "carrier-type", "BT");
1176 DBG("For 3G, carrier-type: BT has been added");
1177 aul_launch_app_async(CALL_ALIAS_APP_ID, b);
1180 INFO("-aul_launch_app_async -");
1185 static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
1186 guint index, gint value)
1188 GDBusConnection *conn;
1190 struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
1192 ERR("Indicator is NULL");
1199 conn = __bt_hf_get_gdbus_connection();
1201 ERR("Unable to get connection");
1205 INFO("Indicator name is %s, value = [%d]", name, value);
1206 if (!strcmp(name, "\"call\"")) {
1207 bt_hf_info->ciev_call_status = value;
1209 __bt_hf_agent_emit_signal(conn,
1210 BT_HF_AGENT_OBJECT_PATH,
1211 BT_HF_SERVICE_INTERFACE,
1212 "CallStarted", NULL);
1213 bt_hf_info->is_dialing = FALSE;
1214 bt_hf_info->call_active = TRUE;
1215 if (TIZEN_MODEL_NAME_DA)
1216 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_STARTED;
1217 } else if (bt_hf_info->call_active) {
1218 __bt_hf_agent_emit_signal(conn,
1219 BT_HF_AGENT_OBJECT_PATH,
1220 BT_HF_SERVICE_INTERFACE,
1222 bt_hf_info->call_active = FALSE;
1223 if (TIZEN_MODEL_NAME_DA)
1224 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_ENDED;
1226 if (bt_hf_info->ciev_call_setup_status == 0) {
1227 __bt_hf_agent_emit_signal(gdbus_conn,
1228 BT_HF_AGENT_OBJECT_PATH,
1229 BT_HF_SERVICE_INTERFACE,
1231 if (TIZEN_MODEL_NAME_DA)
1232 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
1236 } else if (!strcmp(name, "\"callsetup\"")) {
1237 bt_hf_info->ciev_call_setup_status = value;
1238 if (value == 0 && bt_hf_info->is_dialing) {
1239 bt_hf_info->is_dialing = FALSE;
1240 __bt_hf_agent_emit_signal(conn,
1241 BT_HF_AGENT_OBJECT_PATH,
1242 BT_HF_SERVICE_INTERFACE,
1245 if (TIZEN_MODEL_NAME_DA)
1246 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_TERMINATED;
1247 } else if (!bt_hf_info->is_dialing && value > 0) {
1248 bt_hf_info->is_dialing = TRUE;
1251 if (bt_hf_info->ciev_call_setup_status == 1) {
1252 __bt_hf_agent_emit_signal(gdbus_conn,
1253 BT_HF_AGENT_OBJECT_PATH,
1254 BT_HF_SERVICE_INTERFACE,
1255 "CallSetupIncoming", NULL);
1256 if (TIZEN_MODEL_NAME_DA)
1257 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_INCOMING;
1258 if (__bt_hf_agent_launch_call_app() == FALSE)
1259 DBG("call app launching failed");
1260 } else if (bt_hf_info->ciev_call_setup_status == 2) {
1261 __bt_hf_agent_emit_signal(gdbus_conn,
1262 BT_HF_AGENT_OBJECT_PATH,
1263 BT_HF_SERVICE_INTERFACE,
1264 "CallSetupDialing", NULL);
1265 if (TIZEN_MODEL_NAME_DA)
1266 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING;
1267 } else if (bt_hf_info->ciev_call_setup_status == 3) {
1268 __bt_hf_agent_emit_signal(gdbus_conn,
1269 BT_HF_AGENT_OBJECT_PATH,
1270 BT_HF_SERVICE_INTERFACE,
1271 "CallSetupAlerting", NULL);
1272 if (TIZEN_MODEL_NAME_DA)
1273 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING;
1274 } else if (bt_hf_info->ciev_call_status == 0 &&
1275 bt_hf_info->ciev_call_setup_status == 0) {
1276 __bt_hf_agent_emit_signal(gdbus_conn,
1277 BT_HF_AGENT_OBJECT_PATH,
1278 BT_HF_SERVICE_INTERFACE,
1280 if (TIZEN_MODEL_NAME_DA)
1281 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
1283 } else if (!strcmp(name, "\"callheld\"")) {
1284 if (value == 0) { /* No calls held*/
1285 __bt_hf_agent_emit_signal(conn,
1286 BT_HF_AGENT_OBJECT_PATH,
1287 BT_HF_SERVICE_INTERFACE,
1290 } else if (value == 1) {
1291 /*Call is placed on hold or active/held calls swapped */
1292 __bt_hf_agent_emit_signal(conn,
1293 BT_HF_AGENT_OBJECT_PATH,
1294 BT_HF_SERVICE_INTERFACE,
1295 "CallsSwapped", NULL);
1297 /*Call on hold, no active call*/
1298 __bt_hf_agent_emit_signal(conn,
1299 BT_HF_AGENT_OBJECT_PATH,
1300 BT_HF_SERVICE_INTERFACE,
1301 "CallOnHold", NULL);
1303 } else if (!strcmp(name, "\"service\"")) {
1304 if (value < 0 || value > 1)
1305 ERR("Out of range");
1307 __bt_hf_agent_emit_property_changed(conn,
1308 BT_HF_AGENT_OBJECT_PATH,
1309 BT_HF_SERVICE_INTERFACE,
1310 "RegistrationStatus",
1311 g_variant_new("q", value));
1312 } else if (!strcmp(name, "\"signal\"")) {
1313 if (value < 0 || value > 5)
1314 ERR("Out of range");
1316 __bt_hf_agent_emit_property_changed(conn,
1317 BT_HF_AGENT_OBJECT_PATH,
1318 BT_HF_SERVICE_INTERFACE, "SignalStrength",
1319 g_variant_new("q", value));
1320 } else if (!strcmp(name, "\"roam\"")) {
1321 if (value < 0 || value > 1)
1322 ERR("Out of range");
1324 __bt_hf_agent_emit_property_changed(conn,
1325 BT_HF_AGENT_OBJECT_PATH,
1326 BT_HF_SERVICE_INTERFACE, "RoamingStatus",
1327 g_variant_new("q", value));
1328 } else if (!strcmp(name, "\"battchg\"")) {
1329 if (value < 0 || value > 5)
1330 ERR("Out of range");
1332 __bt_hf_agent_emit_property_changed(conn,
1333 BT_HF_AGENT_OBJECT_PATH,
1334 BT_HF_SERVICE_INTERFACE, "BatteryCharge",
1335 g_variant_new("q", value));
1339 static void __bt_hf_agent_handle_voice_activation(gint value)
1341 GDBusConnection *conn;
1343 conn = __bt_hf_get_gdbus_connection();
1345 ERR("Unable to get connection");
1349 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1350 BT_HF_SERVICE_INTERFACE,
1352 g_variant_new("(i)", value));
1357 static void __bt_hf_agent_handle_speaker_gain(gint value)
1359 GDBusConnection *conn;
1361 conn = __bt_hf_get_gdbus_connection();
1363 ERR("Unable to get connection");
1367 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1368 BT_HF_SERVICE_INTERFACE, "VolumeSpeaker",
1369 g_variant_new("(i)", value));
1374 static int __bt_hf_agent_handle_clip(bt_hf_agent_info_t *bt_hf_info,
1377 GDBusConnection *conn;
1379 gchar number[BT_HF_CALLER_NUM_SIZE];
1381 char fmt_str[BT_HF_FMT_STR_SIZE];
1382 int len = strlen(buf);
1384 DBG("__bt_hf_agent_handle_clip +");
1385 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1386 ERR("buf len %d is too long", len);
1390 if ((clip = strstr(buf, "\r\n+CLIP"))) {
1391 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CLIP: \"%%%ds", (int)(sizeof(number) - 1));
1392 if (sscanf(clip, fmt_str, number) == 1) {
1393 sep = strchr(number, '"');
1398 conn = __bt_hf_get_gdbus_connection();
1400 ERR("Unable to get connection");
1404 __bt_hf_agent_emit_signal(conn,
1405 BT_HF_AGENT_OBJECT_PATH,
1406 BT_HF_SERVICE_INTERFACE, "Ring",
1407 g_variant_new("(s)", clip));
1409 ERR_SECURE("CLIP '%s' is Call Incoming", buf);
1413 DBG("__bt_hf_agent_handle_clip -");
1417 static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info,
1420 GDBusConnection *conn;
1422 gchar number[BT_HF_CALLER_NUM_SIZE];
1424 char fmt_str[BT_HF_FMT_STR_SIZE];
1425 int len = strlen(buf);
1427 DBG("__bt_hf_agent_handle_ccwa +");
1428 if (len > BT_HF_CALLER_NUM_SIZE + 10) {
1429 ERR("buf len %d is too long", len);
1433 if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
1434 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds",
1435 (int)(sizeof(number) - 1));
1436 if (sscanf(ccwa, fmt_str, number) == 1) {
1437 sep = strchr(number, '"');
1442 conn = __bt_hf_get_gdbus_connection();
1444 ERR("Unable to get connection");
1448 __bt_hf_agent_emit_signal(conn,
1449 BT_HF_AGENT_OBJECT_PATH,
1450 BT_HF_SERVICE_INTERFACE, "CallWaiting",
1451 g_variant_new("(s)", ccwa));
1453 ERR_SECURE("CCWA '%s' is Call Wating", buf);
1457 DBG("__bt_hf_agent_handle_ccwa -");
1461 static void __bt_hf_agent_handle_bsir(bt_hf_agent_info_t *bt_hf_info,
1464 INFO("new value : %d", value);
1467 bt_hf_info->inband_ringtone_support = TRUE;
1469 bt_hf_info->inband_ringtone_support = FALSE;
1474 static GSList *__bt_hf_prepare_call_list(const char *buf)
1476 GSList *call_list = NULL;
1481 char delim_sep[] = "\r\n";
1482 char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,};
1484 hf_call_list_info_t *call_info;
1487 strncpy(temp_buf, buf, BT_HF_DATA_BUF_SIZE - 1);
1489 str = strtok_r(temp_buf, delim_sep, &sp);
1490 while (str != NULL) {
1491 if (!(strstr(str, "+CLCC:"))) {
1492 str = strtok_r(NULL, delim_sep, &sp);
1496 call_info = g_new0(hf_call_list_info_t, 1);
1498 sscanf(str, "+CLCC: %1d,%1d, %1d, %1d, %1d",
1499 &call_info->idx, &call_info->dir,
1500 &call_info->status, &call_info->mode,
1501 &call_info->multi_party);
1502 DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n",
1503 call_info->idx, call_info->dir, call_info->status,
1504 call_info->mode, call_info->multi_party);
1506 ptr = strstr(str, "\"");
1508 temp = strstr(ptr + 1, "\"");
1511 DBG_SECURE("\tPhone Number = [%s]\n", ptr + 1);
1512 call_info->number = g_strdup(ptr + 1);
1514 if (strstr(temp + 1, ",")) {
1516 DBG("\tType = [%s]\n", temp);
1517 call_info->type = atoi(temp);
1521 /*In case of no phone no. in CLCC respnse, we should launch call application
1522 * with NULL string. By doing so "unknown" shall be displayed*/
1523 DBG("Phone number does not exist\n");
1524 call_info->number = g_strdup("");
1527 call_list = g_slist_append(call_list, call_info);
1528 str = strtok_r(NULL, delim_sep, &sp);
1534 static GSList *__bt_hf_get_call_list(bt_hf_agent_info_t *bt_hf_info)
1536 char buf[BT_HF_DATA_BUF_SIZE] = {0,};
1537 GSList *call_list = NULL;
1541 /* Send CLCC when the callsetup */
1542 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLLIST, buf,
1543 sizeof(BT_HF_CALLLIST) - 1);
1544 DBG_SECURE("Receive CLCC response buffer = '%s'", buf);
1546 call_list = __bt_hf_prepare_call_list(buf);
1551 static void __bt_hf_call_info_free(void *data)
1555 hf_call_list_info_t *call_info = data;
1556 g_free(call_info->number);
1562 static void __bt_hf_free_call_list(GSList *call_list)
1566 g_slist_free_full(call_list, __bt_hf_call_info_free);
1571 static void __bt_hf_launch_call_using_call_list(GSList *call_list)
1576 if (call_list == NULL)
1579 len = g_slist_length(call_list);
1581 if (len > 0 && __bt_hf_agent_launch_call_app() == FALSE)
1582 DBG("call app launching failed");
1587 static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list)
1593 hf_call_list_info_t *call_info;
1595 GVariantBuilder *builder;
1598 builder = g_variant_builder_new(G_VARIANT_TYPE("a(siiii)"));
1600 call_count = g_slist_length(call_list);
1601 DBG("Total call count = '%d'", call_count);
1603 while (call_count--) {
1604 call_info = g_slist_nth_data(call_list, call_count);
1606 INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d",
1607 call_info->idx, call_info->dir, call_info->status,
1608 call_info->mode, call_info->multi_party);
1609 caller = call_info->number;
1611 g_variant_builder_add(builder, "(siiii)",
1612 caller, call_info->dir, call_info->status,
1613 call_info->multi_party, call_info->idx);
1616 var_data = g_variant_new("(ia(siiii))",
1617 g_slist_length(call_list), builder);
1619 g_variant_builder_unref(builder);
1624 static void __bt_hf_clear_prev_sent_cmd(void)
1626 if (prev_cmd[0] != 0)
1627 ERR("No sent command");
1629 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
1634 static void __bt_hf_agent_send_call_status_info(GSList *call_list)
1636 GDBusConnection *conn;
1639 conn = __bt_hf_get_gdbus_connection();
1641 ERR("Unable to get connection");
1643 var_data = __bt_hf_agent_get_call_status_info(call_list);
1644 __bt_hf_agent_emit_signal(conn,
1645 BT_HF_AGENT_OBJECT_PATH,
1646 BT_HF_SERVICE_INTERFACE,
1652 static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info)
1656 __bt_hf_lock_display(0);
1658 bt_hf_info->context = NULL;
1660 /* Send CLCC. The response will be handled in the handler */
1661 ret = __bt_hf_send_only(bt_hf_info, BT_HF_CALLLIST,
1662 sizeof(BT_HF_CALLLIST) - 1);
1664 ERR("Failed to send CLCC");
1666 __bt_hf_unlock_display();
1669 static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only)
1671 gchar buf[BT_HF_DATA_BUF_SIZE];
1672 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1675 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_AVAILABLE_CODEC,
1676 BT_HF_CODEC_ID_CVSD, BT_HF_CODEC_ID_MSBC);
1678 bt_hf_info->context = NULL;
1680 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1683 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
1686 if (!ret || !strstr(buf, "OK"))
1692 static int _hf_agent_codec_setup(const char *addr, guint codec_id)
1697 ERR("g_obj_path is NULL\n");
1698 return BT_HF_AGENT_ERROR_INTERNAL;
1702 case BT_HF_CODEC_ID_CVSD:
1703 INFO("Set NB parameters");
1704 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1705 g_variant_new("(ss)", "Handsfree", addr),
1706 BT_ADAPTER_INTERFACE,
1709 case BT_HF_CODEC_ID_MSBC:
1710 INFO("Set WBS parameters");
1711 ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
1712 g_variant_new("(ss)", "Handsfree", addr),
1713 BT_ADAPTER_INTERFACE,
1714 "SetWbsParameters");
1717 ret = BT_HF_AGENT_ERROR_INTERNAL;
1718 ERR("Invalid Codec\n");
1723 ERR("Failed to setup the Codec\n");
1725 current_codec_id = codec_id;
1730 static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info,
1733 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
1737 if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) {
1738 INFO("Codec id doesn't match, so send available codec again");
1739 ret = __bt_hf_send_available_codec(bt_hf_info, 1);
1741 ERR("Failed to send avalable codec");
1745 /* HF should be ready accpet SCO connection before sending theresponse for
1746 "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */
1747 retval = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id);
1749 ERR("_hf_agent_codec_setup : Failed [%d]", retval);
1752 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id);
1754 bt_hf_info->context = NULL;
1755 ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
1757 ERR("__bt_hf_send_only : FALSE");
1761 static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1763 gchar indicator[BT_HF_INDICATOR_DESCR_SIZE + 4];
1767 char fmt_str[BT_HF_FMT_STR_SIZE];
1769 DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
1771 snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n",
1772 BT_HF_INDICATOR_DESCR_SIZE + 4 - 1);
1773 if (sscanf(buf, fmt_str, indicator) == 1) {
1774 sep = strchr(indicator, ',');
1777 index = atoi(indicator);
1779 __bt_hf_agent_handle_ind_change(bt_hf_info, index, value);
1781 DBG("--------- __bt_hf_agent_handler_ciev ------------");
1785 static void __bt_hf_agent_handle_ven_samsung(bt_hf_agent_info_t *bt_hf_info,
1786 gint app_id, const char *msg)
1788 /* Whomesoever wants need to handle it */
1789 char *sig_name = "SamsungXSAT";
1790 GDBusConnection *conn;
1792 conn = __bt_hf_get_gdbus_connection();
1794 ERR("Unable to get connection");
1798 __bt_hf_agent_emit_signal(conn,
1799 BT_HF_AGENT_OBJECT_PATH,
1800 BT_HF_SERVICE_INTERFACE,
1802 g_variant_new("(is)", app_id, msg));
1805 static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1807 DBG("++++++++ __bt_hf_agent_handler_ring ++++++++");
1808 DBG("---------__bt_hf_agent_handler_ring --------");
1813 static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1815 DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++");
1816 __bt_hf_agent_handle_clip(bt_hf_info, buf);
1817 DBG("---------__bt_hf_agent_handler_clip --------");
1822 static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1824 DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++");
1826 if (sscanf(buf, "\r\n+BVRA:%1d\r\n", &value) == 1)
1827 __bt_hf_agent_handle_voice_activation(value);
1829 DBG("---------__bt_hf_agent_handler_bvra --------");
1833 static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1836 DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-");
1837 if (sscanf(buf, "\r\n+BCS:%3d\r\n", &codec_id))
1838 __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id);
1840 DBG("---------__bt_hf_agent_handler_bcs --------");
1844 static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1848 DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
1850 ret = sscanf(buf, "\r\n+VGS:%2d\r\n", &value);
1851 else if (buf[6] == '=')
1852 ret = sscanf(buf, "\r\n+VGS=%2d\r\n", &value);
1854 __bt_hf_agent_handle_speaker_gain(value);
1856 DBG("---------__bt_hf_agent_handler_vgs --------");
1861 static int __bt_hf_agent_handler_ccwa(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1863 DBG("+++++++++ __bt_hf_agent_handler_ccwa ++++++++");
1864 __bt_hf_agent_handle_ccwa(bt_hf_info, buf);
1865 DBG("---------__bt_hf_agent_handler_ccwa --------");
1871 static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
1875 char msg[BT_HF_DATA_BUF_SIZE];
1876 char fmt_str[BT_HF_CMD_BUF_SIZE];
1878 DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
1879 snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n",
1880 (int)(sizeof(msg) - 1));
1881 if (sscanf(buf, fmt_str, &app_id, msg)) {
1882 if (app_id == 2 && strstr(msg, "READTXPOWER")) {
1883 char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, };
1884 char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr);
1885 snprintf(cmd_buf, sizeof(cmd_buf), "AT+XSAT: 2,%d", power);
1886 bt_hf_agent_send_at_cmd(NULL, cmd_buf);
1888 __bt_hf_agent_handle_ven_samsung(bt_hf_info, app_id, msg);
1892 DBG("---------__bt_hf_agent_handler_xsat --------");
1897 static int __bt_hf_agent_handler_bsir(bt_hf_agent_info_t *bt_hf_info, const char *buf)
1899 DBG("+++++++++ __bt_hf_agent_handler_bsir +++++++++");
1901 if (sscanf(buf, "\r\n+BSIR:%1d\r\n", &value) == 1)
1902 __bt_hf_agent_handle_bsir(bt_hf_info, value);
1904 DBG("---------__bt_hf_agent_handler_bsir --------");
1908 static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info,
1911 DBG("+++++++++ __bt_hf_agent_handler_cme_error ++++++++");
1913 GDBusConnection *conn;
1915 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1916 conn = __bt_hf_get_gdbus_connection();
1918 ERR("Unable to get connection");
1922 __bt_hf_agent_emit_signal(conn,
1923 BT_HF_AGENT_OBJECT_PATH,
1924 BT_HF_SERVICE_INTERFACE,
1929 __bt_hf_clear_prev_sent_cmd();
1934 static int __bt_hf_agent_handler_response_ok(bt_hf_agent_info_t *bt_hf_info,
1937 DBG("+++++++++ __bt_hf_agent_handler_response_ok ++++++++");
1939 __bt_hf_clear_prev_sent_cmd();
1944 static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info,
1947 DBG("+++++++++ __bt_hf_agent_handler_response_err ++++++++");
1948 GDBusConnection *conn;
1950 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1951 conn = __bt_hf_get_gdbus_connection();
1953 ERR("Unable to get connection");
1957 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1958 BT_HF_SERVICE_INTERFACE,
1962 __bt_hf_clear_prev_sent_cmd();
1967 static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info,
1971 GDBusConnection *conn;
1973 if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
1974 conn = __bt_hf_get_gdbus_connection();
1976 ERR("Unable to get connection");
1980 __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
1981 BT_HF_SERVICE_INTERFACE,
1986 __bt_hf_clear_prev_sent_cmd();
1992 static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char *buffer)
1995 GSList *call_list = NULL;
1996 DBG("+++++++++ __bt_hf_agent_handler_clcc ++++++++");
1997 DBG_SECURE("Receive CLCC response buffer = '%s'", buffer);
1999 __bt_hf_lock_display(0);
2001 call_list = __bt_hf_prepare_call_list(buffer);
2003 if (call_list == NULL)
2006 __bt_hf_launch_call_using_call_list(call_list);
2008 __bt_hf_agent_send_call_status_info(call_list);
2010 __bt_hf_free_call_list(call_list);
2013 __bt_hf_unlock_display();
2014 DBG("---------__bt_hf_agent_handler_clcc --------");
2018 static bt_hf_event hf_event_callbacks[] = {
2019 { "\r\n+CIEV:", __bt_hf_agent_handler_ciev },
2020 { "\r\nRING", __bt_hf_agent_handler_ring },
2021 { "\r\n+CLIP:", __bt_hf_agent_handler_clip },
2022 { "\r\n+BVRA:", __bt_hf_agent_handler_bvra },
2023 { "\r\n+BCS:", __bt_hf_agent_handler_bcs },
2024 { "\r\n+VGS", __bt_hf_agent_handler_vgs },
2025 { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa },
2026 { "\r\n+XSAT:", __bt_hf_agent_handler_xsat },
2027 {"\r\n+CLCC:", __bt_hf_agent_handler_clcc },
2028 {"\r\n+BSIR:", __bt_hf_agent_handler_bsir },
2032 static bt_hf_event hf_event_resp_callbacks[] = {
2033 { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error },
2034 { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok },
2035 { "ERROR", __bt_hf_agent_handler_response_err },
2036 { "SERR", __bt_hf_agent_handler_response_serr },
2040 bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info)
2044 bt_hf_agent_send_at_info *cmd;
2045 len = g_slist_length(bt_hf_info->cmd_send_queue);
2046 for (i = 0; i < len; ++i) {
2047 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i);
2049 DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id);
2051 len = g_slist_length(bt_hf_info->cmd_send_queue);
2052 DBG("Context queue length = %d", len);
2056 cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
2058 bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
2059 DBG("NEXT[%d] Found %s, context = 0x%p, pending = %d", cmd->id,
2060 cmd->at_cmd, cmd->context, cmd->pending);
2064 DBG("**** Not found any pending command on list length %d ****", len);
2069 static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf)
2073 bt_hf_agent_send_at_info *cmd = NULL;
2075 __bt_hf_agent_print_at_buffer("Processing [Rx cmd]:", buf);
2077 for (ev = hf_event_resp_callbacks; ev->cmd; ev++) {
2078 if (strstr(buf, ev->cmd)) {
2081 DBG("Send flag value = %d(after)", send_flag);
2082 ret = ev->callback(bt_hf_info, buf);
2089 for (ev = hf_event_callbacks; ev->cmd; ev++) {
2090 if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) {
2091 ret = ev->callback(bt_hf_info, buf);
2099 cmd = __bt_hf_agent_find_next(bt_hf_info);
2101 if (cmd && cmd->context) {
2102 DBG("Pending context found for %.6s[%d]", cmd->at_cmd, cmd->id);
2103 g_dbus_method_invocation_return_value(cmd->context, NULL);
2105 g_source_remove(cmd->timer_id);
2111 cmd = __bt_hf_agent_find_next(bt_hf_info);
2113 if (cmd && cmd->pending && send_flag == 0) {
2114 DBG("Pending only found of %.6s[%d]", cmd->at_cmd, cmd->id);
2115 __bt_hf_send_only_without_queue(bt_hf_info,
2116 cmd->at_cmd, cmd->count);
2117 cmd->pending = FALSE;
2118 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
2120 DBG("Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
2123 DBG("Pending free for %.6s[%d] - send_flag = %d",
2124 cmd->at_cmd, cmd->id, send_flag);
2126 g_source_remove(cmd->timer_id);
2132 /* Need to process further pending */
2133 cmd = __bt_hf_agent_find_next(bt_hf_info);
2135 if (cmd->pending && send_flag == 0) {
2136 DBG("2nd Pending only found of %.6s[%d]",
2137 cmd->at_cmd, cmd->id);
2138 __bt_hf_send_only_without_queue(bt_hf_info,
2139 cmd->at_cmd, cmd->count);
2140 cmd->pending = FALSE;
2142 bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
2144 DBG("2nd Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
2150 static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf)
2154 int cmd_buf_len = 0;
2155 char *pos_start, *pos_end;
2156 const char *datap = buf;
2158 cmd_buf_len = strlen(cmd_buf);
2159 buf_length = strlen(buf);
2160 DBG("buf_length = %d, cmd_buf_len = %d", buf_length, cmd_buf_len);
2162 if (buf_length > 0 && strstr(datap, "+CLCC")) {
2163 pos_start = strstr(datap, "\r\n");
2164 if (pos_start == NULL) {
2165 ERR("Invalid AT command signature..\n");
2169 pos_end = g_strrstr(datap, "+CLCC");
2170 if (pos_end == NULL) {
2171 ERR("Invalid AT command signature..\n");
2174 pos_end = strstr(pos_end, "\r\n");
2175 cmd_length = (pos_end - pos_start) + 2;
2176 INFO("CLCC balance Cmd Length = %d\n", cmd_length);
2177 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
2178 cmd_buf[cmd_buf_len + cmd_length] = '\0';
2180 if (strstr(cmd_buf, "\r\nOK\r\n")) {
2181 pos_end = strstr(datap, "\r\nOK\r\n");
2182 cmd_length = (pos_end - pos_start);
2183 memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
2184 cmd_buf[cmd_buf_len + cmd_length] = '\0';
2185 INFO("New CLCC balance Cmd Length = %d", cmd_length);
2192 static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf)
2196 char *pos_start, *pos_end;
2198 gchar cmd_buf[BT_HF_DATA_BUF_SIZE] = {0,};
2199 const char *datap = buf;
2201 __bt_hf_agent_print_at_buffer("[HF AT CMD] Recv >>>>>:", buf);
2203 buf_length = strlen(buf);
2205 while (buf_length > 0) {
2206 pos_start = strstr(datap, "\r\n");
2207 if (pos_start == NULL) {
2208 ERR("Invalid AT command start signature..\n");
2213 pos_end = strstr(datap, "\r\n");
2214 if (pos_end == NULL) {
2215 ERR("Invalid AT command end signature..\n");
2218 cmd_length = (pos_end - pos_start) + 2;
2219 DBG("Cmd Length = %d\n", cmd_length);
2221 if (cmd_length > BT_HF_DATA_BUF_SIZE - 1)
2223 memcpy(cmd_buf, pos_start, cmd_length);
2224 cmd_buf[cmd_length] = '\0';
2226 buf_length = buf_length - cmd_length;
2227 datap = datap + cmd_length - 2;
2229 /* We need to pass all the CLCC's together to its handler */
2230 if (strstr(cmd_buf, "+CLCC")) {
2231 tmp = hf_handle_append_clcc_buff(cmd_buf, datap);
2233 buf_length = buf_length - tmp;
2235 hf_handle_rx_at_cmd(bt_hf_info, cmd_buf);
2236 DBG("Pending buf_length = %d\n", buf_length);
2241 static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
2242 bt_hf_agent_info_t *bt_hf_info)
2244 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2246 GError *gerr = NULL;
2247 gboolean recvd_ok = FALSE;
2248 gboolean recvd_error = FALSE;
2249 gboolean recvd_sec_error = FALSE;
2251 if (cond & (G_IO_ERR | G_IO_HUP)) {
2252 ERR("ERR or HUP on RFCOMM socket");
2253 INFO_C("### Disconnected [HF role] [Terminated by remote dev]");
2254 is_hf_connected = FALSE;
2255 bt_hf_info->slc = FALSE;
2256 __bt_hf_agent_release();
2260 if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, &gerr)
2261 != G_IO_STATUS_NORMAL) {
2263 ERR("Read failed, cond = [%d], Err msg = [%s]",
2264 cond, gerr->message);
2270 recvd_ok = NULL != strstr(buf, BT_HF_OK_RESPONSE);
2271 recvd_error = NULL != strstr(buf, BT_HF_ERROR_RESPONSE);
2272 recvd_sec_error = NULL != strstr(buf, BT_HF_SEC_ERROR_RESPONSE);
2273 DBG("<-------Received data --send flag status = %d ----->", send_flag);
2275 /* Once service level connection is established we need to handle
2276 * all the intermediate AT commands */
2277 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2281 strncat(global_buff, buf,
2282 (BT_AT_COMMAND_BUFFER_MAX - 1) - strlen(global_buff));
2283 if (!(recvd_ok || recvd_error || recvd_sec_error)) {
2284 __bt_hf_agent_print_at_buffer("Concat ()", global_buff);
2286 DBG("*** Received terminator.. process Rx buffer ***");
2287 hf_handle_rx_at_buff(bt_hf_info, global_buff);
2288 memset(global_buff, 0, sizeof(global_buff));
2291 INFO("*** Received Direct AT buffer packet handling ****");
2292 hf_handle_rx_at_buff(bt_hf_info, buf);
2297 static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info)
2299 bt_hf_info->watch_id = g_io_add_watch(bt_hf_info->io_chan,
2300 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2301 (GIOFunc) __bt_hf_agent_data_cb, bt_hf_info);
2304 static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info)
2306 if (bt_hf_info->watch_id > 0) {
2307 g_source_remove(bt_hf_info->watch_id);
2308 bt_hf_info->watch_id = 0;
2312 static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
2319 status = g_io_channel_write_chars(io, data, count, &written,
2321 if (status != G_IO_STATUS_NORMAL)
2330 static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
2331 gchar *data, gsize count)
2333 GIOChannel *io_chan = bt_hf_info->io_chan;
2334 if (!__bt_hf_channel_write(io_chan, data, count))
2337 g_io_channel_flush(io_chan, NULL);
2339 if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
2340 INFO("[HF AT CMD] Send only without queue <<<<<: Buffer = %s, Length = %zd ",
2341 "ATDXXXXXXX", count);
2342 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
2344 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send only without queue <<<<<:",
2349 /* DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
2350 * send_flag, count, data); */
2355 static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
2358 gboolean pending = FALSE;
2359 GIOChannel *io_chan = bt_hf_info->io_chan;
2364 __bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
2369 if (!__bt_hf_channel_write(io_chan, data, count))
2372 g_io_channel_flush(io_chan, NULL);
2374 if (count > 2 && data[2] == 'D') /* ATDXXXXX */
2375 INFO("[HF AT CMD] Send only <<<<<: Buffer = %s, Length = %zd ",
2376 "ATDXXXXXXX", count);
2378 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send only <<<<<:",
2382 DBG("Ref %d(after) on Send only buffer size =[%zd] - Send <<<<<",
2387 static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
2388 gchar *data, gchar *response, gsize count)
2390 GIOChannel *io_chan = bt_hf_info->io_chan;
2392 gboolean recvd_ok = FALSE;
2393 gboolean recvd_error = FALSE;
2394 gboolean recvd_sec_error = FALSE;
2395 gchar *resp_buf = response;
2396 gsize toread = BT_HF_DATA_BUF_SIZE - 1;
2401 GDBusConnection *conn;
2403 /* Should not send cmds if DUT send a command and wait the response */
2404 if (prev_cmd[0] != 0) {
2405 INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
2409 memset(resp_buf, 0, BT_HF_DATA_BUF_SIZE);
2411 if (!__bt_hf_channel_write(io_chan, data, count))
2414 g_io_channel_flush(io_chan, NULL);
2416 __bt_hf_agent_print_at_buffer("[HF AT CMD] Send <<<<<:", data);
2418 fd = g_io_channel_unix_get_fd(io_chan);
2420 p.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
2422 /* Maximun 8 seconds of poll or 8 minus no of cmd received */
2423 for (i = 1; i <= MAX_WAITING_DELAY; i++) {
2424 DBG("Loop Counter = %d", i);
2426 err = poll(&p, 1, 1000);
2428 ERR("Loop Counter = %d, >>>> Poll error happen", i);
2430 } else if (err == 0) {
2431 INFO("Loop Counter = %d, >>>> Poll Timeout", i);
2434 if (p.revents & (POLLERR | POLLHUP | POLLNVAL)) {
2435 ERR("Loop Counter = %d, >> Poll ERR/HUP/INV (%d)",
2438 conn = __bt_hf_get_gdbus_connection();
2440 ERR("Unable to get connection");
2444 __bt_hf_agent_emit_signal(conn,
2445 BT_HF_AGENT_OBJECT_PATH,
2446 BT_HF_SERVICE_INTERFACE,
2448 g_variant_new("(s)",
2449 bt_hf_info->remote_addr));
2451 bt_hf_info->state = BT_HF_STATE_DISCONNECTED;
2455 if (p.revents & POLLIN) {
2456 rd_size = read(fd, resp_buf, toread);
2457 resp_buf[rd_size] = '\0';
2458 DBG_SECURE("size = %zd, Buffer=[%s]", rd_size, resp_buf);
2459 recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
2460 recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
2461 recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
2463 resp_buf += rd_size;
2466 if (recvd_ok || recvd_error || recvd_sec_error) {
2467 DBG("Break Loop Counter = %d", i);
2473 /* Once service level connection is established we need to handle
2474 * all the intermediate AT commands */
2475 if (bt_hf_info->state == BT_HF_STATE_CONNECTED)
2476 hf_handle_rx_at_buff(bt_hf_info, response);
2480 static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indices)
2482 struct indicator *ind;
2483 gchar *cur = names - 1;
2484 GSList *list = indices;
2487 DBG("Indicator buffer = %s", names);
2488 __bt_hf_agent_print_at_buffer("Indicator names :", names);
2489 while (cur != NULL) {
2491 next = strstr(cur, ",(");
2492 ind = g_new0(struct indicator, 1);
2493 g_strlcpy(ind->descr, cur, BT_HF_INDICATOR_DESCR_SIZE);
2494 ind->descr[(intptr_t) next - (intptr_t) cur] = '\0';
2495 list = g_slist_append(list, (gpointer) ind);
2496 cur = strstr(next + 1, ",(");
2501 static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices)
2504 struct indicator *ind;
2505 GSList *runner = indices;
2507 gchar *cur = values - 1;
2508 DBG("Indicator string = %s", values);
2509 __bt_hf_agent_print_at_buffer("Indicator values :", values);
2510 while (cur != NULL) {
2512 sscanf(cur, "%1d", &val);
2513 cur = strchr(cur, ',');
2514 ind = g_slist_nth_data(runner, 0);
2517 runner = g_slist_next(runner);
2524 static guint __bt_hf_get_hold_mpty_features(gchar *features)
2528 if (strstr(features, "0"))
2529 result |= BT_HF_CHLD_0;
2531 if (strstr(features, "1"))
2532 result |= BT_HF_CHLD_1;
2534 if (strstr(features, "1x"))
2535 result |= BT_HF_CHLD_1x;
2537 if (strstr(features, "2"))
2538 result |= BT_HF_CHLD_2;
2540 if (strstr(features, "2x"))
2541 result |= BT_HF_CHLD_2x;
2543 if (strstr(features, "3"))
2544 result |= BT_HF_CHLD_3;
2546 if (strstr(features, "4"))
2547 result |= BT_HF_CHLD_4;
2552 /* for FHUB's HFP HF role */
2553 #include <sound_manager.h>
2554 sound_stream_info_h g_stream_info_write_h = NULL;
2556 static void __release_audio_in(bt_hf_agent_info_t *bt_hf_info)
2560 if (bt_hf_info->audio_input != NULL) {
2561 audio_in_unprepare((audio_in_h)bt_hf_info->audio_input);
2562 audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
2563 bt_hf_info->audio_input = NULL;
2569 static void __release_audio_out(bt_hf_agent_info_t *bt_hf_info)
2573 if (bt_hf_info->audio_output != NULL) {
2574 /* Skip audio drain */
2575 //audio_out_drain((audio_out_h)bt_hf_info->audio_output);
2576 audio_out_unprepare((audio_out_h)bt_hf_info->audio_output);
2577 audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
2578 bt_hf_info->audio_output = NULL;
2584 static int __initialize_audio_in(bt_hf_agent_info_t *bt_hf_info)
2589 if (bt_hf_info->audio_input != NULL) {
2590 __release_audio_in(bt_hf_info);
2594 ret = audio_in_create(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
2595 AUDIO_SAMPLE_TYPE_S16_LE, (audio_in_h *)&bt_hf_info->audio_input);
2596 if (ret == AUDIO_IO_ERROR_NONE) {
2597 if (!(audio_in_prepare((audio_in_h)bt_hf_info->audio_input))) {
2598 DBG("voice capturing is ready!\n");
2599 bt_hf_info->is_audio_input_mute = FALSE;
2601 ERR("audio_in_prepare failed, err(0x%x)\n", ret);
2602 audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
2606 ERR("audio_in_create failed.\n");
2614 static int __initialize_audio_out(bt_hf_agent_info_t *bt_hf_info)
2619 if (bt_hf_info->audio_output != NULL) {
2620 __release_audio_out(bt_hf_info);
2624 ret = audio_out_create_new(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
2625 AUDIO_SAMPLE_TYPE_S16_LE, (audio_out_h *)&bt_hf_info->audio_output);
2626 if (ret == AUDIO_IO_ERROR_NONE) {
2627 INFO("after audio_out_create!!!");
2629 /* set sound stream info */
2630 if (g_stream_info_write_h) {
2631 if (!(ret = audio_out_set_sound_stream_info(bt_hf_info->audio_output, g_stream_info_write_h))) {
2632 INFO("after audio_out_set_sound_stream_info");
2634 ERR("fail to audio_out_set_sound_stream_info(), ret(0x%x)\n", ret);
2637 ERR("no stream info!!!!");
2641 if (!(ret = audio_out_prepare((audio_out_h)bt_hf_info->audio_output))) {
2642 DBG("voice playback is ready!\n");
2644 ERR("audio_out_prepare failed, err(0x%x)\n", ret);
2645 audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
2646 bt_hf_info->audio_output = NULL;
2649 ERR("audio_out_create failed. \n");
2656 static gboolean __bt_hf_agent_sco_event_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2658 bt_hf_agent_info_t *bt_hf_info = user_data;
2659 GDBusConnection *conn;
2660 int sco_skt = g_io_channel_unix_get_fd(chan);
2662 if (cond & G_IO_NVAL)
2665 if (cond & (G_IO_HUP | G_IO_ERR)) {
2666 g_io_channel_shutdown(chan, TRUE, NULL);
2667 close(bt_hf_info->cli_sco_fd);
2668 bt_hf_info->cli_sco_fd = -1;
2669 g_io_channel_unref(chan);
2670 DBG("Emit AudioDisconnected Signal");
2672 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2674 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
2675 bt_hf_info->is_first_audio_out = TRUE;
2677 __release_audio_out(bt_hf_info);
2678 __release_audio_in(bt_hf_info);
2680 conn = __bt_hf_get_gdbus_connection();
2682 ERR("Unable to get connection");
2685 __bt_hf_agent_emit_signal(conn,
2686 BT_HF_AGENT_OBJECT_PATH,
2687 BT_HF_SERVICE_INTERFACE,
2688 "AudioDisconnected", NULL);
2693 if (cond & G_IO_IN) {
2694 gchar buf_rx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
2697 read = recv(sco_skt, buf_rx, HFP_SCO_DATA_BUFFER_SIZE, MSG_DONTWAIT);
2699 if (bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING ||
2700 bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING ||
2701 bt_hf_info->call_active) {
2703 if (bt_hf_info->is_first_audio_out) {
2704 __initialize_audio_out(bt_hf_info);
2705 bt_hf_info->is_first_audio_out = FALSE;
2707 if (bt_hf_info->audio_output) {
2708 audio_out_write(bt_hf_info->audio_output, buf_rx, read);
2710 ERR("can't write audio");
2715 if (cond & G_IO_OUT) {
2716 gchar buf_tx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
2719 if (bt_hf_info->is_first_audio_in) {
2720 __initialize_audio_in(bt_hf_info);
2721 bt_hf_info->is_first_audio_in = FALSE;
2725 size = audio_in_read(bt_hf_info->audio_input, (void *)buf_tx, HFP_SCO_DATA_BUFFER_SIZE);
2727 if (bt_hf_info->call_active) {
2729 if (bt_hf_info->is_audio_input_mute) {
2730 memset(buf_tx, 0x0, size);
2733 if (send(sco_skt, buf_tx, size, MSG_DONTWAIT) < 0) {
2734 ERR("Write failed, error = %d[%s]", errno, strerror(errno));
2743 static gboolean __bt_hf_agent_sco_disconnect_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2745 bt_hf_agent_info_t *bt_hf_info = user_data;
2746 GDBusConnection *conn;
2749 if (cond & G_IO_NVAL)
2752 if (cond & (G_IO_HUP | G_IO_ERR)) {
2753 g_io_channel_shutdown(chan, TRUE, NULL);
2754 close(bt_hf_info->cli_sco_fd);
2755 bt_hf_info->cli_sco_fd = -1;
2756 g_io_channel_unref(chan);
2757 DBG("Emit AudioDisconnected Signal");
2759 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2761 conn = __bt_hf_get_gdbus_connection();
2763 ERR("Unable to get connection");
2766 __bt_hf_agent_emit_signal(conn,
2767 BT_HF_AGENT_OBJECT_PATH,
2768 BT_HF_SERVICE_INTERFACE,
2769 "AudioDisconnected", NULL);
2777 static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2779 bt_hf_agent_info_t *bt_hf_info = user_data;
2783 GDBusConnection *conn;
2785 INFO("Incoming SCO....");
2787 if (cond & G_IO_NVAL)
2790 sco_skt = g_io_channel_unix_get_fd(chan);
2792 if (cond & (G_IO_HUP | G_IO_ERR)) {
2797 cli_sco_sock = accept(sco_skt, NULL, NULL);
2798 if (cli_sco_sock < 0)
2801 bt_hf_info->cli_sco_fd = cli_sco_sock;
2803 sco_io = g_io_channel_unix_new(cli_sco_sock);
2804 g_io_channel_set_close_on_unref(sco_io, TRUE);
2805 g_io_channel_set_encoding(sco_io, NULL, NULL);
2806 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2807 g_io_channel_set_buffered(sco_io, FALSE);
2809 if (TIZEN_MODEL_NAME_DA) {
2810 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
2811 bt_hf_info->is_first_audio_out = TRUE;
2812 bt_hf_info->is_first_audio_in = TRUE;
2813 //__initialize_audio_in(bt_hf_info);
2815 g_io_add_watch(sco_io, G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2816 __bt_hf_agent_sco_event_cb, bt_hf_info);
2818 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2819 __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
2821 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2822 ERR("HFP is not yet connected");
2824 /* S-Voice app requires the AudioConnected signal earlier */
2825 DBG("Emit AudioConnected Signal");
2827 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
2829 conn = __bt_hf_get_gdbus_connection();
2831 ERR("Unable to get connection");
2835 __bt_hf_agent_emit_signal(conn,
2836 BT_HF_AGENT_OBJECT_PATH,
2837 BT_HF_SERVICE_INTERFACE,
2838 "AudioConnected", NULL);
2840 /* In the case of incoming call, the call app is already launched,
2841 * hence AudioConnected signal is enough to update the call status.
2842 * In the case of outgoing call we need to lauch the callapp.
2845 __bt_hf_agent_launch_call_app();
2850 static void __bt_convert_addr_string_to_type_rev(unsigned char *addr,
2851 const char *address)
2856 ret_if(address == NULL);
2857 ret_if(addr == NULL);
2859 for (i = 0; i < BT_ADDRESS_LENGTH_MAX; i++) {
2860 addr[5 - i] = strtol(address, &ptr, 16);
2861 if (ptr[0] != '\0') {
2870 static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
2872 struct sockaddr_sco addr;
2874 bdaddr_t bd_addr = {{0},};
2878 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
2880 ERR("Can't create socket:\n");
2884 /* Bind to local address */
2885 memset(&addr, 0, sizeof(addr));
2886 addr.sco_family = AF_BLUETOOTH;
2888 DBG("Bind to address %s", bt_hf_info->remote_addr);
2890 __bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
2891 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2893 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2894 ERR("Can't bind socket:\n");
2898 if (listen(sco_skt, 1)) {
2899 ERR("Can not listen on the socket:\n");
2903 sco_io = g_io_channel_unix_new(sco_skt);
2904 g_io_channel_set_close_on_unref(sco_io, TRUE);
2905 g_io_channel_set_encoding(sco_io, NULL, NULL);
2906 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2907 g_io_channel_set_buffered(sco_io, FALSE);
2909 bt_hf_info->sco_fd = sco_skt;
2910 bt_hf_info->sco_io_chan = sco_io;
2912 bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
2913 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
2915 g_io_channel_unref(sco_io);
2924 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
2926 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2929 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
2930 sizeof(BT_HF_INDICATORS_SUPP) - 1);
2931 if (!ret || !strstr(buf, "+CIND:"))
2934 bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
2939 static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
2944 if (bt_hf_info == NULL || cmd == NULL) {
2945 ERR("Invalid parameter");
2949 ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
2951 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
2952 ret = g_strlcat(cmd, "0,", cmd_size);
2953 if (ret >= cmd_size) {
2954 ERR("Too many indices");
2960 cmd[ret - 1] = '\0';
2961 DBG("BIA Str : %s", cmd);
2963 ret = g_strlcat(cmd, "\r", cmd_size);
2964 if (ret >= cmd_size) {
2965 ERR("Too many indices");
2972 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
2974 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2980 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
2981 sizeof(BT_HF_INDICATORS_VAL) - 1);
2982 if (!ret || !strstr(buf, "+CIND:"))
2985 /* if buf has other command prefix, skip it */
2986 str = strstr(buf, "+CIND");
2990 bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
2992 /* Parse the updated value */
2993 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
2994 struct indicator *ind = l->data;
2996 DBG("Index is NULL");
3000 if (0 == g_strcmp0(ind->descr, "\"call\"")) {
3001 DBG("CIND Match found index = %d, %s, value = %d",
3002 index, ind->descr, ind->value);
3003 bt_hf_info->ciev_call_status = ind->value;
3004 if (ind->value > 0) {
3005 bt_hf_info->is_dialing = FALSE;
3006 bt_hf_info->call_active = TRUE;
3008 } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
3009 DBG("CIND Match found index = %d, %s, value = %d",
3010 index, ind->descr, ind->value);
3011 bt_hf_info->ciev_call_setup_status = ind->value;
3012 if (!bt_hf_info->is_dialing && ind->value > 0)
3013 bt_hf_info->is_dialing = TRUE;
3020 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
3022 gchar buf[BT_HF_DATA_BUF_SIZE];
3023 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
3028 if (TIZEN_MODEL_NAME_DA)
3029 feature = BT_HF_FEATURE_CLI_PRESENTATION |
3030 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3031 BT_HF_FEATURE_ESCO_S4;
3033 feature = BT_HF_FEATURE_EC_ANDOR_NR |
3034 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
3035 BT_HF_FEATURE_CLI_PRESENTATION |
3036 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3037 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
3039 if (TIZEN_PROFILE_WEARABLE)
3040 feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
3043 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
3044 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
3049 buf_ptr = strstr(buf, "\r\n+BRSF:");
3050 if (buf_ptr == NULL)
3053 if (!ret || sscanf(buf_ptr, "\r\n+BRSF:%5d", &bt_hf_info->ag_features) != 1)
3055 INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
3057 if (TIZEN_PROFILE_WEARABLE) {
3058 if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
3059 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
3060 if (ret != BT_HF_AGENT_ERROR_NONE)
3061 ERR("Unable to set the default WBC codec");
3063 ret = __bt_hf_send_available_codec(bt_hf_info, 0);
3068 /* Default codec is NB */
3069 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
3070 if (ret != BT_HF_AGENT_ERROR_NONE)
3071 ERR("Unable to set the default NBC codec");
3074 ret = __bt_get_supported_indicators(bt_hf_info);
3079 ret = __bt_get_current_indicators(bt_hf_info);
3083 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
3084 sizeof(BT_HF_INDICATORS_ENABLE) - 1);
3085 if (!ret || !strstr(buf, "OK"))
3088 if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
3089 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
3090 buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
3091 if (!ret || !strstr(buf, "+CHLD:")) {
3092 ERR("Unable to get the CHLD Supported info");
3095 bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
3098 bt_hf_info->hold_multiparty_features = 0;
3100 if (bt_hf_info->ag_features & BT_AG_FEATURE_INBAND_RINGTONE)
3101 bt_hf_info->inband_ringtone_support = TRUE;
3103 bt_hf_info->inband_ringtone_support = FALSE;
3105 INFO("Service layer connection successfully established...!");
3107 bt_hf_info->slc = TRUE;
3110 memset(global_buff, 0, sizeof(global_buff));
3114 static void __bt_establish_initialization(bt_hf_agent_info_t *bt_hf_info)
3116 gchar buf[BT_HF_DATA_BUF_SIZE];
3117 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
3120 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
3121 sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
3122 __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
3123 sizeof(BT_HF_CARRIER_FORMAT) - 1);
3124 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
3125 sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
3127 if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
3128 __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
3129 sizeof(BT_HF_NREC) - 1);
3131 if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
3132 __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
3133 buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
3135 if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
3136 __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
3138 ERR("__bt_get_bia_cmd is failed");
3140 if (!TIZEN_MODEL_NAME_DA) {
3141 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
3142 sizeof(BT_HF_XSAT) - 1);
3144 DBG("sent BT_HF_XSAT");
3146 ERR("BT_HF_XSAT sending failed");
3149 if (TIZEN_PROFILE_WEARABLE) {
3150 /* send Bluetooth Samsung Support Feature cmd */
3151 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
3152 sizeof(BT_HF_BSSF) - 1);
3154 /* If we got a 'OK' reply, peer AG is samsung device.
3155 * Otherwise, non-samsung device */
3156 if (ret && strstr(buf, "OK"))
3157 bt_hf_info->is_companion_dev = TRUE;
3159 bt_hf_info->is_companion_dev = FALSE;
3162 INFO("SLC completed with [%s] device",
3163 bt_hf_info->is_companion_dev ? "SS Companion" : "Other");
3165 ERR("BT_HF_BSSF sending failed");
3169 static void __bt_hf_agent_sigterm_handler(int signo)
3171 GDBusConnection *conn;
3174 ERR_C("***** Signal handler came with signal %d *****", signo);
3176 conn = __bt_hf_get_gdbus_connection();
3178 ERR("Unable to get G-DBus connection");
3181 INFO("Getting gdbus connection done");
3183 __bt_hf_agent_emit_signal(conn,
3184 BT_HF_AGENT_OBJECT_PATH,
3185 BT_HF_SERVICE_INTERFACE,
3187 INFO("CallEnded Signal done");
3189 g_dbus_connection_flush(conn, NULL, NULL, NULL);
3190 INFO("Flush g_dbus_connection");
3194 g_main_loop_quit(gmain_loop);
3198 INFO_C("Terminating HF agent");
3202 if (signo == SIGTERM)
3205 for (i = 0; i < BT_HF_SIG_NUM; i++)
3206 sigaction(bt_hf_sig_to_handle[i], &(bt_hf_sigoldact[i]), NULL);
3211 static void __bt_convert_addr_type_to_rev_string(char *address,
3212 unsigned char *addr)
3214 ret_if(address == NULL);
3215 ret_if(addr == NULL);
3217 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
3218 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
3219 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
3223 static gboolean __bt_hf_agent_release_after(gpointer user_data)
3225 if (__bt_hf_agent_release() == FALSE)
3226 ERR("Unable to release hf connection");
3231 static gboolean __bt_agent_request_service_level_conn(gpointer data)
3234 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
3235 GDBusConnection *conn;
3238 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
3240 __bt_hf_agent_sco_accept(&bt_hf_info);
3242 if (!__bt_establish_service_level_conn(&bt_hf_info)) {
3243 ERR("Service Level Connection is fail");
3245 conn = __bt_hf_get_gdbus_connection();
3247 remote_addr = bt_hf_info.remote_addr;
3248 __bt_hf_agent_emit_signal(conn,
3249 BT_HF_AGENT_OBJECT_PATH,
3250 BT_HF_SERVICE_INTERFACE,
3252 g_variant_new("(s)", remote_addr));
3254 bt_hf_info.state = BT_HF_STATE_CONNECTED;
3256 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3257 DBG("BT device state is : 0x%X", bt_device_state);
3258 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3259 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3260 ERR("vconf_set_int failed");
3262 ERR("vconf_get_int failed");
3265 g_idle_add(__bt_hf_agent_release_after, NULL);
3270 bt_hf_info.state = BT_HF_STATE_CONNECTED;
3272 __bt_hf_agent_start_watch(&bt_hf_info);
3274 remote_addr = bt_hf_info.remote_addr;
3276 INFO_SECURE("Address is : %s", remote_addr);
3277 INFO_C("### Connected [HF role]");
3279 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3280 DBG("BT device state is : 0x%X", bt_device_state);
3281 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3283 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3284 ERR("vconf_set_int failed");
3286 ERR("vconf_get_int failed");
3289 conn = __bt_hf_get_gdbus_connection();
3291 ERR("Unable to get connection");
3295 __bt_hf_agent_emit_signal(conn,
3296 BT_HF_AGENT_OBJECT_PATH,
3297 BT_HF_SERVICE_INTERFACE,
3299 g_variant_new("(s)", remote_addr));
3301 /* Establish the initialization */
3302 __bt_establish_initialization(&bt_hf_info);
3309 static void __unprepare_stream_info(void)
3313 if (!g_stream_info_write_h) {
3314 ERR("no stream to destroy");
3318 ret = sound_manager_destroy_stream_information(g_stream_info_write_h);
3319 if (ret != SOUND_MANAGER_ERROR_NONE) {
3320 ERR("Failed to destroy stream information");
3324 g_stream_info_write_h = NULL;
3327 void stream_focus_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
3328 sound_stream_focus_change_reason_e reason, int sound_behavior, const char *extra_info, void *user_data)
3333 static gboolean __prepare_stream_info(void)
3336 sound_device_list_h g_device_list = NULL;
3337 sound_device_h device = NULL;
3338 sound_device_type_e selected_type = SOUND_DEVICE_BUILTIN_SPEAKER;
3339 sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER;
3341 if (TIZEN_MODEL_NAME_FHUB) {
3342 char *processor = NULL;
3344 system_info_get_platform_string("tizen.org/system/platform.processor", &processor);
3346 if (!strcasecmp(processor, "SDP1601")) {
3347 DBG("set specific sound type");
3348 selected_type = SOUND_DEVICE_BUILTIN_RECEIVER;
3349 type = SOUND_DEVICE_BUILTIN_RECEIVER;
3355 if (g_stream_info_write_h) {
3356 ERR("there is already created one %p", g_stream_info_write_h);
3357 __unprepare_stream_info();
3360 ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOIP, stream_focus_cb, NULL, &g_stream_info_write_h);
3361 if (ret != SOUND_MANAGER_ERROR_NONE) {
3362 ERR("Failed to create stream information");
3365 INFO("created stream info %p", g_stream_info_write_h);
3367 ret = sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_OUT_MASK, &g_device_list);
3368 if (ret != SOUND_MANAGER_ERROR_NONE) {
3369 ERR("fail to get current device list, ret(0x%x)\n", ret);
3374 while (!sound_manager_get_next_device(g_device_list, &device)) {
3375 if ((ret = sound_manager_get_device_type(device, &type))) {
3376 ERR("fail to get type of device, ret(0x%x)\n", ret);
3380 if (selected_type == type) {
3381 DBG("try to set route for device\n");
3382 ret = sound_manager_add_device_for_stream_routing(g_stream_info_write_h, device);
3383 if (ret == SOUND_MANAGER_ERROR_NONE) {
3384 ret = sound_manager_apply_stream_routing(g_stream_info_write_h);
3385 if (ret != SOUND_MANAGER_ERROR_NONE)
3386 ERR("failed to sound_manager_apply_stream_routing(), ret(0x%x)\n", ret);
3388 ERR("failed to sound_manager_add_device_for_stream_routing(), ret(0x%x)\n", ret);
3394 ret = sound_manager_free_device_list(g_device_list);
3395 if (ret != SOUND_MANAGER_ERROR_NONE)
3396 ERR("fail to free device list, ret[0x%x]\n", ret);
3398 g_device_list = NULL;
3403 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
3407 struct sockaddr_remote address;
3408 socklen_t address_len;
3409 bt_hf_info.path = g_strdup(obj_path);
3411 INFO_C("**** New HFP connection ****");
3413 is_hf_connected = TRUE;
3415 address_len = sizeof(address);
3416 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
3417 ERR("BD_ADDR is NULL");
3419 DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
3421 bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
3422 flags = g_io_channel_get_flags(bt_hf_info.io_chan);
3424 flags &= ~G_IO_FLAG_NONBLOCK;
3425 flags &= G_IO_FLAG_MASK;
3426 g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
3427 g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
3428 g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
3430 bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
3431 __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
3432 address.remote_bdaddr.b);
3434 if (TIZEN_MODEL_NAME_DA)
3435 __prepare_stream_info();
3437 g_idle_add(__bt_agent_request_service_level_conn, NULL);
3442 static void __bt_hf_agent_indicator_free(gpointer mem)
3447 static gboolean __bt_hf_agent_release(void)
3449 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
3450 GDBusConnection *conn;
3452 if (TIZEN_MODEL_NAME_DA)
3453 __unprepare_stream_info();
3456 g_source_remove(clcc_timer);
3460 if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
3461 ERR("hf is already disconnected");
3465 if (bt_hf_info.indies) {
3466 g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
3467 bt_hf_info.indies = NULL;
3470 if (bt_hf_info.io_chan) {
3471 g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
3472 g_io_channel_unref(bt_hf_info.io_chan);
3473 bt_hf_info.io_chan = NULL;
3476 if (bt_hf_info.sco_watch_id > 0) {
3477 g_source_remove(bt_hf_info.sco_watch_id);
3478 bt_hf_info.sco_watch_id = 0;
3481 bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
3483 __bt_hf_agent_release_queue();
3485 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3486 DBG("BT device state is : 0x%X", bt_device_state);
3487 bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3489 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3490 ERR("vconf_set_int failed");
3492 ERR("vconf_get_int failed");
3495 __bt_hf_agent_stop_watch(&bt_hf_info);
3496 conn = __bt_hf_get_gdbus_connection();
3498 ERR("Unable to get connection");
3502 __bt_hf_agent_emit_signal(conn,
3503 BT_HF_AGENT_OBJECT_PATH,
3504 BT_HF_SERVICE_INTERFACE,
3506 g_variant_new("(s)", bt_hf_info.remote_addr));
3508 g_free(bt_hf_info.path);
3509 bt_hf_info.path = NULL;
3511 g_free(bt_hf_info.remote_addr);
3512 bt_hf_info.remote_addr = NULL;
3514 is_hf_connected = FALSE;
3519 static gboolean __bt_hf_agent_connection_release(void)
3521 return __bt_hf_agent_release();
3524 static int __bt_hf_register_profile(const char *uuid, uint16_t version,
3525 const char *name, const char *object, uint16_t features)
3530 GError *error = NULL;
3531 GVariantBuilder *builder;
3534 proxy = __bt_hf_gdbus_get_profile_proxy();
3537 return BT_HF_AGENT_ERROR_INTERNAL;
3539 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3541 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3543 g_variant_builder_add(builder, "{sv}",
3544 "Name", g_variant_new("s",
3546 g_variant_builder_add(builder, "{sv}",
3547 "Version", g_variant_new("q", version));
3549 g_variant_builder_add(builder, "{sv}",
3550 "features", g_variant_new("q", features));
3552 if (TIZEN_MODEL_NAME_DA)
3553 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3554 g_variant_new("(osa{sv})", object,
3556 G_DBUS_CALL_FLAGS_NONE, -1,
3559 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3560 g_variant_new("(osa{sv})", path,
3561 HFP_HF_UUID, builder),
3562 G_DBUS_CALL_FLAGS_NONE, -1,
3565 g_variant_builder_unref(builder);
3568 /* dBUS-RPC is failed */
3569 ERR("dBUS-RPC is failed");
3570 if (error != NULL) {
3571 /* dBUS gives error cause */
3572 ERR("D-Bus API failure: errCode[%x], message[%s]",
3573 error->code, error->message);
3574 g_clear_error(&error);
3577 return BT_HF_AGENT_ERROR_INTERNAL;
3579 g_variant_unref(ret);
3583 return BT_HF_AGENT_ERROR_NONE;
3586 static void __bt_hf_agent_register(void)
3591 uint16_t version = hf_ver;
3592 uint16_t features = bt_hf_info.feature;
3594 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3595 name = g_strdup("Hands-Free");
3597 ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
3600 ERR("Error in hf register");
3602 if (TIZEN_MODEL_NAME_DA) {
3603 ret = __bt_hf_register_profile(PBAP_PCE_UUID, 0x0101,
3604 "Phone Book Access Client",
3605 BT_PBAP_CLIENT_OBJECT_PATH, 0);
3607 ERR("Error in pce register");
3617 static void __bt_hf_agent_unregister(void)
3621 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3624 __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
3625 g_variant_new("(o)", path),
3626 BLUEZ_HF_INTERFACE_NAME,
3638 static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
3639 const gchar *sender_name,
3640 const gchar *object_path,
3641 const gchar *interface_name,
3642 const gchar *signal_name,
3643 GVariant *parameters,
3647 GVariant *optional_param = NULL;
3649 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3650 g_variant_get(parameters, "(&o@a{sa{sv}})", &path, &optional_param);
3652 g_variant_unref(optional_param);
3655 ERR("Invalid adapter path");
3659 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3660 g_obj_path = g_strdup(path);
3661 INFO("Adapter Path = [%s]", path);
3662 __bt_hf_agent_register();
3664 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
3665 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
3667 __bt_hf_agent_unregister();
3670 g_variant_unref(optional_param);
3674 static int __bt_hf_agent_get_adapter_path(GDBusConnection *conn, char *path)
3677 GDBusProxy *manager_proxy = NULL;
3678 GVariant *result = NULL;
3679 char *adapter_path = NULL;
3682 return BT_HF_AGENT_ERROR_INTERNAL;
3684 manager_proxy = g_dbus_proxy_new_sync(conn,
3685 G_DBUS_PROXY_FLAGS_NONE, NULL,
3688 BT_MANAGER_INTERFACE,
3691 if (!manager_proxy) {
3692 ERR("Unable to create proxy: %s", err->message);
3696 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
3697 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
3700 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
3702 ERR("Fail to get DefaultAdapter");
3707 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
3708 ERR("Incorrect result\n");
3712 g_variant_get(result, "(&o)", &adapter_path);
3714 if (adapter_path == NULL ||
3715 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
3716 ERR("Adapter path is inproper\n");
3721 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
3723 if (g_obj_path == NULL) {
3724 g_obj_path = g_strdup(adapter_path);
3725 INFO("Update g_obj_path [%s]", adapter_path);
3728 g_variant_unref(result);
3729 g_object_unref(manager_proxy);
3734 g_clear_error(&err);
3737 g_variant_unref(result);
3740 g_object_unref(manager_proxy);
3742 return BT_HF_AGENT_ERROR_INTERNAL;
3746 static void __bt_hf_agent_dbus_init(void)
3748 GDBusConnection *conn;
3752 conn = __bt_hf_get_gdbus_connection();
3754 ERR("Error in creating the gdbus connection\n");
3757 if (!__bt_hf_register_profile_methods()) {
3758 ERR("Error in register_profile_methods\n");
3762 if (!__bt_hf_agent_get_adapter_path(gdbus_conn , NULL)) {
3763 __bt_hf_agent_register();
3766 interface_added_sig_id = g_dbus_connection_signal_subscribe(conn,
3767 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0,
3768 __bt_hf_agent_filter_cb, NULL, NULL);
3770 interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
3771 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
3772 __bt_hf_agent_filter_cb, NULL, NULL);
3777 static void __bt_hf_agent_dbus_deinit(void)
3779 if (profile_gproxy) {
3780 g_object_unref(profile_gproxy);
3781 profile_gproxy = NULL;
3785 if (interface_added_sig_id > 0)
3786 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3787 interface_added_sig_id);
3789 if (interface_removed_sig_id > 0)
3790 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3791 interface_removed_sig_id);
3793 interface_added_sig_id = 0;
3794 interface_removed_sig_id = 0;
3796 g_object_unref(gdbus_conn);
3801 static int _hf_agent_answer_call(GDBusMethodInvocation *context)
3806 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3807 ERR("HF not Connected");
3808 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3810 bt_hf_info.context = context;
3812 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
3813 sizeof(BT_HF_ANSWER_CALL) - 1);
3815 return BT_HF_AGENT_ERROR_INTERNAL;
3818 return BT_HF_AGENT_ERROR_NONE;
3822 static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
3827 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3828 ERR("HF not Connected");
3829 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3832 bt_hf_info.context = context;
3834 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
3835 sizeof(BT_HF_END_CALL) - 1);
3837 return BT_HF_AGENT_ERROR_INTERNAL;
3840 return BT_HF_AGENT_ERROR_NONE;
3843 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
3846 int prev_cmd_len = 0;
3847 char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
3849 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3850 ERR("HF not Connected");
3851 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3854 bt_hf_info.context = context;
3856 if (strlen(no) > 0) {
3857 snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
3859 if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
3860 && bt_hf_info.ciev_call_setup_status == 0) {
3861 INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
3862 ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
3866 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3869 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3870 prev_cmd_len = snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
3872 if (prev_cmd_len < 0) {
3873 ERR("Encoding error occured in snprintf");
3874 return BT_HF_AGENT_ERROR_INTERNAL;
3878 return BT_HF_AGENT_ERROR_INTERNAL;
3880 return BT_HF_AGENT_ERROR_NONE;
3883 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3884 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
3886 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
3887 sizeof(BT_HF_REDIAL) - 1);
3889 return BT_HF_AGENT_ERROR_INTERNAL;
3891 return BT_HF_AGENT_ERROR_NONE;
3894 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
3899 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3900 ERR("HF not Connected");
3901 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3904 snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
3906 bt_hf_info.context = context;
3908 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3910 return BT_HF_AGENT_ERROR_INTERNAL;
3913 return BT_HF_AGENT_ERROR_NONE;
3916 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
3921 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3922 ERR("HF not Connected");
3923 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3926 if (gain > BT_HF_MAX_SPEAKER_GAIN)
3927 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3929 snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
3931 bt_hf_info.context = context;
3933 ret = __bt_hf_send_only(&bt_hf_info, buf,
3936 return BT_HF_AGENT_ERROR_INTERNAL;
3938 return BT_HF_AGENT_ERROR_NONE;
3942 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
3947 if (strlen(dtmf) <= 0)
3948 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3950 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3951 ERR("HF not Connected");
3952 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3955 snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
3957 bt_hf_info.context = context;
3959 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3961 return BT_HF_AGENT_ERROR_INTERNAL;
3964 return BT_HF_AGENT_ERROR_NONE;
3968 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
3972 if (strlen(cmd) <= 0)
3973 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3975 bt_hf_info.context = context;
3977 ret = __bt_hf_send_only(&bt_hf_info, cmd,
3980 return BT_HF_AGENT_ERROR_INTERNAL;
3982 return BT_HF_AGENT_ERROR_NONE;
3985 static gboolean bt_hf_agent_sco_connect(void)
3987 struct sockaddr_sco addr;
3988 bdaddr_t bd_addr = {{0},};
3991 GDBusConnection *conn;
3995 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3996 ERR("HF RFCOMM not Connected");
4000 if (bt_hf_info.cli_sco_fd > 0) {
4001 ERR("SCO Already connected..");
4006 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
4008 ERR("Can't create SCO socket");
4012 /* Bind to local address */
4013 memset(&addr, 0, sizeof(addr));
4014 addr.sco_family = AF_BLUETOOTH;
4015 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
4017 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
4018 ERR("Can't bind socket");
4022 /* Connect to remote device */
4023 memset(&addr, 0, sizeof(addr));
4024 addr.sco_family = AF_BLUETOOTH;
4025 __bt_convert_addr_string_to_type_rev(addr.sco_bdaddr.b, bt_hf_info.remote_addr);
4026 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
4027 ERR("Can't connect");
4031 DBG("SCO Connected");
4033 bt_hf_info.cli_sco_fd = sk;
4035 sco_io = g_io_channel_unix_new(sk);
4036 g_io_channel_set_close_on_unref(sco_io, TRUE);
4037 g_io_channel_set_encoding(sco_io, NULL, NULL);
4038 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
4039 g_io_channel_set_buffered(sco_io, FALSE);
4041 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
4042 __bt_hf_agent_sco_disconnect_cb, &bt_hf_info);
4044 DBG("Emit AudioConnected Signal - Outgoing SCo connection");
4045 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
4047 conn = __bt_hf_get_gdbus_connection();
4049 ERR("Unable to get connection");
4053 __bt_hf_agent_emit_signal(conn,
4054 BT_HF_AGENT_OBJECT_PATH,
4055 BT_HF_SERVICE_INTERFACE,
4056 "AudioConnected", NULL);
4067 static gboolean bt_hf_agent_sco_disconnect(void)
4070 GDBusConnection *conn;
4072 close(bt_hf_info.cli_sco_fd);
4073 bt_hf_info.cli_sco_fd = -1;
4075 DBG("Emit AudioDisconnected Signal");
4076 conn = __bt_hf_get_gdbus_connection();
4078 ERR("Unable to get connection");
4082 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
4084 __bt_hf_agent_emit_signal(conn,
4085 BT_HF_AGENT_OBJECT_PATH,
4086 BT_HF_SERVICE_INTERFACE,
4087 "AudioDisconnected", NULL);
4092 static GVariant *bt_hf_agent_request_call_list(void)
4094 GSList *call_list = NULL;
4098 call_list = __bt_hf_get_call_list(&bt_hf_info);
4100 INFO("call list is NULL");
4104 var_data = __bt_hf_agent_get_call_status_info(call_list);
4105 __bt_hf_free_call_list(call_list);
4111 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
4115 char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
4120 return BT_HF_AGENT_ERROR_INVALID_PARAM;
4122 if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
4123 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
4125 strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
4126 strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
4128 bt_hf_info.context = context;
4130 ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
4132 return BT_HF_AGENT_ERROR_INTERNAL;
4135 return BT_HF_AGENT_ERROR_NONE;
4138 static uint32_t __bt_hf_agent_get_hf_features(void)
4140 uint32_t hf_features;
4142 if (TIZEN_MODEL_NAME_DA)
4143 hf_features = BT_HF_FEATURE_CLI_PRESENTATION |
4144 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
4145 BT_HF_FEATURE_ESCO_S4;
4147 hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
4148 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
4149 BT_HF_FEATURE_CLI_PRESENTATION |
4150 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
4151 BT_HF_FEATURE_ENHANCED_CALL_STATUS |
4152 BT_HF_FEATURE_CODEC_NEGOTIATION;
4154 if (TIZEN_PROFILE_WEARABLE)
4155 hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
4158 if (TIZEN_MODEL_NAME_DA)
4159 hf_ver = HFP_VERSION_1_7;
4161 hf_ver = HFP_VERSION_1_6;
4169 struct sigaction sa;
4170 uint32_t hf_features;
4172 INFO_C("### Starting Bluetooth HF agent");
4174 #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36
4177 hf_features = __bt_hf_agent_get_hf_features();
4178 if (TIZEN_MODEL_NAME_DA)
4179 bt_hf_info.feature = (uint16_t) hf_features & 0xFFFF;
4181 bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
4183 bt_hf_info.audio_input = NULL;
4184 bt_hf_info.audio_output = NULL;
4186 memset(&sa, 0, sizeof(sa));
4187 sa.sa_flags = SA_NOCLDSTOP;
4188 sa.sa_handler = __bt_hf_agent_sigterm_handler;
4190 for (i = 0; i < BT_HF_SIG_NUM; i++)
4191 sigaction(bt_hf_sig_to_handle[i], &sa, &(bt_hf_sigoldact[i]));
4193 g_log_set_default_handler(__on_log_glib, NULL);
4195 gmain_loop = g_main_loop_new(NULL, FALSE);
4197 if (gmain_loop == NULL) {
4198 ERR("GMainLoop create failed\n");
4199 return EXIT_FAILURE;
4202 __bt_hf_agent_dbus_init();
4204 g_main_loop_run(gmain_loop);
4206 __bt_hf_agent_dbus_deinit();
4209 g_main_loop_unref(gmain_loop);
4211 INFO_C("### Terminating Bluetooth HF agent");