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 audio_out_drain((audio_out_h)bt_hf_info->audio_output);
2575 audio_out_unprepare((audio_out_h)bt_hf_info->audio_output);
2576 audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
2577 bt_hf_info->audio_output = NULL;
2583 static int __initialize_audio_in(bt_hf_agent_info_t *bt_hf_info)
2588 if (bt_hf_info->audio_input != NULL) {
2589 __release_audio_in(bt_hf_info);
2593 ret = audio_in_create(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
2594 AUDIO_SAMPLE_TYPE_S16_LE, (audio_in_h *)&bt_hf_info->audio_input);
2595 if (ret == AUDIO_IO_ERROR_NONE) {
2596 if (!(audio_in_prepare((audio_in_h)bt_hf_info->audio_input))) {
2597 DBG("voice capturing is ready!\n");
2598 bt_hf_info->is_audio_input_mute = FALSE;
2600 ERR("audio_in_prepare failed, err(0x%x)\n", ret);
2601 audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
2605 ERR("audio_in_create failed.\n");
2613 static int __initialize_audio_out(bt_hf_agent_info_t *bt_hf_info)
2618 if (bt_hf_info->audio_output != NULL) {
2619 __release_audio_out(bt_hf_info);
2623 ret = audio_out_create_new(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
2624 AUDIO_SAMPLE_TYPE_S16_LE, (audio_out_h *)&bt_hf_info->audio_output);
2625 if (ret == AUDIO_IO_ERROR_NONE) {
2626 INFO("after audio_out_create!!!");
2628 /* set sound stream info */
2629 if (g_stream_info_write_h) {
2630 if (!(ret = audio_out_set_sound_stream_info(bt_hf_info->audio_output, g_stream_info_write_h))) {
2631 INFO("after audio_out_set_sound_stream_info");
2633 ERR("fail to audio_out_set_sound_stream_info(), ret(0x%x)\n", ret);
2636 ERR("no stream info!!!!");
2640 if (!(ret = audio_out_prepare((audio_out_h)bt_hf_info->audio_output))) {
2641 DBG("voice playback is ready!\n");
2643 ERR("audio_out_prepare failed, err(0x%x)\n", ret);
2644 audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
2645 bt_hf_info->audio_output = NULL;
2648 ERR("audio_out_create failed. \n");
2655 static gboolean __bt_hf_agent_sco_event_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2657 bt_hf_agent_info_t *bt_hf_info = user_data;
2658 GDBusConnection *conn;
2659 int sco_skt = g_io_channel_unix_get_fd(chan);
2661 if (cond & G_IO_NVAL)
2664 if (cond & (G_IO_HUP | G_IO_ERR)) {
2665 g_io_channel_shutdown(chan, TRUE, NULL);
2666 close(bt_hf_info->cli_sco_fd);
2667 bt_hf_info->cli_sco_fd = -1;
2668 g_io_channel_unref(chan);
2669 DBG("Emit AudioDisconnected Signal");
2671 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2673 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
2674 bt_hf_info->is_first_audio_out = TRUE;
2676 __release_audio_out(bt_hf_info);
2677 __release_audio_in(bt_hf_info);
2679 conn = __bt_hf_get_gdbus_connection();
2681 ERR("Unable to get connection");
2684 __bt_hf_agent_emit_signal(conn,
2685 BT_HF_AGENT_OBJECT_PATH,
2686 BT_HF_SERVICE_INTERFACE,
2687 "AudioDisconnected", NULL);
2692 if (cond & G_IO_IN) {
2693 gchar buf_rx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
2696 read = recv(sco_skt, buf_rx, HFP_SCO_DATA_BUFFER_SIZE, MSG_DONTWAIT);
2698 if (bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING ||
2699 bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING ||
2700 bt_hf_info->call_active) {
2702 if (bt_hf_info->is_first_audio_out) {
2703 __initialize_audio_out(bt_hf_info);
2704 bt_hf_info->is_first_audio_out = FALSE;
2706 if (bt_hf_info->audio_output) {
2707 audio_out_write(bt_hf_info->audio_output, buf_rx, read);
2709 ERR("can't write audio");
2714 if (cond & G_IO_OUT) {
2715 gchar buf_tx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
2718 if (bt_hf_info->is_first_audio_in) {
2719 __initialize_audio_in(bt_hf_info);
2720 bt_hf_info->is_first_audio_in = FALSE;
2724 size = audio_in_read(bt_hf_info->audio_input, (void *)buf_tx, HFP_SCO_DATA_BUFFER_SIZE);
2726 if (bt_hf_info->call_active) {
2728 if (bt_hf_info->is_audio_input_mute) {
2729 memset(buf_tx, 0x0, size);
2732 if (send(sco_skt, buf_tx, size, MSG_DONTWAIT) < 0) {
2733 ERR("Write failed, error = %d[%s]", errno, strerror(errno));
2742 static gboolean __bt_hf_agent_sco_disconnect_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2744 bt_hf_agent_info_t *bt_hf_info = user_data;
2745 GDBusConnection *conn;
2748 if (cond & G_IO_NVAL)
2751 if (cond & (G_IO_HUP | G_IO_ERR)) {
2752 g_io_channel_shutdown(chan, TRUE, NULL);
2753 close(bt_hf_info->cli_sco_fd);
2754 bt_hf_info->cli_sco_fd = -1;
2755 g_io_channel_unref(chan);
2756 DBG("Emit AudioDisconnected Signal");
2758 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
2760 conn = __bt_hf_get_gdbus_connection();
2762 ERR("Unable to get connection");
2765 __bt_hf_agent_emit_signal(conn,
2766 BT_HF_AGENT_OBJECT_PATH,
2767 BT_HF_SERVICE_INTERFACE,
2768 "AudioDisconnected", NULL);
2776 static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
2778 bt_hf_agent_info_t *bt_hf_info = user_data;
2782 GDBusConnection *conn;
2784 INFO("Incoming SCO....");
2786 if (cond & G_IO_NVAL)
2789 sco_skt = g_io_channel_unix_get_fd(chan);
2791 if (cond & (G_IO_HUP | G_IO_ERR)) {
2796 cli_sco_sock = accept(sco_skt, NULL, NULL);
2797 if (cli_sco_sock < 0)
2800 bt_hf_info->cli_sco_fd = cli_sco_sock;
2802 sco_io = g_io_channel_unix_new(cli_sco_sock);
2803 g_io_channel_set_close_on_unref(sco_io, TRUE);
2804 g_io_channel_set_encoding(sco_io, NULL, NULL);
2805 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2806 g_io_channel_set_buffered(sco_io, FALSE);
2808 if (TIZEN_MODEL_NAME_DA) {
2809 bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
2810 bt_hf_info->is_first_audio_out = TRUE;
2811 bt_hf_info->is_first_audio_in = TRUE;
2812 //__initialize_audio_in(bt_hf_info);
2814 g_io_add_watch(sco_io, G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2815 __bt_hf_agent_sco_event_cb, bt_hf_info);
2817 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2818 __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
2820 if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
2821 ERR("HFP is not yet connected");
2823 /* S-Voice app requires the AudioConnected signal earlier */
2824 DBG("Emit AudioConnected Signal");
2826 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
2828 conn = __bt_hf_get_gdbus_connection();
2830 ERR("Unable to get connection");
2834 __bt_hf_agent_emit_signal(conn,
2835 BT_HF_AGENT_OBJECT_PATH,
2836 BT_HF_SERVICE_INTERFACE,
2837 "AudioConnected", NULL);
2839 /* In the case of incoming call, the call app is already launched,
2840 * hence AudioConnected signal is enough to update the call status.
2841 * In the case of outgoing call we need to lauch the callapp.
2844 __bt_hf_agent_launch_call_app();
2849 static void __bt_convert_addr_string_to_type_rev(unsigned char *addr,
2850 const char *address)
2855 ret_if(address == NULL);
2856 ret_if(addr == NULL);
2858 for (i = 0; i < BT_ADDRESS_LENGTH_MAX; i++) {
2859 addr[5 - i] = strtol(address, &ptr, 16);
2860 if (ptr[0] != '\0') {
2869 static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
2871 struct sockaddr_sco addr;
2873 bdaddr_t bd_addr = {{0},};
2877 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
2879 ERR("Can't create socket:\n");
2883 /* Bind to local address */
2884 memset(&addr, 0, sizeof(addr));
2885 addr.sco_family = AF_BLUETOOTH;
2887 DBG("Bind to address %s", bt_hf_info->remote_addr);
2889 __bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
2890 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2892 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2893 ERR("Can't bind socket:\n");
2897 if (listen(sco_skt, 1)) {
2898 ERR("Can not listen on the socket:\n");
2902 sco_io = g_io_channel_unix_new(sco_skt);
2903 g_io_channel_set_close_on_unref(sco_io, TRUE);
2904 g_io_channel_set_encoding(sco_io, NULL, NULL);
2905 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2906 g_io_channel_set_buffered(sco_io, FALSE);
2908 bt_hf_info->sco_fd = sco_skt;
2909 bt_hf_info->sco_io_chan = sco_io;
2911 bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
2912 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
2914 g_io_channel_unref(sco_io);
2923 static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
2925 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2928 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
2929 sizeof(BT_HF_INDICATORS_SUPP) - 1);
2930 if (!ret || !strstr(buf, "+CIND:"))
2933 bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
2938 static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
2943 if (bt_hf_info == NULL || cmd == NULL) {
2944 ERR("Invalid parameter");
2948 ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
2950 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
2951 ret = g_strlcat(cmd, "0,", cmd_size);
2952 if (ret >= cmd_size) {
2953 ERR("Too many indices");
2959 cmd[ret - 1] = '\0';
2960 DBG("BIA Str : %s", cmd);
2962 ret = g_strlcat(cmd, "\r", cmd_size);
2963 if (ret >= cmd_size) {
2964 ERR("Too many indices");
2971 static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
2973 gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
2979 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
2980 sizeof(BT_HF_INDICATORS_VAL) - 1);
2981 if (!ret || !strstr(buf, "+CIND:"))
2984 /* if buf has other command prefix, skip it */
2985 str = strstr(buf, "+CIND");
2989 bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
2991 /* Parse the updated value */
2992 for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
2993 struct indicator *ind = l->data;
2995 DBG("Index is NULL");
2999 if (0 == g_strcmp0(ind->descr, "\"call\"")) {
3000 DBG("CIND Match found index = %d, %s, value = %d",
3001 index, ind->descr, ind->value);
3002 bt_hf_info->ciev_call_status = ind->value;
3003 if (ind->value > 0) {
3004 bt_hf_info->is_dialing = FALSE;
3005 bt_hf_info->call_active = TRUE;
3007 } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
3008 DBG("CIND Match found index = %d, %s, value = %d",
3009 index, ind->descr, ind->value);
3010 bt_hf_info->ciev_call_setup_status = ind->value;
3011 if (!bt_hf_info->is_dialing && ind->value > 0)
3012 bt_hf_info->is_dialing = TRUE;
3019 static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
3021 gchar buf[BT_HF_DATA_BUF_SIZE];
3022 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
3027 if (TIZEN_MODEL_NAME_DA)
3028 feature = BT_HF_FEATURE_CLI_PRESENTATION |
3029 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3030 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
3032 feature = BT_HF_FEATURE_EC_ANDOR_NR |
3033 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
3034 BT_HF_FEATURE_CLI_PRESENTATION |
3035 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
3036 BT_HF_FEATURE_ENHANCED_CALL_STATUS;
3038 if (TIZEN_PROFILE_WEARABLE)
3039 feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
3042 snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
3043 ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
3048 buf_ptr = strstr(buf, "\r\n+BRSF:");
3049 if (buf_ptr == NULL)
3052 if (!ret || sscanf(buf_ptr, "\r\n+BRSF:%5d", &bt_hf_info->ag_features) != 1)
3054 INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
3056 if (TIZEN_PROFILE_WEARABLE) {
3057 if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
3058 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
3059 if (ret != BT_HF_AGENT_ERROR_NONE)
3060 ERR("Unable to set the default WBC codec");
3062 ret = __bt_hf_send_available_codec(bt_hf_info, 0);
3067 /* Default codec is NB */
3068 ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
3069 if (ret != BT_HF_AGENT_ERROR_NONE)
3070 ERR("Unable to set the default NBC codec");
3073 ret = __bt_get_supported_indicators(bt_hf_info);
3078 ret = __bt_get_current_indicators(bt_hf_info);
3082 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
3083 sizeof(BT_HF_INDICATORS_ENABLE) - 1);
3084 if (!ret || !strstr(buf, "OK"))
3087 if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
3088 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
3089 buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
3090 if (!ret || !strstr(buf, "+CHLD:")) {
3091 ERR("Unable to get the CHLD Supported info");
3094 bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
3097 bt_hf_info->hold_multiparty_features = 0;
3099 if (bt_hf_info->ag_features & BT_AG_FEATURE_INBAND_RINGTONE)
3100 bt_hf_info->inband_ringtone_support = TRUE;
3102 bt_hf_info->inband_ringtone_support = FALSE;
3104 INFO("Service layer connection successfully established...!");
3106 bt_hf_info->slc = TRUE;
3109 memset(global_buff, 0, sizeof(global_buff));
3113 static void __bt_establish_initialization(bt_hf_agent_info_t *bt_hf_info)
3115 gchar buf[BT_HF_DATA_BUF_SIZE];
3116 gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
3119 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
3120 sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
3121 __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
3122 sizeof(BT_HF_CARRIER_FORMAT) - 1);
3123 __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
3124 sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
3126 if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
3127 __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
3128 sizeof(BT_HF_NREC) - 1);
3130 if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
3131 __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
3132 buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
3134 if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
3135 __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
3137 ERR("__bt_get_bia_cmd is failed");
3139 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
3140 sizeof(BT_HF_XSAT) - 1);
3142 DBG("sent BT_HF_XSAT");
3144 ERR("BT_HF_XSAT sending failed");
3146 if (TIZEN_PROFILE_WEARABLE) {
3147 /* send Bluetooth Samsung Support Feature cmd */
3148 ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
3149 sizeof(BT_HF_BSSF) - 1);
3151 /* If we got a 'OK' reply, peer AG is samsung device.
3152 * Otherwise, non-samsung device */
3153 if (ret && strstr(buf, "OK"))
3154 bt_hf_info->is_companion_dev = TRUE;
3156 bt_hf_info->is_companion_dev = FALSE;
3159 INFO("SLC completed with [%s] device",
3160 bt_hf_info->is_companion_dev ? "SS Companion" : "Other");
3162 ERR("BT_HF_BSSF sending failed");
3166 static void __bt_hf_agent_sigterm_handler(int signo)
3168 GDBusConnection *conn;
3171 ERR_C("***** Signal handler came with signal %d *****", signo);
3173 conn = __bt_hf_get_gdbus_connection();
3175 ERR("Unable to get G-DBus connection");
3178 INFO("Getting gdbus connection done");
3180 __bt_hf_agent_emit_signal(conn,
3181 BT_HF_AGENT_OBJECT_PATH,
3182 BT_HF_SERVICE_INTERFACE,
3184 INFO("CallEnded Signal done");
3186 g_dbus_connection_flush(conn, NULL, NULL, NULL);
3187 INFO("Flush g_dbus_connection");
3191 g_main_loop_quit(gmain_loop);
3195 INFO_C("Terminating HF agent");
3199 if (signo == SIGTERM)
3202 for (i = 0; i < BT_HF_SIG_NUM; i++)
3203 sigaction(bt_hf_sig_to_handle[i], &(bt_hf_sigoldact[i]), NULL);
3208 static void __bt_convert_addr_type_to_rev_string(char *address,
3209 unsigned char *addr)
3211 ret_if(address == NULL);
3212 ret_if(addr == NULL);
3214 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
3215 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
3216 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
3220 static gboolean __bt_hf_agent_release_after(gpointer user_data)
3222 if (__bt_hf_agent_release() == FALSE)
3223 ERR("Unable to release hf connection");
3228 static gboolean __bt_agent_request_service_level_conn(gpointer data)
3231 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
3232 GDBusConnection *conn;
3235 memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
3237 __bt_hf_agent_sco_accept(&bt_hf_info);
3239 if (!__bt_establish_service_level_conn(&bt_hf_info)) {
3240 ERR("Service Level Connection is fail");
3242 conn = __bt_hf_get_gdbus_connection();
3244 remote_addr = bt_hf_info.remote_addr;
3245 __bt_hf_agent_emit_signal(conn,
3246 BT_HF_AGENT_OBJECT_PATH,
3247 BT_HF_SERVICE_INTERFACE,
3249 g_variant_new("(s)", remote_addr));
3251 bt_hf_info.state = BT_HF_STATE_CONNECTED;
3253 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3254 DBG("BT device state is : 0x%X", bt_device_state);
3255 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3256 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3257 ERR("vconf_set_int failed");
3259 ERR("vconf_get_int failed");
3262 g_idle_add(__bt_hf_agent_release_after, NULL);
3267 bt_hf_info.state = BT_HF_STATE_CONNECTED;
3269 __bt_hf_agent_start_watch(&bt_hf_info);
3271 remote_addr = bt_hf_info.remote_addr;
3273 INFO_SECURE("Address is : %s", remote_addr);
3274 INFO_C("### Connected [HF role]");
3276 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3277 DBG("BT device state is : 0x%X", bt_device_state);
3278 bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3280 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3281 ERR("vconf_set_int failed");
3283 ERR("vconf_get_int failed");
3286 conn = __bt_hf_get_gdbus_connection();
3288 ERR("Unable to get connection");
3292 __bt_hf_agent_emit_signal(conn,
3293 BT_HF_AGENT_OBJECT_PATH,
3294 BT_HF_SERVICE_INTERFACE,
3296 g_variant_new("(s)", remote_addr));
3298 /* Establish the initialization */
3299 __bt_establish_initialization(&bt_hf_info);
3306 static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
3310 struct sockaddr_remote address;
3311 socklen_t address_len;
3312 bt_hf_info.path = g_strdup(obj_path);
3314 INFO_C("**** New HFP connection ****");
3316 is_hf_connected = TRUE;
3318 address_len = sizeof(address);
3319 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
3320 ERR("BD_ADDR is NULL");
3322 DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
3324 bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
3325 flags = g_io_channel_get_flags(bt_hf_info.io_chan);
3327 flags &= ~G_IO_FLAG_NONBLOCK;
3328 flags &= G_IO_FLAG_MASK;
3329 g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
3330 g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
3331 g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
3333 bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
3334 __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
3335 address.remote_bdaddr.b);
3337 g_idle_add(__bt_agent_request_service_level_conn, NULL);
3342 static void __bt_hf_agent_indicator_free(gpointer mem)
3347 static gboolean __bt_hf_agent_release(void)
3349 int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
3350 GDBusConnection *conn;
3353 g_source_remove(clcc_timer);
3357 if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
3358 ERR("hf is already disconnected");
3362 if (bt_hf_info.indies) {
3363 g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
3364 bt_hf_info.indies = NULL;
3367 if (bt_hf_info.io_chan) {
3368 g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
3369 g_io_channel_unref(bt_hf_info.io_chan);
3370 bt_hf_info.io_chan = NULL;
3373 if (bt_hf_info.sco_watch_id > 0) {
3374 g_source_remove(bt_hf_info.sco_watch_id);
3375 bt_hf_info.sco_watch_id = 0;
3378 bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
3380 __bt_hf_agent_release_queue();
3382 if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
3383 DBG("BT device state is : 0x%X", bt_device_state);
3384 bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
3386 if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0)
3387 ERR("vconf_set_int failed");
3389 ERR("vconf_get_int failed");
3392 __bt_hf_agent_stop_watch(&bt_hf_info);
3393 conn = __bt_hf_get_gdbus_connection();
3395 ERR("Unable to get connection");
3399 __bt_hf_agent_emit_signal(conn,
3400 BT_HF_AGENT_OBJECT_PATH,
3401 BT_HF_SERVICE_INTERFACE,
3403 g_variant_new("(s)", bt_hf_info.remote_addr));
3405 g_free(bt_hf_info.path);
3406 bt_hf_info.path = NULL;
3408 g_free(bt_hf_info.remote_addr);
3409 bt_hf_info.remote_addr = NULL;
3411 is_hf_connected = FALSE;
3416 static gboolean __bt_hf_agent_connection_release(void)
3418 return __bt_hf_agent_release();
3421 static int __bt_hf_register_profile(const char *uuid, uint16_t version,
3422 const char *name, const char *object, uint16_t features)
3427 GError *error = NULL;
3428 GVariantBuilder *builder;
3431 proxy = __bt_hf_gdbus_get_profile_proxy();
3434 return BT_HF_AGENT_ERROR_INTERNAL;
3436 path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3438 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3440 g_variant_builder_add(builder, "{sv}",
3441 "Name", g_variant_new("s",
3443 g_variant_builder_add(builder, "{sv}",
3444 "Version", g_variant_new("q", version));
3446 g_variant_builder_add(builder, "{sv}",
3447 "features", g_variant_new("q", features));
3449 if (TIZEN_MODEL_NAME_DA)
3450 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3451 g_variant_new("(osa{sv})", object,
3453 G_DBUS_CALL_FLAGS_NONE, -1,
3456 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3457 g_variant_new("(osa{sv})", path,
3458 HFP_HF_UUID, builder),
3459 G_DBUS_CALL_FLAGS_NONE, -1,
3462 g_variant_builder_unref(builder);
3465 /* dBUS-RPC is failed */
3466 ERR("dBUS-RPC is failed");
3467 if (error != NULL) {
3468 /* dBUS gives error cause */
3469 ERR("D-Bus API failure: errCode[%x], message[%s]",
3470 error->code, error->message);
3471 g_clear_error(&error);
3474 return BT_HF_AGENT_ERROR_INTERNAL;
3476 g_variant_unref(ret);
3480 return BT_HF_AGENT_ERROR_NONE;
3483 static void __bt_hf_agent_register(void)
3488 uint16_t version = hf_ver;
3489 uint16_t features = bt_hf_info.feature;
3491 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3492 name = g_strdup("Hands-Free");
3494 ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
3497 ERR("Error in hf register");
3499 if (TIZEN_MODEL_NAME_DA) {
3500 ret = __bt_hf_register_profile(PBAP_PCE_UUID, 0x0101,
3501 "Phone Book Access Client",
3502 BT_PBAP_CLIENT_OBJECT_PATH, 0);
3504 ERR("Error in pce register");
3514 static void __bt_hf_agent_unregister(void)
3518 gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
3521 __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
3522 g_variant_new("(o)", path),
3523 BLUEZ_HF_INTERFACE_NAME,
3535 static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
3536 const gchar *sender_name,
3537 const gchar *object_path,
3538 const gchar *interface_name,
3539 const gchar *signal_name,
3540 GVariant *parameters,
3546 GVariant *optional_param;
3548 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3550 g_variant_get(parameters, "(&o@a{sa{sv}})",
3551 &path, &optional_param);
3553 ERR("Invalid adapter path");
3557 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3558 g_obj_path = g_strdup(path);
3559 INFO("Adapter Path = [%s]", path);
3560 __bt_hf_agent_register();
3562 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
3563 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
3565 __bt_hf_agent_unregister();
3570 static int __bt_hf_agent_get_adapter_path(GDBusConnection *conn, char *path)
3573 GDBusProxy *manager_proxy = NULL;
3574 GVariant *result = NULL;
3575 char *adapter_path = NULL;
3578 return BT_HF_AGENT_ERROR_INTERNAL;
3580 manager_proxy = g_dbus_proxy_new_sync(conn,
3581 G_DBUS_PROXY_FLAGS_NONE, NULL,
3584 BT_MANAGER_INTERFACE,
3587 if (!manager_proxy) {
3588 ERR("Unable to create proxy: %s", err->message);
3592 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
3593 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
3596 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
3598 ERR("Fail to get DefaultAdapter");
3603 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
3604 ERR("Incorrect result\n");
3608 g_variant_get(result, "(&o)", &adapter_path);
3610 if (adapter_path == NULL ||
3611 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
3612 ERR("Adapter path is inproper\n");
3617 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
3619 if (g_obj_path == NULL) {
3620 g_obj_path = g_strdup(adapter_path);
3621 INFO("Update g_obj_path [%s]", adapter_path);
3624 g_variant_unref(result);
3625 g_object_unref(manager_proxy);
3630 g_clear_error(&err);
3633 g_variant_unref(result);
3636 g_object_unref(manager_proxy);
3638 return BT_HF_AGENT_ERROR_INTERNAL;
3642 static void __bt_hf_agent_dbus_init(void)
3644 GDBusConnection *conn;
3648 conn = __bt_hf_get_gdbus_connection();
3650 ERR("Error in creating the gdbus connection\n");
3653 if (!__bt_hf_register_profile_methods()) {
3654 ERR("Error in register_profile_methods\n");
3658 if (!__bt_hf_agent_get_adapter_path(gdbus_conn , NULL)) {
3659 __bt_hf_agent_register();
3662 interface_added_sig_id = g_dbus_connection_signal_subscribe(conn,
3663 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0,
3664 __bt_hf_agent_filter_cb, NULL, NULL);
3666 interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
3667 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
3668 __bt_hf_agent_filter_cb, NULL, NULL);
3673 static void __bt_hf_agent_dbus_deinit(void)
3675 if (profile_gproxy) {
3676 g_object_unref(profile_gproxy);
3677 profile_gproxy = NULL;
3681 if (interface_added_sig_id > 0)
3682 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3683 interface_added_sig_id);
3685 if (interface_removed_sig_id > 0)
3686 g_dbus_connection_signal_unsubscribe(gdbus_conn,
3687 interface_removed_sig_id);
3689 interface_added_sig_id = 0;
3690 interface_removed_sig_id = 0;
3692 g_object_unref(gdbus_conn);
3697 static int _hf_agent_answer_call(GDBusMethodInvocation *context)
3702 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3703 ERR("HF not Connected");
3704 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3706 bt_hf_info.context = context;
3708 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
3709 sizeof(BT_HF_ANSWER_CALL) - 1);
3711 return BT_HF_AGENT_ERROR_INTERNAL;
3714 return BT_HF_AGENT_ERROR_NONE;
3718 static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
3723 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3724 ERR("HF not Connected");
3725 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3728 bt_hf_info.context = context;
3730 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
3731 sizeof(BT_HF_END_CALL) - 1);
3733 return BT_HF_AGENT_ERROR_INTERNAL;
3736 return BT_HF_AGENT_ERROR_NONE;
3739 static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
3742 int prev_cmd_len = 0;
3743 char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
3745 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3746 ERR("HF not Connected");
3747 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3750 bt_hf_info.context = context;
3752 if (strlen(no) > 0) {
3753 snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
3755 if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
3756 && bt_hf_info.ciev_call_setup_status == 0) {
3757 INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
3758 ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
3762 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3765 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3766 prev_cmd_len = snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
3768 if (prev_cmd_len < 0) {
3769 ERR("Encoding error occured in snprintf");
3770 return BT_HF_AGENT_ERROR_INTERNAL;
3774 return BT_HF_AGENT_ERROR_INTERNAL;
3776 return BT_HF_AGENT_ERROR_NONE;
3779 /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
3780 snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
3782 ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
3783 sizeof(BT_HF_REDIAL) - 1);
3785 return BT_HF_AGENT_ERROR_INTERNAL;
3787 return BT_HF_AGENT_ERROR_NONE;
3790 static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
3795 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3796 ERR("HF not Connected");
3797 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3800 snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
3802 bt_hf_info.context = context;
3804 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3806 return BT_HF_AGENT_ERROR_INTERNAL;
3809 return BT_HF_AGENT_ERROR_NONE;
3812 static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
3817 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3818 ERR("HF not Connected");
3819 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3822 if (gain > BT_HF_MAX_SPEAKER_GAIN)
3823 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3825 snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
3827 bt_hf_info.context = context;
3829 ret = __bt_hf_send_only(&bt_hf_info, buf,
3832 return BT_HF_AGENT_ERROR_INTERNAL;
3834 return BT_HF_AGENT_ERROR_NONE;
3838 static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
3843 if (strlen(dtmf) <= 0)
3844 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3846 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3847 ERR("HF not Connected");
3848 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
3851 snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
3853 bt_hf_info.context = context;
3855 ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
3857 return BT_HF_AGENT_ERROR_INTERNAL;
3860 return BT_HF_AGENT_ERROR_NONE;
3864 static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
3868 if (strlen(cmd) <= 0)
3869 return BT_HF_AGENT_ERROR_INVALID_PARAM;
3871 bt_hf_info.context = context;
3873 ret = __bt_hf_send_only(&bt_hf_info, cmd,
3876 return BT_HF_AGENT_ERROR_INTERNAL;
3878 return BT_HF_AGENT_ERROR_NONE;
3881 static gboolean bt_hf_agent_sco_connect(void)
3883 struct sockaddr_sco addr;
3884 bdaddr_t bd_addr = {{0},};
3887 GDBusConnection *conn;
3891 if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
3892 ERR("HF RFCOMM not Connected");
3896 if (bt_hf_info.cli_sco_fd > 0) {
3897 ERR("SCO Already connected..");
3902 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
3904 ERR("Can't create SCO socket");
3908 /* Bind to local address */
3909 memset(&addr, 0, sizeof(addr));
3910 addr.sco_family = AF_BLUETOOTH;
3911 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
3913 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3914 ERR("Can't bind socket");
3918 /* Connect to remote device */
3919 memset(&addr, 0, sizeof(addr));
3920 addr.sco_family = AF_BLUETOOTH;
3921 __bt_convert_addr_string_to_type_rev(addr.sco_bdaddr.b, bt_hf_info.remote_addr);
3922 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3923 ERR("Can't connect");
3927 DBG("SCO Connected");
3929 bt_hf_info.cli_sco_fd = sk;
3931 sco_io = g_io_channel_unix_new(sk);
3932 g_io_channel_set_close_on_unref(sco_io, TRUE);
3933 g_io_channel_set_encoding(sco_io, NULL, NULL);
3934 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
3935 g_io_channel_set_buffered(sco_io, FALSE);
3937 g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
3938 __bt_hf_agent_sco_disconnect_cb, &bt_hf_info);
3940 DBG("Emit AudioConnected Signal - Outgoing SCo connection");
3941 sco_audio_connected = BT_HF_AUDIO_CONNECTED;
3943 conn = __bt_hf_get_gdbus_connection();
3945 ERR("Unable to get connection");
3949 __bt_hf_agent_emit_signal(conn,
3950 BT_HF_AGENT_OBJECT_PATH,
3951 BT_HF_SERVICE_INTERFACE,
3952 "AudioConnected", NULL);
3963 static gboolean bt_hf_agent_sco_disconnect(void)
3966 GDBusConnection *conn;
3968 close(bt_hf_info.cli_sco_fd);
3969 bt_hf_info.cli_sco_fd = -1;
3971 DBG("Emit AudioDisconnected Signal");
3972 conn = __bt_hf_get_gdbus_connection();
3974 ERR("Unable to get connection");
3978 sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
3980 __bt_hf_agent_emit_signal(conn,
3981 BT_HF_AGENT_OBJECT_PATH,
3982 BT_HF_SERVICE_INTERFACE,
3983 "AudioDisconnected", NULL);
3988 static GVariant *bt_hf_agent_request_call_list(void)
3990 GSList *call_list = NULL;
3994 call_list = __bt_hf_get_call_list(&bt_hf_info);
3996 INFO("call list is NULL");
4000 var_data = __bt_hf_agent_get_call_status_info(call_list);
4001 __bt_hf_free_call_list(call_list);
4007 static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
4011 char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
4016 return BT_HF_AGENT_ERROR_INVALID_PARAM;
4018 if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
4019 return BT_HF_AGENT_ERROR_NOT_CONNECTED;
4021 strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
4022 strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
4024 bt_hf_info.context = context;
4026 ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
4028 return BT_HF_AGENT_ERROR_INTERNAL;
4031 return BT_HF_AGENT_ERROR_NONE;
4034 static uint32_t __bt_hf_agent_get_hf_features(void)
4036 uint32_t hf_features;
4038 if (TIZEN_MODEL_NAME_DA)
4039 hf_features = BT_HF_FEATURE_CLI_PRESENTATION |
4040 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL;
4042 hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
4043 BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
4044 BT_HF_FEATURE_CLI_PRESENTATION |
4045 BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
4046 BT_HF_FEATURE_ENHANCED_CALL_STATUS |
4047 BT_HF_FEATURE_CODEC_NEGOTIATION;
4049 if (TIZEN_PROFILE_WEARABLE)
4050 hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
4053 hf_ver = HFP_VERSION_1_6;
4061 struct sigaction sa;
4062 uint32_t hf_features;
4064 INFO_C("### Starting Bluetooth HF agent");
4066 #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36
4069 hf_features = __bt_hf_agent_get_hf_features();
4070 bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
4072 bt_hf_info.audio_input = NULL;
4073 bt_hf_info.audio_output = NULL;
4075 memset(&sa, 0, sizeof(sa));
4076 sa.sa_flags = SA_NOCLDSTOP;
4077 sa.sa_handler = __bt_hf_agent_sigterm_handler;
4079 for (i = 0; i < BT_HF_SIG_NUM; i++)
4080 sigaction(bt_hf_sig_to_handle[i], &sa, &(bt_hf_sigoldact[i]));
4082 g_log_set_default_handler(__on_log_glib, NULL);
4084 gmain_loop = g_main_loop_new(NULL, FALSE);
4086 if (gmain_loop == NULL) {
4087 ERR("GMainLoop create failed\n");
4088 return EXIT_FAILURE;
4091 __bt_hf_agent_dbus_init();
4093 g_main_loop_run(gmain_loop);
4095 __bt_hf_agent_dbus_deinit();
4098 g_main_loop_unref(gmain_loop);
4100 INFO_C("### Terminating Bluetooth HF agent");