4 * Copyright (c) 2014 - 2015 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>
9 * Rakesh MK <rakesh.mk@samsung.com>
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
28 #include <gio/gunixfdlist.h>
29 #include <bundle_internal.h>
30 #include "bluetooth-ag-agent.h"
31 #include "bluetooth-ag-handler.h"
33 #include <TapiUtility.h>
35 #include <ITapiModem.h>
36 #include <TelNetwork.h>
39 #include <system_info.h>
44 static GMainLoop *gmain_loop = NULL;
45 static GDBusProxy *service_gproxy;
46 static int owner_sig_id = -1;
47 static int name_owner_sig_id = -1;
48 GDBusConnection *ag_dbus_conn = NULL;
49 gchar *remote_dev_path = NULL;
53 static TapiHandle *tapi_handle;
54 extern wbs_options wbs_opts;
55 GSList *active_devices = NULL;
56 static gchar *local_addr = NULL;
57 static GDBusProxy *app_gproxy;
58 static gboolean call_launch_requested = FALSE;
59 static gchar* sco_owner = NULL;
60 static guint sco_open_timer_id = 0;
61 static gboolean sco_open_request = FALSE;
62 static guint hf_bluez_id;
63 static guint hs_bluez_id;
65 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
66 static int media_sig_id = -1;
67 static int media_state_sig_id = -1;
68 static bt_ag_media_transport_state_t transport_state;
71 #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
72 #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
73 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
74 #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
76 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
78 #ifdef TIZEN_FEATURE_BT_LUNAR_DEVICE
79 #define VCONF_KEY_BT_LUNAR_ENABLED "db/wms/bt_loop_device_hfp_connected"
82 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
83 #define CALL_APP_ID "org.tizen.call-ui"
86 #if defined(TIZEN_SUPPORT_DUAL_HF)
87 #define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac"
88 #define MAX_CONNECTED_DEVICES 2
90 #define MAX_CONNECTED_DEVICES 1
93 #define BT_AG_SIG_NUM 3
94 static struct sigaction bt_ag_sigoldact[BT_AG_SIG_NUM];
95 static int bt_ag_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
97 /*Below Inrospection data is exposed to bluez from agent*/
98 static const gchar ag_agent_bluez_introspection_xml[] =
100 " <interface name='org.bluez.Profile1'>"
101 " <method name='NewConnection'>"
102 " <arg type='o' name='device' direction='in'/>"
103 " <arg type='h' name='fd' direction='in'/>"
104 " <arg type='a{sv}' name='options' direction='in'/>"
106 " <method name='RequestDisconnection'>"
107 " <arg type='o' name='device' direction='in'/>"
112 /*Below Introspection data is exposed to application from agent*/
113 static const gchar ag_agent_app_introspection_xml[] =
115 " <interface name='Org.Hfp.App.Interface'>"
116 " <method name='RegisterApplication'>"
117 " <arg type='s' name='path' direction='in'/>"
118 " <arg type='s' name='address' direction='in'/>"
120 " <method name='UnregisterApplication'>"
121 " <arg type='s' name='path' direction='in'/>"
123 " <method name='IncomingCall'>"
124 " <arg type='s' name='path' direction='in'/>"
125 " <arg type='s' name='number' direction='in'/>"
126 " <arg type='i' name='id' direction='in'/>"
128 " <method name='OutgoingCall'>"
129 " <arg type='s' name='path' direction='in'/>"
130 " <arg type='s' name='number' direction='in'/>"
131 " <arg type='i' name='id' direction='in'/>"
133 " <method name='ChangeCallStatus'>"
134 " <arg type='s' name='path' direction='in'/>"
135 " <arg type='s' name='number' direction='in'/>"
136 " <arg type='i' name='status' direction='in'/>"
137 " <arg type='i' name='id' direction='in'/>"
139 " <method name='GetProperties'>"
140 " <arg type='a{sv}' name='properties' direction='out'/>"
142 " <method name='Disconnect'>"
144 " <method name='IsConnected'>"
145 " <arg type='b' name='connected' direction='out'/>"
147 " <method name='IndicateCall'>"
149 " <method name='CancelCall'>"
151 " <method name='Play'>"
153 " <method name='Stop'>"
155 " <method name='IsPlaying'>"
156 " <arg type='b' name='playing' direction='out'/>"
158 " <method name='GetSpeakerGain'>"
159 " <arg type='q' name='gain' direction='out'/>"
161 " <method name='GetMicrophoneGain'>"
162 " <arg type='q' name='gain' direction='out'/>"
164 " <method name='SetSpeakerGain'>"
165 " <arg type='q' name='gain' direction='in'/>"
167 " <method name='SetMicrophoneGain'>"
168 " <arg type='q' name='gain' direction='in'/>"
170 " <method name='SetVoiceDial'>"
171 " <arg type='b' name='enable' direction='in'/>"
173 " <method name='CheckPrivilege'>"
175 " <method name='SwapHeadset'>"
176 " <arg type='s' name='remote_addr' direction='in'/>"
183 int (*callback)(bt_ag_info_t *hs, const char *buf);
186 struct sco_socket_addr {
187 sa_family_t sco_family;
196 bt_ag_info_t *bt_ag_info;
200 bt_ag_status_t ag = {
201 .telephony_ready = FALSE,
205 .rh = BT_RSP_HOLD_NOT_SUPPORTED,
211 static void __bt_ag_agent_sigterm_handler(int signo);
212 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
213 const gchar *object_path);
214 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs);
215 static gboolean __bt_ag_event_handler(GIOChannel *channel, GIOCondition cond,
217 static int __bt_ag_sco_connect(bt_ag_info_t *hs);
218 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state);
219 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data);
220 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle);
221 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
222 const gchar *sender_name,
223 const gchar *object_path,
224 const gchar *interface_name,
225 const gchar *signal_name,
226 GVariant *parameters,
229 static void __bt_convert_addr_type_to_rev_string(char *address,
232 ret_if(address == NULL);
233 ret_if(addr == NULL);
235 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
236 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
237 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
240 static GDBusProxy *__bt_ag_gdbus_init_service_proxy(const gchar *service,
241 const gchar *path, const gchar *interface)
248 if (ag_dbus_conn == NULL)
249 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
253 ERR("Unable to connect to gdbus: %s", err->message);
259 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
260 G_DBUS_PROXY_FLAGS_NONE, NULL,
262 interface, NULL, &err);
266 ERR("Unable to create proxy: %s", err->message);
276 static GDBusProxy *__bt_ag_gdbus_get_app_proxy(const gchar *service,
277 const gchar *path, const gchar *interface)
279 return (app_gproxy) ? app_gproxy :
280 __bt_ag_gdbus_init_service_proxy(service,
284 static int __bt_ag_agent_gdbus_method_send(const char *service,
285 const gchar *path, const char *interface,
286 const char *method, gboolean response,
287 GVariant *parameters)
293 GError *error = NULL;
295 proxy = __bt_ag_gdbus_get_app_proxy(service, path, interface);
297 return BT_HFP_AGENT_ERROR_INTERNAL;
300 ret = g_dbus_proxy_call_sync(proxy,
302 G_DBUS_CALL_FLAGS_NONE, -1,
305 /* dBUS-RPC is failed */
306 ERR("dBUS-RPC is failed");
308 /* dBUS gives error cause */
309 ERR("D-Bus API failure: errCode[%x], message[%s]",
310 error->code, error->message);
312 g_clear_error(&error);
314 return BT_HFP_AGENT_ERROR_INTERNAL;
317 g_variant_unref(ret);
319 g_dbus_proxy_call(proxy,
321 G_DBUS_CALL_FLAGS_NONE, 2000,
324 return BT_HFP_AGENT_ERROR_NONE;
327 gboolean _bt_ag_agent_emit_signal(
328 GDBusConnection *connection,
330 const char *interface,
336 GError *error = NULL;
338 ret = g_dbus_connection_emit_signal(connection,
339 NULL, path, interface,
344 /* dBUS gives error cause */
345 ERR("D-Bus API failure: errCode[%x], message[%s]",
346 error->code, error->message);
347 g_clear_error(&error);
350 INFO_C("Emit Signal done = [%s]", name);
356 gboolean _bt_ag_agent_emit_property_changed(
357 GDBusConnection *connection,
359 const char *interface,
368 var_data = g_variant_new("(sv)", name, property);
370 ret = _bt_ag_agent_emit_signal(connection,
372 "PropertyChanged", var_data);
377 static void __bt_ag_agent_start_watch(bt_ag_info_t *bt_ag_info)
379 bt_ag_info->watch_id = g_io_add_watch(bt_ag_info->io_chan,
380 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
381 (GIOFunc) __bt_ag_event_handler, bt_ag_info);
384 static void __bt_ag_agent_remove_watch(guint *watch_id)
386 DBG("Remove IO watch ID %d", *watch_id);
388 g_source_remove(*watch_id);
393 #if defined(TIZEN_SUPPORT_DUAL_HF)
394 gboolean __bt_ag_agent_is_companion_device(const char *addr)
396 #if defined(TIZEN_PROFILE_WEARABLE)
397 char *host_device_address = NULL;
398 host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR);
400 if (!host_device_address) {
401 INFO("Failed to get a companion device address");
405 if (g_strcmp0(host_device_address, addr) == 0) {
406 INFO("addr[%s] is companion device", addr);
412 /* TODO : Need to add companion device check condition for Phone models */
417 void __bt_convert_device_path_to_address(const gchar *device_path,
418 char *device_address)
420 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
423 ret_if(device_path == NULL);
424 ret_if(device_address == NULL);
426 dev_addr = strstr(device_path, "dev_");
427 if (dev_addr != NULL) {
430 g_strlcpy(address, dev_addr, sizeof(address));
432 while ((pos = strchr(address, '_')) != NULL)
435 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
439 static gboolean __bt_ag_agent_is_companion_device_connected(void)
443 for (l = active_devices ; l; l = l->next) {
444 bt_ag_info_t *data = l->data;
446 if (data->is_companion_device) {
447 DBG("Companion device found");
455 gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
457 char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
458 gboolean is_companion_device;
460 __bt_convert_device_path_to_address(device_path, device_address);
461 is_companion_device = __bt_ag_agent_is_companion_device(device_address);
463 DBG(" device_address[%s]", device_address);
464 DBG(" is_companion_device[%d]", is_companion_device);
466 if (__bt_ag_agent_is_companion_device_connected()) {
467 if (is_companion_device)
470 if (!is_companion_device)
475 #endif /* TIZEN_SUPPORT_DUAL_HF */
477 static gboolean __bt_is_phone_locked(int *phone_lock_state)
482 if (NULL == phone_lock_state)
485 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, phone_lock_state);
487 ERR("Failed to read [%s]\n", VCONFKEY_IDLE_LOCK_STATE);
495 static gboolean __bt_get_outgoing_callapp_type(int *callapp_type)
499 if (NULL == callapp_type)
502 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
503 *callapp_type = BT_VOICE_CALL;
510 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT,
513 ERR("Failed to read [%s]\n",
514 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT);
518 INFO(" [%s] = [%d]\n",
519 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT, *callapp_type);
521 /* The vconf value does not include in platform. */
522 *callapp_type = BT_VOICE_CALL;
528 static gboolean __bt_get_outgoing_call_condition(int *condition)
532 if (NULL == condition)
535 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
536 *condition = BT_MO_ONLY_UNLOCKED;
543 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT,
546 ERR("Failed to read [%s]\n",
547 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT);
551 /* The vconf value does not include in platform. */
552 *condition = BT_MO_ONLY_UNLOCKED;
558 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_TELEPHONY_ENABLED)
559 static gboolean __bt_ag_agent_launch_call_app(const char *number)
564 DBG_SECURE("number(%s)", number);
568 ERR("bundle_create() Failed");
572 bundle_add(b, "launch-type", "MO");
573 bundle_add(b, "dial-type", "HEADSET");
575 if (strlen(number) != 0)
576 bundle_add(b, "number", number);
578 aul_launch_app_async(CALL_APP_ID, b);
586 static void *__bt_ag_agent_launch_call_req(void *arg)
589 bundle *b = (bundle *)arg;
590 if (appsvc_run_service(b, 0, NULL, NULL) < 0)
591 ERR("Unable to run app svc");
593 call_launch_requested = FALSE;
598 static gboolean __bt_ag_agent_make_call(const char *number)
602 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
604 return __bt_ag_agent_launch_call_app(number);
606 char telnum[BT_MAX_TEL_NUM_STRING];
610 if (call_launch_requested == TRUE) {
611 DBG("Launch request is in progress");
619 appsvc_set_operation(b, APPSVC_OPERATION_CALL);
620 snprintf(telnum, sizeof(telnum), "tel:%s", number);
621 appsvc_set_uri(b, telnum);
622 appsvc_add_data(b, "ctindex", "-1");
624 call_launch_requested = TRUE;
625 if (pthread_create(&thread_id, NULL,
626 (void *)&__bt_ag_agent_launch_call_req,
628 ERR("pthread_create() is failed");
629 call_launch_requested = FALSE;
632 if (pthread_detach(thread_id) < 0)
633 ERR("pthread_detach() is failed");
640 static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
645 kb = bundle_create();
649 bundle_add(kb, "KEY_CALL_TYPE", "MO");
650 bundle_add(kb, "number", mo_number);
651 aul_launch_app("org.tizen.vtmain", kb);
658 gboolean _bt_ag_agent_answer_call(unsigned int call_id,
659 const gchar *path, const gchar *sender)
663 if (path == NULL || sender == NULL) {
664 DBG("Invalid Arguments");
668 DBG("Application path = %s", path);
669 DBG("Call Id = %d", call_id);
670 DBG("Sender = %s", sender);
672 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
673 BT_AG_SERVICE_NAME, "Answer",
674 g_variant_new("(u)", call_id));
679 gboolean _bt_ag_agent_reject_call(unsigned int call_id,
680 const gchar *path, const gchar *sender)
684 if (path == NULL || sender == NULL) {
685 DBG("Invalid Arguments");
689 DBG("Application path = %s", path);
690 DBG("Call Id = %d", call_id);
691 DBG("Sender = %s", sender);
693 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
694 BT_AG_SERVICE_NAME, "Reject",
695 g_variant_new("(u)", call_id));
700 gboolean _bt_ag_agent_release_call(unsigned int call_id,
701 const gchar *path, const gchar *sender)
705 if (path == NULL || sender == NULL) {
706 DBG("Invalid Arguments");
710 DBG("Application path = %s", path);
711 DBG("Call Id = %d", call_id);
712 DBG("Sender = %s", sender);
714 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
715 BT_AG_SERVICE_NAME, "Release",
716 g_variant_new("(u)", call_id));
722 bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
724 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
726 int phone_lock_state;
731 if (number == NULL) {
732 ERR("Invalid Argument");
733 error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
737 DBG("Number = %s", number);
738 DBG("flags = %d", flags);
740 if (!__bt_is_phone_locked(&phone_lock_state)) {
741 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
745 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
746 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
750 if (!__bt_get_outgoing_call_condition(&condition)) {
751 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
755 if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
756 VCONFKEY_IDLE_LOCK) {
757 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
761 if (callapp_type == BT_VIDEO_CALL) {
762 if (!__bt_ag_agent_make_video_call(number)) {
763 ERR("Problem launching application");
764 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
768 if (!__bt_ag_agent_make_call(number)) {
769 ERR("Problem launching application");
770 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
780 bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
782 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
784 contacts_filter_h filter = NULL;
785 contacts_query_h query = NULL;
786 contacts_list_h list = NULL;
787 contacts_record_h record = NULL;
788 unsigned int projections[] = {
789 _contacts_speeddial.number,
794 DBG("location = %d", location);
796 /*Get number from contacts location*/
797 if (contacts_connect() != CONTACTS_ERROR_NONE) {
798 ERR(" contacts_connect failed");
799 return BT_HFP_AGENT_ERROR_INTERNAL;
802 contacts_filter_create(_contacts_speeddial._uri, &filter);
807 if (contacts_filter_add_int(filter,
808 _contacts_speeddial.speeddial_number,
809 CONTACTS_MATCH_EQUAL, location) !=
810 CONTACTS_ERROR_NONE) {
811 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
815 contacts_query_create(_contacts_speeddial._uri, &query);
820 contacts_query_set_filter(query, filter);
822 if (contacts_query_set_projection(query, projections,
823 sizeof(projections)/sizeof(unsigned int)) !=
824 CONTACTS_ERROR_NONE) {
825 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
829 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
830 CONTACTS_ERROR_NONE) {
831 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
835 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
836 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
840 if (contacts_list_get_current_record_p(list, &record) !=
841 CONTACTS_ERROR_NONE) {
842 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
849 if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
850 != CONTACTS_ERROR_NONE) {
851 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
855 if (number == NULL) {
856 ERR("No number at the location");
857 error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
861 DBG("number %s", number);
864 if (!__bt_ag_agent_make_call(number)) {
865 ERR("Problem launching application");
866 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
872 contacts_list_destroy(list, TRUE);
875 contacts_filter_destroy(filter);
878 contacts_query_destroy(query);
880 contacts_disconnect();
887 bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
888 const gchar *path, const gchar *sender)
890 bt_hfp_agent_error_t ret;
894 if (dtmf == NULL || path == NULL || sender == NULL) {
895 ERR("Invalid Argument");
899 DBG("Dtmf = %s", dtmf);
900 DBG("Application path = %s", path);
901 DBG("Sender = %s", sender);
903 ret = __bt_ag_agent_gdbus_method_send(sender,
904 path, TELEPHONY_APP_INTERFACE,
906 g_variant_new("(s)", dtmf));
911 gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
912 const gchar *path, const gchar *sender)
916 if (path == NULL || sender == NULL) {
917 DBG("Invalid Arguments");
921 DBG("Application path = %s", path);
922 DBG("Value = %d", chld_value);
923 DBG("Sender = %s", sender);
925 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
926 /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
927 if not return FALSE */
928 if (chld_value != 0 && chld_value != 1 && chld_value != 2)
931 if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
935 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
936 BT_AG_SERVICE_NAME, "Threeway",
937 g_variant_new("(u)", chld_value));
942 bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
944 bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
945 char *last_num = NULL;
948 int phone_lock_state;
950 contacts_list_h list = NULL;
951 contacts_query_h query = NULL;
952 contacts_filter_h filter = NULL;
953 contacts_record_h record = NULL;
954 unsigned int projections[] = {
955 _contacts_phone_log.address,
956 _contacts_phone_log.log_type,
961 if (contacts_connect() != CONTACTS_ERROR_NONE) {
962 ERR(" contacts_connect failed");
963 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
967 contacts_filter_create(_contacts_phone_log._uri, &filter);
972 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
973 CONTACTS_MATCH_EQUAL,
974 CONTACTS_PLOG_TYPE_VOICE_OUTGOING) !=
975 CONTACTS_ERROR_NONE) {
976 ERR(" contacts_filter_add_int failed");
977 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
981 if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) !=
982 CONTACTS_ERROR_NONE) {
983 ERR(" contacts_filter_add_operator failed");
984 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
988 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
989 CONTACTS_MATCH_EQUAL,
990 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) !=
991 CONTACTS_ERROR_NONE) {
992 ERR(" contacts_filter_add_int failed");
993 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
997 contacts_query_create(_contacts_phone_log._uri, &query);
1002 contacts_query_set_filter(query, filter);
1004 if (contacts_query_set_projection(query, projections,
1005 sizeof(projections)/sizeof(unsigned int)) !=
1006 CONTACTS_ERROR_NONE) {
1007 ERR(" contacts_query_set_projection failed");
1008 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1012 if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false)
1013 != CONTACTS_ERROR_NONE) {
1014 ERR(" contacts_query_set_sort failed");
1015 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1019 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
1020 CONTACTS_ERROR_NONE) {
1021 ERR(" contacts_db_get_records_with_query failed");
1022 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1026 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
1027 ERR(" contacts_list_first failed");
1028 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1032 if (contacts_list_get_current_record_p(list, &record) !=
1033 CONTACTS_ERROR_NONE) {
1034 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1041 if (contacts_record_get_str(record, _contacts_phone_log.address,
1042 &last_num) != CONTACTS_ERROR_NONE) {
1043 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1047 if (last_num == NULL) {
1048 ERR("No last number");
1049 err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
1053 if (!__bt_is_phone_locked(&phone_lock_state)) {
1054 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1058 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
1059 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1063 if (!__bt_get_outgoing_call_condition(&condition)) {
1064 ERR(" Failed to get the call condition");
1065 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1069 if (condition == BT_MO_ONLY_UNLOCKED &&
1070 phone_lock_state == VCONFKEY_IDLE_LOCK) {
1071 ERR(" call condition and phone lock state check fail");
1072 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1076 switch (callapp_type) {
1078 if (!__bt_ag_agent_make_call(last_num)) {
1079 ERR("Problem launching application");
1080 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1084 if (!__bt_ag_agent_make_video_call(last_num)) {
1085 ERR("Problem launching application");
1086 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1089 case BT_FOLLOW_CALL_LOG:
1090 if (contacts_record_get_int(record,
1091 _contacts_phone_log.log_type,
1092 &type) != CONTACTS_ERROR_NONE) {
1093 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1096 if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
1097 if (!__bt_ag_agent_make_call(last_num)) {
1098 ERR("Problem launching application");
1099 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1101 } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
1102 if (!__bt_ag_agent_make_video_call(last_num)) {
1103 ERR("Problem launching application");
1104 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1107 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1111 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1118 contacts_list_destroy(list, TRUE);
1121 contacts_filter_destroy(filter);
1124 contacts_query_destroy(query);
1126 contacts_disconnect();
1128 if (last_num != NULL)
1136 bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
1137 const gchar *path, const gchar *sender)
1139 bt_hfp_agent_error_t ret;
1143 if (cmd == NULL || path == NULL || sender == NULL) {
1144 ERR("Invalid Argument");
1145 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
1148 DBG("cmd = %s", cmd);
1149 DBG("Application path = %s", path);
1150 DBG("Sender = %s", sender);
1152 ret = __bt_ag_agent_gdbus_method_send(sender,
1153 path, TELEPHONY_APP_INTERFACE,
1155 g_variant_new("(s)", cmd));
1160 gboolean _bt_ag_agent_get_signal_quality(void *device)
1166 if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
1167 DBG("VCONFKEY_TELEPHONY_RSSI failed\n");
1171 DBG("RSSI : %d", rssi);
1173 _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
1180 _bt_hfp_signal_quality_reply(-1, -1, device);
1184 gboolean _bt_ag_agent_get_battery_status(void *device)
1186 gint battery_chrg_status;
1187 gint battery_capacity;
1191 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
1192 &battery_chrg_status)) {
1193 DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n");
1197 DBG("Status : %d\n", battery_chrg_status);
1199 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
1200 &battery_capacity)) {
1201 DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n");
1205 DBG("Capacity : %d\n", battery_capacity);
1207 _bt_hfp_battery_property_reply(device,
1208 battery_chrg_status, battery_capacity);
1213 _bt_hfp_battery_property_reply(device, -1, -1);
1218 gboolean _bt_ag_agent_get_operator_name(void *device)
1220 char *operator_name;
1223 operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
1224 if (NULL == operator_name) {
1225 DBG("vconf_get_str failed");
1226 _bt_hfp_operator_reply(NULL, device);
1230 DBG("operator_name = [%s]", operator_name);
1232 _bt_hfp_operator_reply(operator_name, device);
1234 free(operator_name);
1240 gboolean _bt_hfp_agent_nrec_status(gboolean status,
1244 bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
1246 DBG("NREC status = %d", status);
1248 hs->nrec_status = FALSE;
1250 hs->nrec_status = TRUE;
1252 _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
1253 BT_AG_SERVICE_NAME, "NrecStatusChanged",
1254 g_variant_new("(b)", status));
1259 gboolean _bt_ag_agent_get_imei_number(void *device)
1264 imei_number = tel_get_misc_me_imei_sync(tapi_handle);
1265 if (NULL == imei_number) {
1266 ERR("tel_get_misc_me_imei_sync for imei_number failed");
1270 if (!g_utf8_validate(imei_number, -1, NULL)) {
1272 ERR("get_imei_number : invalid UTF8");
1276 DBG_SECURE("imei_number = [%s]", imei_number);
1277 _bt_hfp_get_imei_number_reply(imei_number, device);
1283 _bt_hfp_get_imei_number_reply(NULL, device);
1288 void _bt_ag_agent_get_manufacturer_name(void *device)
1291 char *manufacturer_name;
1294 ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
1295 &manufacturer_name);
1296 if (SYSTEM_INFO_ERROR_NONE != ret) {
1297 ERR("Get manufacturer_name failed : %d", ret);
1298 if (NULL != manufacturer_name)
1299 free(manufacturer_name);
1301 manufacturer_name = g_strdup("Unknown");
1302 } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
1303 free(manufacturer_name);
1304 manufacturer_name = g_strdup("Unknown");
1305 ERR("get_manufacturer_name : invalid UTF8");
1308 DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
1309 _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
1310 free(manufacturer_name);
1314 void _bt_ag_agent_get_imsi(void *device)
1317 TelSimImsiInfo_t imsi;
1318 memset(&imsi, 0, sizeof(TelSimImsiInfo_t));
1319 if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
1320 ERR("tel_get_sim_imsi failed");
1323 DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
1325 _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
1329 _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
1333 int _bt_ag_agent_registration_status_convert(int result)
1336 case TAPI_NETWORK_SERVICE_LEVEL_NO:
1337 return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
1338 case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
1339 return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
1340 case TAPI_NETWORK_SERVICE_LEVEL_FULL:
1341 return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
1342 case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
1343 return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
1345 return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
1350 void _bt_ag_agent_get_creg_status(void *device)
1356 int registration_status = 0;
1357 int roam_status = 0;
1359 ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
1361 if (ret != TAPI_API_SUCCESS) {
1362 ERR("tel_get_property_int failed");
1365 registration_status =
1366 _bt_ag_agent_registration_status_convert(result);
1368 DBG_SECURE("Registration status %d", result);
1369 DBG_SECURE("Mapped Status %d", registration_status);
1370 if (registration_status ==
1371 BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
1372 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
1374 ERR("Get roaming status failed err = %d\n", ret);
1377 DBG_SECURE("Roam status %d", roam_status);
1378 if (roam_status == 1) {
1379 registration_status =
1380 BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
1384 _bt_hfp_get_creg_status_reply(n, registration_status, device);
1390 void _bt_ag_agent_get_model_name(void *device)
1396 ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
1397 if (SYSTEM_INFO_ERROR_NONE != ret) {
1398 ERR("Get model_name failed: %d", ret);
1399 if (NULL != model_name)
1402 model_name = g_strdup("Unknown");
1403 } else if (!g_utf8_validate(model_name, -1, NULL)) {
1405 model_name = g_strdup("Unknown");
1406 ERR("get_model_name : invalid UTF8");
1409 DBG_SECURE("model_name = [%s]", model_name);
1410 _bt_hfp_get_model_info_reply(model_name, device);
1415 void _bt_ag_agent_get_revision_information(void *device)
1418 char *revision_info;
1421 ret = system_info_get_platform_string("http://tizen.org/system/build.string",
1423 if (SYSTEM_INFO_ERROR_NONE != ret) {
1424 ERR("Get revision_info failed: %d", ret);
1425 if (NULL != revision_info)
1426 free(revision_info);
1428 revision_info = g_strdup("Unknown");
1429 } else if (!g_utf8_validate(revision_info, -1, NULL)) {
1430 free(revision_info);
1431 revision_info = g_strdup("Unknown");
1432 ERR("get_revision_info: invalid UTF8");
1435 DBG_SECURE("revision_info = [%s]", revision_info);
1436 _bt_hfp_get_revision_info_reply(revision_info, device);
1437 free(revision_info);
1441 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
1442 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1447 b = bundle_create();
1449 ERR("bundle_create() Failed");
1453 bundle_add(b, "domain", "bt_headset");
1455 bundle_add(b, "action_type", "deactivate");
1457 aul_launch_app_async("org.tizen.svoice", b);
1463 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1466 app_control_h service = NULL;
1468 app_control_create(&service);
1470 if (service == NULL) {
1471 ERR("Service create failed");
1475 app_control_set_app_id(service, "org.tizen.svoice");
1476 app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
1477 if (app_control_add_extra_data(service, "domain", "bt_headset")
1478 != APP_CONTROL_ERROR_NONE) {
1479 ERR("app_control_add_extra_data failed");
1480 app_control_destroy(service);
1485 if (app_control_add_extra_data(service, "action_type", "deactivate")
1486 != APP_CONTROL_ERROR_NONE) {
1487 ERR("app_control_add_extra_data failed");
1488 app_control_destroy(service);
1492 if (app_control_send_launch_request(service, NULL, NULL) !=
1493 APP_CONTROL_ERROR_NONE) {
1494 ERR("launch failed");
1495 app_control_destroy(service);
1499 app_control_destroy(service);
1505 gboolean _bt_ag_agent_voice_dial(gboolean activate)
1507 DBG("Activate = %d", activate);
1509 return __bt_ag_agent_launch_voice_dial(activate);
1512 static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
1515 hs->codec_info.is_negotiating = FALSE;
1516 hs->codec_info.requested_by_hf = FALSE;
1517 hs->codec_info.sending_codec = 0;
1519 hs->codec_info.remote_codecs = 0;
1520 hs->codec_info.final_codec = 0;
1521 hs->nrec_status = FALSE;
1524 if (hs->codec_info.nego_timer) {
1525 g_source_remove(hs->codec_info.nego_timer);
1526 hs->codec_info.nego_timer = 0;
1528 wbs_opts.wbs_enable = wbs_en;
1531 static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
1533 struct ag_codec *data = (struct ag_codec *)user_data;
1535 if (g_strcmp0(data->codec_status, "finish") == 0) {
1536 DBG("Codec negotiation finished");
1537 __bt_ag_sco_connect(data->bt_ag_info);
1538 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1539 g_free(data->codec_status);
1542 } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
1543 DBG("Timeout is occured in codec negotiation");
1546 if (data->bt_ag_info->codec_info.requested_by_hf) {
1547 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1549 __bt_ag_sco_connect(data->bt_ag_info);
1550 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1552 g_free(data->codec_status);
1558 static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
1563 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
1565 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
1566 G_DBUS_PROXY_FLAGS_NONE, NULL,
1567 BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
1568 BT_ADAPTER_INTERFACE, NULL, &err);
1572 ERR("Unable to create proxy: %s", err->message);
1573 g_clear_error(&err);
1575 return BT_HFP_AGENT_ERROR_INTERNAL;
1578 ret = g_dbus_proxy_call_sync(proxy, method,
1579 g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
1580 G_DBUS_CALL_FLAGS_NONE, -1,
1583 /* dBUS-RPC is failed */
1584 ERR("dBUS-RPC is failed");
1586 /* dBUS gives error cause */
1587 ERR("D-Bus API failure: errCode[%x], message[%s]",
1588 err->code, err->message);
1590 g_clear_error(&err);
1592 return BT_HFP_AGENT_ERROR_INTERNAL;
1594 g_variant_unref(ret);
1596 return BT_HFP_AGENT_ERROR_NONE;
1599 static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
1602 bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
1604 DBG("Codec setup [%x]", codec);
1606 /* 1. Compare sending codec & recieved code */
1607 if (hs->codec_info.sending_codec != codec)
1608 err = BT_HFP_AGENT_ERROR_INTERNAL;
1610 /* 2. Send WB or NB command */
1612 case BT_CVSD_CODEC_ID:
1613 err = __bt_ag_set_codec(hs, "SetNbParameters");
1615 case BT_MSBC_CODEC_ID:
1616 err = __bt_ag_set_codec(hs, "SetWbsParameters");
1619 err = BT_HFP_AGENT_ERROR_INTERNAL;
1623 /* If the vendor specific calling returns error or codec is not correct,
1624 * we send CVSD Codec parameter to MM module. and also returns
1625 * normal value to HF
1627 if (err != BT_HFP_AGENT_ERROR_NONE)
1628 codec = BT_CVSD_CODEC_ID;
1630 hs->codec_info.final_codec = codec;
1635 static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
1636 gboolean init_by_hf)
1639 struct ag_codec *data = NULL;;
1641 #ifdef TIZEN_FEATURE_BT_KIRAN_DEVICE
1642 codec = BT_CVSD_CODEC_ID;
1644 if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
1645 codec = BT_MSBC_CODEC_ID;
1647 codec = BT_CVSD_CODEC_ID;
1650 if (wbs_opts.wbs_enable == FALSE)
1651 codec = BT_CVSD_CODEC_ID;
1655 if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
1656 return BT_HFP_AGENT_ERROR_INTERNAL;
1658 DBG("Send +BCS:%d\n", codec);
1660 /* Send +BCS command to HF, and wait some times */
1661 hs->codec_info.is_negotiating = TRUE;
1662 hs->codec_info.sending_codec = codec;
1663 hs->codec_info.requested_by_hf = init_by_hf;
1664 hs->codec_info.final_codec = codec;
1666 data = g_new0(struct ag_codec, 1);
1668 return BT_HFP_AGENT_ERROR_NO_MEMORY;
1670 data->bt_ag_info = hs;
1671 data->codec_status = g_strdup("timeout");
1673 hs->codec_info.nego_timer = g_timeout_add_seconds(
1674 HFP_CODEC_NEGOTIATION_TIMEOUT,
1675 (GSourceFunc)__bt_ag_codec_negotiation_finished,
1678 return BT_HFP_AGENT_ERROR_NONE;
1682 static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
1683 bt_ag_info_t *hs, gboolean init_by_hf)
1685 DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
1687 if (hs->state < HEADSET_STATE_CONNECTED)
1688 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1690 if (hs->codec_info.is_negotiating == TRUE) {
1691 /* In codec negotiation, return and wait */
1692 ERR("Codec nogotiation is in progress");
1693 return BT_HFP_AGENT_ERROR_BUSY;
1696 /* Not support Codec Negotiation or Not recieved BAC command */
1697 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
1698 hs->codec_info.remote_codecs == 0) {
1699 ERR("No support for Codec Negotiation or receive BAC command");
1701 return BT_HFP_AGENT_ERROR_INTERNAL;
1703 __bt_ag_sco_connect(hs);
1704 return BT_HFP_AGENT_ERROR_INTERNAL;
1708 /* If HF initiated codec connection setup, it should send OK command
1709 * before +BCS command transmission.
1712 return HFP_STATE_MNGR_ERR_NONE;
1714 return __bt_hfp_send_bcs_command(hs, init_by_hf);
1718 static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
1721 *codecs = 0x00000000;
1723 str = strchr(cmd, '=');
1727 while (str != NULL) {
1730 if (atoi(str) == BT_CVSD_CODEC_ID)
1731 *codecs |= BT_CVSD_CODEC_MASK;
1732 else if (atoi(str) == BT_MSBC_CODEC_ID)
1733 *codecs |= BT_MSBC_CODEC_MASK;
1735 str = strchr(str, ',');
1738 if (*codecs == 0x00000000)
1744 /* AT+BAC (Bluetooth Available Codecs) */
1745 static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
1747 uint32_t codecs = 0x00000000;
1748 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1750 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
1751 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1752 } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
1753 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1755 DBG("Update remote available codecs [%x]", codecs);
1756 hs->codec_info.remote_codecs = codecs;
1759 _bt_ag_send_response(hs, err);
1761 /* Reset codec information and
1762 * restart codec connection setup by AG
1764 hs->codec_info.final_codec = 0;
1765 if (hs->codec_info.nego_timer) {
1766 hs->codec_info.is_negotiating = FALSE;
1767 hs->codec_info.requested_by_hf = FALSE;
1768 hs->codec_info.sending_codec = 0;
1769 g_source_remove(hs->codec_info.nego_timer);
1770 __bt_hfp_codec_connection_setup(hs, FALSE);
1776 /* AT+BCC (Bluetooth Codec Connection) */
1777 static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
1779 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1781 err = __bt_hfp_codec_connection_setup(hs, TRUE);
1783 _bt_ag_send_response(hs, err);
1785 if (err == HFP_STATE_MNGR_ERR_NONE)
1786 err = __bt_hfp_send_bcs_command(hs, TRUE);
1788 if (err != HFP_STATE_MNGR_ERR_NONE)
1789 ERR("Fail to request codec connection setup");
1794 /* AT+BCS (Bluetooth Codec Selection) */
1795 static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
1797 uint32_t codec = 0x00000000;
1798 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1799 struct ag_codec *data = g_new0(struct ag_codec, 1);
1802 if (hs->codec_info.nego_timer) {
1803 g_source_remove(hs->codec_info.nego_timer);
1804 hs->codec_info.nego_timer = 0;
1807 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
1808 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1809 else if (__hfp_parse_available_codecs(buf, &codec) < 0)
1810 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1811 else if (__bt_ag_codec_selection_setup(hs, codec) !=
1812 BT_HFP_AGENT_ERROR_NONE)
1813 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1815 data->bt_ag_info = hs;
1816 data->codec_status = g_strdup("finish");
1817 _bt_ag_send_response(hs, err);
1818 __bt_ag_codec_negotiation_finished(data);
1823 static void __bt_ag_str2ba(const char *str, bt_addr *ba)
1826 for (i = 5; i >= 0; i--, str += 3)
1827 ba->b[i] = strtol(str, NULL, 16);
1830 static const char *__bt_ag_state2str(hs_state_t state)
1833 case HEADSET_STATE_DISCONNECTED:
1834 return "disconnected";
1835 case HEADSET_STATE_CONNECTING:
1836 return "connecting";
1837 case HEADSET_STATE_CONNECTED:
1839 case HEADSET_STATE_PLAY_IN_PROGRESS:
1840 return "Play In Progress";
1841 case HEADSET_STATE_ON_CALL:
1848 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
1849 const char *address)
1854 ret_if(address == NULL);
1855 ret_if(addr == NULL);
1857 for (i = 0; i < 6; i++) {
1858 addr[5 - i] = strtol(address, &ptr, 16);
1859 if (ptr[0] != '\0') {
1868 static gboolean __bt_ag_check_nval(GIOChannel *chan)
1870 struct pollfd file_desc;
1872 memset(&file_desc, 0, sizeof(file_desc));
1873 file_desc.fd = g_io_channel_unix_get_fd(chan);
1874 file_desc.events = POLLNVAL;
1876 if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
1882 static int __bt_ag_sco_connect(bt_ag_info_t *hs)
1884 struct sco_socket_addr sco_addr;
1889 bt_ag_slconn_t *slconn = hs->slc;
1892 if (hs->state == HEADSET_STATE_ON_CALL)
1893 return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED;
1895 if (hs->state != HEADSET_STATE_CONNECTED)
1896 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1897 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
1898 _bt_ag_agent_check_transport_state();
1901 /* Create Sco socket */
1902 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
1904 ERR("ERROR: Create socket failed.\n");
1905 return BT_HFP_AGENT_ERROR_INTERNAL;
1908 /* Bind Sco Socket to Local BD addr */
1909 memset(&sco_addr, 0, sizeof(sco_addr));
1910 sco_addr.sco_family = AF_BLUETOOTH;
1912 __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
1913 DBG("Local BD address: %s", local_addr);
1915 err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1917 ERR("ERROR: sco socket binding failed");
1918 ERR("Close SCO skt");
1920 return BT_HFP_AGENT_ERROR_INTERNAL;
1923 DBG("Socket FD : %d", sco_skt);
1925 io = g_io_channel_unix_new(sco_skt);
1926 g_io_channel_set_close_on_unref(io, TRUE);
1927 /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
1928 g_io_channel_set_buffered(io, FALSE);
1929 g_io_channel_set_encoding(io, NULL, NULL);*/
1931 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
1932 (slconn && (slconn->hs_features &
1933 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
1934 wbs_opts.wbs_enable == TRUE) {
1935 bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
1936 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
1938 DBG("set Bluetooth voice: %d", bt_vo.setting);
1939 err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
1940 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
1942 ERR("ERROR: sco socket set socket option failed");
1943 ERR("Close SCO skt");
1944 g_io_channel_unref(io);
1946 return BT_HFP_AGENT_ERROR_INTERNAL;
1949 DBG("Set NB codec parameter");
1950 __bt_ag_set_codec(hs, "SetNbParameters");
1953 memset(&sco_addr, 0, sizeof(sco_addr));
1954 sco_addr.sco_family = AF_BLUETOOTH;
1955 __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
1956 DBG("remotel BD address: %s", hs->remote_addr);
1958 err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1959 if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
1960 ERR("ERROR: sco socket connect failed : %d", err);
1961 ERR("Close SCO skt");
1962 g_io_channel_unref(io);
1964 return BT_HFP_AGENT_ERROR_INTERNAL;
1967 /* Disabling the watch since SCO is connected */
1968 /*watch_id = __bt_ag_set_watch(io,
1969 (GIOFunc) __bt_ag_sco_connect_cb, hs);
1971 DBG("SCO watch set Success");*/
1975 _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
1976 return BT_HFP_AGENT_ERROR_NONE;
1979 static void __bt_ag_close_sco(bt_ag_info_t *hs)
1983 int sock = g_io_channel_unix_get_fd(hs->sco);
1984 shutdown(sock, SHUT_RDWR);
1985 g_io_channel_unref(hs->sco);
1990 __bt_ag_agent_remove_watch(&hs->sco_id);
1993 static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
1994 GIOCondition cond, gpointer user_data)
1996 bt_ag_info_t *ag_info = user_data;
1999 if (cond & G_IO_NVAL)
2002 if (cond & (G_IO_HUP | G_IO_ERR)) {
2003 ag_info->sco = NULL;
2004 if (ag_info->sco_id)
2005 __bt_ag_agent_remove_watch(&ag_info->sco_id);
2007 if (ag_info->watch_id)
2008 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
2014 static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
2015 GIOCondition cond, gpointer user_data)
2017 bt_ag_info_t *ag_info = user_data;
2021 bt_ag_slconn_t *slconn = ag_info->slc;
2025 if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
2026 __bt_ag_check_nval(chan)) {
2027 ERR("cond or chan is not valid");
2031 INFO_C("Incoming SCO....");
2033 if (ag_info->state < HEADSET_STATE_CONNECTED)
2034 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
2036 sco_skt = g_io_channel_unix_get_fd(chan);
2038 cli_sco_sock = accept(sco_skt, NULL, NULL);
2039 if (cli_sco_sock < 0) {
2040 ERR("accept is failed");
2044 sco_io = g_io_channel_unix_new(cli_sco_sock);
2045 g_io_channel_set_close_on_unref(sco_io, TRUE);
2046 g_io_channel_set_encoding(sco_io, NULL, NULL);
2047 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2048 g_io_channel_set_buffered(sco_io, FALSE);
2050 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2051 (slconn && (slconn->hs_features &
2052 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
2053 wbs_opts.wbs_enable == TRUE) {
2054 bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
2055 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
2057 DBG("set Bluetooth voice: %d", bt_vo.setting);
2058 err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
2059 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
2061 ERR("Sco socket set socket option failed");
2062 close(cli_sco_sock);
2067 ag_info->sco = sco_io;
2068 ag_info->sco_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2069 __bt_ag_sco_server_conn_cb, ag_info);
2071 if (remote_dev_path)
2072 g_free(remote_dev_path);
2074 remote_dev_path = g_strdup(ag_info->path);
2076 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
2081 static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
2083 DBG("Start SCO server");
2084 struct sco_socket_addr addr;
2087 bdaddr_t bd_addr = {{0},};
2089 if (hs->sco_server_started) {
2090 DBG("Already exsist");
2091 return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
2095 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
2097 ERR("Can't create socket:\n");
2098 return BT_HFP_AGENT_ERROR_INTERNAL;
2101 /* Bind to local address */
2102 memset(&addr, 0, sizeof(addr));
2103 addr.sco_family = AF_BLUETOOTH;
2105 _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
2106 DBG("Bind to address %s", hs->remote_addr);
2107 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2109 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2110 ERR("Can't bind socket:\n");
2114 if (listen(sco_skt, 1)) {
2115 ERR("Can not listen on the socket:\n");
2119 sco_io = g_io_channel_unix_new(sco_skt);
2120 g_io_channel_set_close_on_unref(sco_io, TRUE);
2121 g_io_channel_set_encoding(sco_io, NULL, NULL);
2122 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2123 g_io_channel_set_buffered(sco_io, FALSE);
2125 hs->sco_server = sco_io;
2126 hs->sco_watch_id = g_io_add_watch(sco_io,
2127 G_IO_IN | G_IO_HUP | G_IO_ERR |
2128 G_IO_NVAL, __bt_ag_sco_server_cb, hs);
2130 hs->sco_server_started = TRUE;
2131 return BT_HFP_AGENT_ERROR_NONE;
2135 return BT_HFP_AGENT_ERROR_INTERNAL;
2138 void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
2140 DBG("Stop SCO server");
2141 if (hs->sco_server) {
2142 g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
2143 g_io_channel_unref(hs->sco_server);
2144 hs->sco_server = NULL;
2146 hs->sco_server_started = FALSE;
2149 static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
2151 GIOChannel *rfcomm = hs->rfcomm;
2154 g_io_channel_shutdown(rfcomm, TRUE, NULL);
2155 g_io_channel_unref(rfcomm);
2165 static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
2168 if (cond & G_IO_NVAL)
2171 if (name_owner_sig_id != -1)
2172 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
2174 name_owner_sig_id = -1;
2178 DBG("Audio connection disconnected");
2179 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2184 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
2186 bt_ag_slconn_t *slconn = hs->slc;
2187 const char *hs_state;
2188 hs_state_t org_state = hs->state;
2189 gboolean val = FALSE;
2191 if (org_state == state)
2194 hs_state = __bt_ag_state2str(state);
2197 case HEADSET_STATE_CONNECTING:
2198 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2200 BT_HEADSET_INTERFACE, "State",
2201 g_variant_new("s", hs_state));
2205 case HEADSET_STATE_CONNECTED:
2206 if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
2207 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2209 BT_HEADSET_INTERFACE, "State",
2210 g_variant_new("s", hs_state));
2212 if (hs->state < state) {
2214 active_devices = g_slist_append(active_devices, hs);
2215 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2217 BT_HEADSET_INTERFACE,
2219 g_variant_new("b", val));
2221 DBG("Device %s connected\n", hs->remote_addr);
2222 #if defined(TIZEN_SUPPORT_DUAL_HF)
2223 if (!hs->is_companion_device)
2224 __bt_ag_start_sco_server(hs);
2226 __bt_ag_start_sco_server(hs);
2229 /* Set default code as Gateway NB */
2230 __bt_ag_set_codec(hs, "SetNbParameters");
2231 } else if (hs->state == HEADSET_STATE_ON_CALL) {
2233 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2235 BT_HEADSET_INTERFACE,
2237 g_variant_new("b", val));
2242 case HEADSET_STATE_DISCONNECTED:
2243 __bt_ag_close_sco(hs);
2244 __bt_ag_headset_close_rfcomm(hs);
2246 if (hs->state == HEADSET_STATE_ON_CALL) {
2248 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2250 BT_HEADSET_INTERFACE,
2252 g_variant_new("b", val));
2256 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2258 BT_HEADSET_INTERFACE,
2260 g_variant_new("b", val));
2261 if (hs->state > HEADSET_STATE_CONNECTING)
2262 _bt_hfp_device_disconnected(hs);
2264 active_devices = g_slist_remove(active_devices, hs);
2266 __bt_ag_codec_negotiation_info_reset(hs, TRUE);
2267 #if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
2268 __bt_ag_set_codec(hs, "SetNbParameters");
2272 /* Since SCO server is binded on remote address */
2273 /* Need to stop SCO server once heasdet disconencted*/
2274 if (hs->sco_server_started)
2275 __bt_ag_stop_sco_server(hs);
2277 g_free(hs->remote_addr);
2281 case HEADSET_STATE_PLAY_IN_PROGRESS:
2282 case HEADSET_STATE_ON_CALL:
2284 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2286 BT_HEADSET_INTERFACE, "State",
2287 g_variant_new("s", hs_state));
2289 /*add watch for sco data */
2290 hs->sco_id = g_io_add_watch(hs->sco,
2291 G_IO_ERR | G_IO_NVAL,
2292 (GIOFunc) __bt_ag_sco_cb, hs);
2294 _bt_ag_agent_emit_property_changed(
2295 ag_dbus_conn, hs->path,
2296 BT_HEADSET_INTERFACE, "Playing",
2297 g_variant_new("b", val));
2299 if (slconn->microphone_gain >= 0)
2300 _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
2301 slconn->microphone_gain);
2303 if (slconn->speaker_gain >= 0)
2304 _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
2305 slconn->speaker_gain);
2315 INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
2316 __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
2319 static struct event at_event_callbacks[] = {
2320 { "AT+BRSF", _bt_hfp_supported_features },
2321 { "AT+CIND", _bt_hfp_report_indicators },
2322 { "AT+CMER", _bt_hfp_enable_indicators },
2323 { "AT+CHLD", _bt_hfp_call_hold },
2324 { "ATA", _bt_hfp_answer_call },
2325 { "ATD", _bt_hfp_dial_number },
2326 { "AT+VG", _bt_hfp_signal_gain_setting },
2327 { "AT+CHUP", _bt_hfp_terminate_call },
2328 { "AT+CKPD", _bt_hfp_key_press },
2329 { "AT+CLIP", _bt_hfp_cli_notification },
2330 { "AT+BTRH", _bt_hfp_response_and_hold },
2331 { "AT+BLDN", _bt_hfp_last_dialed_number },
2332 { "AT+VTS", _bt_hfp_dtmf_tone },
2333 { "AT+CNUM", _bt_hfp_subscriber_number },
2334 { "AT+CLCC", _bt_hfp_list_current_calls },
2335 { "AT+CMEE", _bt_hfp_extended_errors },
2336 { "AT+CCWA", _bt_hfp_call_waiting_notify },
2337 { "AT+COPS", _bt_hfp_operator_selection },
2338 { "AT+NREC", _bt_hfp_nr_and_ec },
2339 { "AT+BVRA", _bt_hfp_voice_dial },
2340 { "AT+XAPL", _bt_hfp_apl_command },
2341 { "AT+IPHONEACCEV", _bt_hfp_apl_command },
2342 { "AT+BIA", _bt_hfp_indicators_activation },
2343 { "AT+CPBS", _bt_hfp_select_pb_memory },
2344 { "AT+CPBR", _bt_hfp_read_pb_entries},
2345 { "AT+CPBF", _bt_hfp_find_pb_entires },
2346 { "AT+CSCS", _bt_hfp_select_character_set },
2347 { "AT+CSQ", _bt_hfp_get_signal_quality },
2348 { "AT+CBC", _bt_hfp_get_battery_charge_status },
2349 { "AT+CPAS", _bt_hfp_get_activity_status },
2350 { "AT+CGSN", _bt_hfp_get_equipment_identity },
2351 { "AT+CGMM", _bt_hfp_get_model_information },
2352 { "AT+CGMI", _bt_hfp_get_device_manufacturer },
2353 { "AT+CGMR", _bt_hfp_get_revision_information },
2354 { "AT+BAC", __bt_hfp_available_codecs },
2355 { "AT+BCC", __bt_hfp_codec_connection },
2356 { "AT+BCS", __bt_hfp_codec_selection },
2357 { "AT+XSAT", _bt_hfp_vendor_cmd },
2358 { "AT+CIMI", _bt_hfp_get_imsi },
2359 { "AT+CREG", _bt_hfp_get_creg_status },
2363 int num_of_secure_command = 4;
2364 static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
2366 void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
2370 char s[MAX_BUFFER_SIZE] = {0, };
2371 gboolean hide = FALSE;
2373 gboolean is_security_command = FALSE;
2376 strncpy(s, buf, MAX_BUFFER_SIZE - 1);
2378 for (i = 0; i < num_of_secure_command; i++) {
2379 if (strstr(buf, secure_command[i])) {
2380 is_security_command = TRUE;
2385 /* +XSAT: 11,DISC */
2386 xsat_ptr = strstr(s, "11,DISC,");
2388 xsat_ptr = xsat_ptr + 8;
2390 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2396 /* AT+XSAT=11,Q_CT,X,XXXX */
2397 xsat_ptr = strstr(s, "11,Q_CT,");
2399 xsat_ptr = xsat_ptr + 8;
2401 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2402 if (x > 1) /* ignore 0 and 1 position */
2409 while (s[i] != '\0') {
2410 if (s[i] == '\r' || s[i] == '\n') {
2414 hide = hide ? FALSE : TRUE;
2415 else if (is_security_command && hide) {
2423 INFO("%s Buffer = [%s], Len(%d)", message, s, strlen(s));
2428 static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
2432 __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
2434 for (ev = at_event_callbacks; ev->cmd; ev++) {
2435 if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
2436 return ev->callback(hs, buf);
2442 static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
2445 ssize_t final_written, count;
2446 char rsp_buffer[MAX_BUFFER_SIZE];
2450 count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
2452 ERR("count is %d", count);
2456 if (!hdset->io_chan) {
2457 ERR("__bt_ag_send_at_valist: headset not connected");
2463 fd = g_io_channel_unix_get_fd(hdset->io_chan);
2466 while (final_written < count) {
2470 written = write(fd, rsp_buffer + final_written,
2471 count - final_written);
2472 } while (written < 0 && errno == EINTR);
2476 ERR("write failed : %s (%d)", strerror(-err), -err);
2480 final_written += written;
2483 /* Synchronize the sending buffer */
2487 ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
2491 __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
2496 int __attribute__((format(printf, 2, 3)))
2497 _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
2502 va_start(ap, format);
2503 ret = __bt_ag_send_at_valist(hs, ap, format);
2509 void __attribute__((format(printf, 3, 4)))
2510 _bt_ag_send_foreach_headset(GSList *devices,
2511 int (*cmp) (bt_ag_info_t *hs),
2517 for (l = devices; l != NULL; l = l->next) {
2518 bt_ag_info_t *hs = l->data;
2521 if (cmp && cmp(hs) != 0)
2524 va_start(ap, format);
2525 ret = __bt_ag_send_at_valist(hs, ap, format);
2527 ERR("Failed to send to headset: %s (%d)",
2528 strerror(-ret), -ret);
2533 int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
2535 if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
2536 return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
2539 case HFP_STATE_MNGR_ERR_NONE:
2540 return _bt_ag_send_at(hs, "\r\nOK\r\n");
2541 case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
2542 return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
2544 return _bt_ag_send_at(hs, "\r\nERROR\r\n");
2548 static gboolean __bt_ag_event_handler(GIOChannel *channel,
2549 GIOCondition cond, void *user_data)
2551 bt_ag_slconn_t *slconn;
2552 unsigned char event_buf[MAX_BUFFER_SIZE];
2554 size_t available_buffer;
2556 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2559 if (cond & G_IO_NVAL)
2562 slconn = bt_ag_info->slc;
2563 if (cond & (G_IO_ERR | G_IO_HUP)) {
2564 if (bt_ag_info->watch_id)
2565 __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
2567 ERR("ERR or HUP on RFCOMM socket");
2568 INFO_C("Disconnected [AG role] [Terminated by remote dev]");
2572 fd = g_io_channel_unix_get_fd(channel);
2573 len = read(fd, event_buf, sizeof(event_buf) - 1);
2577 available_buffer = sizeof(slconn->buffer) - (slconn->start) -
2578 (slconn->length) - 1;
2579 if (available_buffer < (size_t) len) {
2580 ERR("Buffer over flow");
2584 memcpy(&slconn->buffer[slconn->start], event_buf, len);
2585 slconn->length += len;
2587 slconn->buffer[slconn->start + slconn->length] = '\0';
2589 while (slconn->length > 0) {
2594 get_cr = strchr(&slconn->buffer[slconn->start], '\r');
2598 cmd_len = 1 + (off_t) get_cr -
2599 (off_t) &slconn->buffer[slconn->start];
2603 DBG("Call AT handler");
2604 err = __bt_ag_at_handler(bt_ag_info,
2605 &slconn->buffer[slconn->start]);
2607 ERR("Failed to call AT handler");
2611 if (err == -EINVAL) {
2612 ERR("Unrecognized command: %s",
2613 &slconn->buffer[slconn->start]);
2614 err = _bt_ag_send_response(bt_ag_info,
2615 HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
2619 ERR("Error handling command %s: %s (%d)",
2620 &slconn->buffer[slconn->start],
2621 strerror(-err), -err);
2623 slconn->start += cmd_len;
2624 slconn->length -= cmd_len;
2626 if (!slconn->length)
2631 ERR("Failed in event handler - SLC Disconnect");
2632 _bt_ag_set_headset_state(bt_ag_info,
2633 HEADSET_STATE_DISCONNECTED);
2637 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
2638 const gchar *object_path)
2642 bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
2643 struct sockaddr_remote address;
2644 socklen_t address_len;
2646 INFO_C("Connected [AG role]");
2647 bt_ag_info->rfcomm = NULL;
2648 bt_ag_info->slc = NULL;
2649 bt_ag_info->hfp_active = TRUE;
2650 bt_ag_info->vr_blacklisted = FALSE;
2651 bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
2652 bt_ag_info->sco_server_started = FALSE;
2653 __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
2655 bt_ag_info->path = device_path;
2656 DBG("device_path = [%s]", device_path);
2658 address_len = sizeof(address);
2659 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2660 ERR("BD_ADDR is NULL");
2662 DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
2663 bt_ag_info->fd = fd;
2664 bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
2665 flags = g_io_channel_get_flags(bt_ag_info->io_chan);
2667 flags &= ~G_IO_FLAG_NONBLOCK;
2668 flags &= G_IO_FLAG_MASK;
2669 g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
2670 g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
2671 g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
2673 bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
2675 bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2676 __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
2677 address.remote_bdaddr.b);
2679 #if defined(TIZEN_SUPPORT_DUAL_HF)
2680 bt_ag_info->is_companion_device =
2681 __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
2684 DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
2686 if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
2687 DBG("HSP connection completed");
2688 _bt_ag_set_headset_state(bt_ag_info,
2689 HEADSET_STATE_CONNECTED);
2691 DBG("HFP connection connecting");
2692 _bt_ag_set_headset_state(bt_ag_info,
2693 HEADSET_STATE_CONNECTING);
2696 __bt_ag_agent_start_watch(bt_ag_info);
2698 bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
2699 bt_ag_info->slc->speaker_gain = 15;
2700 bt_ag_info->slc->microphone_gain = 15;
2701 bt_ag_info->slc->is_nrec = TRUE;
2706 static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
2715 fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
2718 ERR("Unable to open VR blacklist file");
2722 fseek(fp, 0, SEEK_END);
2725 ERR("size is not a positive number");
2732 buffer = g_malloc0(sizeof(char) * size);
2733 if (buffer == NULL) {
2734 ERR("g_malloc0 is failed");
2738 result = fread((char *)buffer, 1, size, fp);
2740 if (result != size) {
2746 token = strtok_r(buffer, "=", &saveptr);
2747 if (token == NULL) {
2752 while ((token = strtok_r(NULL, ",", &saveptr))) {
2753 if (strlen(token) > 8)
2755 if (0 == g_strcmp0(token, lap_addr)) {
2756 INFO("Voice Recognition blacklisted");
2765 static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
2767 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2768 sco_open_timer_id = 0;
2769 DBG("sco_open_request (%d)", sco_open_request);
2771 if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
2772 bt_ag_slconn_t *slconn = bt_ag_info->slc;
2774 INFO("try to open SCO");
2775 sco_open_request = FALSE;
2777 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2778 (slconn && (slconn->hs_features &
2779 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
2780 switch (bt_ag_info->codec_info.final_codec) {
2781 case BT_CVSD_CODEC_ID:
2782 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
2783 __bt_ag_sco_connect(bt_ag_info);
2785 case BT_MSBC_CODEC_ID:
2786 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
2787 __bt_ag_sco_connect(bt_ag_info);
2790 __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
2794 __bt_ag_sco_connect(bt_ag_info);
2801 * Service level connection complete
2802 * indication and state management
2804 void _bt_ag_slconn_complete(bt_ag_info_t *hs)
2806 char lap_address[BT_LOWER_ADDRESS_LENGTH];
2808 DBG("HFP Service Level Connection established\n");
2810 /* Check device Voice Recognition blacklist status */
2811 g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
2812 hs->vr_blacklisted =
2813 __bt_ag_agent_is_device_vr_blacklisted(lap_address);
2815 if (sco_open_timer_id > 0) {
2816 g_source_remove(sco_open_timer_id);
2817 sco_open_timer_id = 0;
2820 sco_open_request = FALSE;
2821 sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
2822 __bt_sco_open_delay_timeout_cb, hs);
2824 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2827 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
2830 g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
2831 g_io_channel_unref(hs->io_chan);
2835 __bt_ag_close_sco(hs);
2836 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2839 __bt_ag_agent_remove_watch(&hs->watch_id);
2841 _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
2845 static GQuark __bt_ag_agent_error_quark(void)
2849 static GQuark quark = 0;
2851 quark = g_quark_from_static_string("ag-agent");
2857 static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
2860 ERR("error[%d]\n", error);
2863 case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
2864 return g_error_new(BT_AG_AGENT_ERROR, error,
2865 BT_ERROR_NOT_AVAILABLE);
2866 case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
2867 return g_error_new(BT_AG_AGENT_ERROR, error,
2868 BT_ERROR_NOT_CONNECTED);
2869 case BT_HFP_AGENT_ERROR_BUSY:
2870 return g_error_new(BT_AG_AGENT_ERROR, error,
2872 case BT_HFP_AGENT_ERROR_INVALID_PARAM:
2873 return g_error_new(BT_AG_AGENT_ERROR, error,
2874 BT_ERROR_INVALID_PARAM);
2875 case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
2876 return g_error_new(BT_AG_AGENT_ERROR, error,
2877 BT_ERROR_ALREADY_EXSIST);
2878 case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
2879 return g_error_new(BT_AG_AGENT_ERROR, error,
2880 BT_ERROR_ALREADY_CONNECTED);
2881 case BT_HFP_AGENT_ERROR_NO_MEMORY:
2882 return g_error_new(BT_AG_AGENT_ERROR, error,
2883 BT_ERROR_NO_MEMORY);
2884 case BT_HFP_AGENT_ERROR_I_O_ERROR:
2885 return g_error_new(BT_AG_AGENT_ERROR, error,
2886 BT_ERROR_I_O_ERROR);
2887 case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
2888 return g_error_new(BT_AG_AGENT_ERROR, error,
2889 BT_ERROR_OPERATION_NOT_AVAILABLE);
2890 case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
2891 return g_error_new(BT_AG_AGENT_ERROR, error,
2893 case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
2894 return g_error_new(BT_AG_AGENT_ERROR, error,
2896 case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
2897 return g_error_new(BT_AG_AGENT_ERROR, error,
2898 BT_ERROR_NO_CALL_LOG);
2899 case BT_HFP_AGENT_ERROR_INTERNAL:
2901 return g_error_new(BT_AG_AGENT_ERROR, error,
2907 static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
2911 for (l = active_devices ; l; l = l->next) {
2912 bt_ag_info_t *data = l->data;
2913 if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
2915 if (g_strcmp0(data->path, device_path) == 0) {
2916 INFO("Active device found");
2921 INFO("Active device not found");
2925 static void __bt_ag_agent_method(GDBusConnection *connection,
2926 const gchar *sender,
2927 const gchar *object_path,
2928 const gchar *interface_name,
2929 const gchar *method_name,
2930 GVariant *parameters,
2931 GDBusMethodInvocation *invocation,
2936 INFO("method %s", method_name);
2937 INFO("object_path %s", object_path);
2938 int ret = BT_HFP_AGENT_ERROR_NONE;
2940 const gchar *device_path = NULL;
2942 if (g_strcmp0(method_name, "NewConnection") == 0) {
2946 GUnixFDList *fd_list;
2947 GVariant *options = NULL;
2948 int device_count = 0;
2950 device_count = g_slist_length(active_devices);
2952 INFO("device_count %d", device_count);
2954 if (device_count >= MAX_CONNECTED_DEVICES) {
2955 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2959 g_variant_get(parameters, "(oha{sv})",
2960 &device_path, &index, &options);
2962 #if defined(TIZEN_SUPPORT_DUAL_HF) && defined(TIZEN_PROFILE_WEARABLE)
2964 * Below code is not required for dual HF support for
2968 __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
2969 INFO("not allow to connect 2nd HF connection");
2970 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2974 msg = g_dbus_method_invocation_get_message(invocation);
2975 fd_list = g_dbus_message_get_unix_fd_list(msg);
2976 if (fd_list == NULL) {
2977 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2981 fd = g_unix_fd_list_get(fd_list, index, NULL);
2983 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2987 DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
2989 if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
2990 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2994 g_dbus_method_invocation_return_value(invocation, NULL);
2995 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
2998 g_variant_get(parameters, "(o)", &device_path);
2999 INFO("device_path %s", device_path);
3001 for (l = active_devices; l; l = l->next) {
3002 bt_ag_info_t *data = l->data;
3004 INFO("data->path %s", data->path);
3005 if (g_strcmp0(data->path, device_path) == 0) {
3006 if (!__bt_ag_agent_connection_release(data)) {
3007 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3010 INFO_C("Disconnected [AG role] [Terminated by local host]");
3011 g_dbus_method_invocation_return_value(invocation, NULL);
3014 } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
3016 gchar *address = NULL;
3017 g_variant_get(parameters, "(&s&s)", &path, &address);
3018 /*local_addr = malloc(strlen(address));
3019 memcpy(local_addr, address, strlen(address));*/
3021 DBG("Sender = %s, Application path = %s\n", sender, path);
3022 ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
3027 local_addr = g_strdup(address);
3028 DBG("Address = %s\n", local_addr);
3029 g_dbus_method_invocation_return_value(invocation, NULL);
3030 } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
3032 g_variant_get(parameters, "(&s)", &path);
3034 DBG("Application path = %s\n", path);
3035 DBG("Sender = %s\n", sender);
3037 ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
3041 g_dbus_method_invocation_return_value(invocation, NULL);
3042 } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
3044 gchar *number = NULL;
3047 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3049 DBG("Application path = %s", path);
3050 DBG_SECURE("Phone number = %s", number);
3051 DBG("Call id = %d", call_id);
3053 DBG("Sender = %s", sender);
3055 ret = _bt_hfp_incoming_call(path, number, call_id, sender);
3058 g_dbus_method_invocation_return_value(invocation, NULL);
3059 } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
3061 gchar *number = NULL;
3064 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3066 DBG("Application path = %s", path);
3067 DBG_SECURE("Phone number = %s", number);
3068 DBG("Call id = %d", call_id);
3070 DBG("Sender = %s", sender);
3072 ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
3075 g_dbus_method_invocation_return_value(invocation, NULL);
3076 } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
3078 gchar *number = NULL;
3083 g_variant_get(parameters, "(&s&sii)",
3084 &path, &number, &status, &call_id);
3085 DBG("Application path = %s\n", path);
3086 DBG_SECURE("Number = %s\n", number);
3087 DBG("Status = %d\n", status);
3088 DBG("Call id = %d\n", call_id);
3089 DBG("Sender = %s\n", sender);
3091 ret = _bt_hfp_change_call_status(path,
3092 number, status, call_id, sender);
3094 if (_bt_hfp_is_call_exist() == FALSE) {
3095 for (l = active_devices; l; l = l->next) {
3096 bt_ag_info_t *data = l->data;
3098 if (data->state == HEADSET_STATE_ON_CALL) {
3099 __bt_ag_close_sco(data);
3100 _bt_ag_set_headset_state(data,
3101 HEADSET_STATE_CONNECTED);
3108 g_dbus_method_invocation_return_value(invocation, NULL);
3109 } else if (g_strcmp0(method_name, "GetProperties") == 0) {
3110 GVariantBuilder *builder;
3112 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3115 gchar *codec = g_strdup("codec");
3116 gchar *nrec = g_strdup("nrec");
3118 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3120 g_variant_builder_add(builder, "{sv}",
3121 codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
3122 g_variant_builder_add(builder, "{sv}",
3123 nrec, g_variant_new("b", bt_ag_info->nrec_status));
3125 var_data = g_variant_new("(a{sv})", builder);
3126 g_variant_builder_unref(builder);
3127 g_dbus_method_invocation_return_value(invocation, var_data);
3132 } else if (g_strcmp0(method_name, "Disconnect") == 0) {
3133 char hdset_address[18] = { 0, };
3136 for (l = active_devices; l; l = l->next) {
3137 bt_ag_info_t *data = l->data;
3139 __bt_convert_addr_type_to_rev_string(hdset_address,
3140 (unsigned char *)data->remote_addr);
3142 DBG("Disconnect Headset %s, %s\n",
3143 hdset_address, data->path);
3144 _bt_ag_set_headset_state(data,
3145 HEADSET_STATE_DISCONNECTED);
3147 g_dbus_method_invocation_return_value(invocation, NULL);
3148 } else if (g_strcmp0(method_name, "IsConnected") == 0) {
3149 gboolean is_connected = FALSE;
3152 for (l = active_devices; l; l = l->next) {
3153 bt_ag_info_t *data = l->data;
3155 if (data->state == HEADSET_STATE_CONNECTED)
3156 is_connected = TRUE;
3158 DBG("is_connected : %s",
3159 is_connected ? "Connected" : "Disconnected");
3161 g_dbus_method_invocation_return_value(invocation,
3162 g_variant_new("(b)", is_connected));
3163 } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
3166 if (0 == g_slist_length(active_devices)) {
3167 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3171 if (ag.ring_timer) {
3172 DBG("IndicateCall received when already indicating");
3173 g_dbus_method_invocation_return_value(invocation, NULL);
3176 for (l = active_devices; l; l = l->next) {
3177 bt_ag_info_t *data = l->data;
3179 if (data->state >= HEADSET_STATE_CONNECTED)
3180 _bt_ag_send_at(data, "\r\nRING\r\n");
3183 __bt_ring_timer_cb(NULL);
3184 ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
3185 __bt_ring_timer_cb, NULL);
3186 g_dbus_method_invocation_return_value(invocation, NULL);
3187 } else if (g_strcmp0(method_name, "CancelCall") == 0) {
3188 if (0 == g_slist_length(active_devices)) {
3189 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3193 if (ag.ring_timer) {
3194 g_source_remove(ag.ring_timer);
3197 DBG("Got CancelCall method call but no call is active");
3199 g_dbus_method_invocation_return_value(invocation, NULL);
3200 } else if (g_strcmp0(method_name, "Play") == 0) {
3201 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3202 bt_ag_slconn_t *slconn = NULL;
3205 slconn = bt_ag_info->slc;
3207 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3211 #ifndef __TIZEN_OPEN__
3214 if (slconn && FALSE == slconn->is_voice_recognition_running &&
3215 mdm_get_service() == MDM_RESULT_SUCCESS) {
3216 mode = mdm_get_allow_bluetooth_outgoing_call();
3217 mdm_release_service();
3219 if (mode == MDM_RESTRICTED) {
3220 ERR("[MDM] Not allow the outgoing call");
3221 ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
3228 switch (bt_ag_info->state) {
3229 case HEADSET_STATE_CONNECTING:
3230 case HEADSET_STATE_DISCONNECTED:
3231 ERR("HEADSET_STATE ERROR");
3232 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3234 case HEADSET_STATE_CONNECTED:
3236 case HEADSET_STATE_PLAY_IN_PROGRESS:
3237 ERR("Play In Progress");
3238 ret = BT_HFP_AGENT_ERROR_BUSY;
3246 if (sco_open_timer_id > 0) {
3247 INFO("SCO open delay");
3248 sco_open_request = TRUE;
3249 g_dbus_method_invocation_return_value(invocation, NULL);
3253 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
3254 (slconn && (slconn->hs_features &
3255 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
3256 switch (bt_ag_info->codec_info.final_codec) {
3257 case BT_CVSD_CODEC_ID:
3258 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
3259 ret = __bt_ag_sco_connect(bt_ag_info);
3261 case BT_MSBC_CODEC_ID:
3262 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
3263 ret = __bt_ag_sco_connect(bt_ag_info);
3266 ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
3270 ret = __bt_ag_sco_connect(bt_ag_info);
3276 sco_owner = g_strdup(sender);
3278 g_dbus_method_invocation_return_value(invocation, NULL);
3280 name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
3281 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
3282 __bt_ag_name_owner_changed_cb, NULL, NULL);
3283 } else if (g_strcmp0(method_name, "Stop") == 0) {
3286 for (l = active_devices; l; l = l->next) {
3287 bt_ag_info_t *data = l->data;
3289 if (data->state > HEADSET_STATE_CONNECTED) {
3290 __bt_ag_close_sco(data);
3291 _bt_ag_set_headset_state(data,
3292 HEADSET_STATE_CONNECTED);
3296 g_dbus_method_invocation_return_value(invocation, NULL);
3297 } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
3298 gboolean is_playing = FALSE;
3301 for (l = active_devices; l; l = l->next) {
3302 bt_ag_info_t *data = l->data;
3304 if (data->state == HEADSET_STATE_ON_CALL)
3307 DBG("is_playing : %s", is_playing ? "Playing" : "Not Playing");
3309 g_dbus_method_invocation_return_value(invocation,
3310 g_variant_new("(b)", is_playing));
3311 } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
3312 bt_ag_slconn_t *slconn = NULL;
3313 guint16 gain_value = 0;
3314 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3316 if (bt_ag_info == NULL) {
3317 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3321 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3322 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3326 slconn = bt_ag_info->slc;
3328 gain_value = (guint16) slconn->speaker_gain;
3330 g_dbus_method_invocation_return_value(invocation,
3331 g_variant_new("(q)", gain_value));
3332 } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
3334 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3336 g_variant_get(parameters, "(q)", &gain);
3337 DBG("Speaker gain = %d\n", gain);
3339 if (bt_ag_info == NULL) {
3340 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3344 ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
3347 g_dbus_method_invocation_return_value(invocation, NULL);
3348 } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
3349 bt_ag_slconn_t *slconn = NULL;
3350 guint16 gain_value = 0;
3351 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3353 if (bt_ag_info == NULL) {
3354 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3358 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3359 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3363 slconn = bt_ag_info->slc;
3365 gain_value = (guint16) slconn->microphone_gain;
3367 g_dbus_method_invocation_return_value(invocation,
3368 g_variant_new("(q)", gain_value));
3369 } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
3371 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3373 g_variant_get(parameters, "(q)", &gain);
3374 DBG("Microphone gain = %d\n", gain);
3376 if (bt_ag_info == NULL) {
3377 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3381 ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
3384 g_dbus_method_invocation_return_value(invocation, NULL);
3385 } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
3386 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3387 if (bt_ag_info == NULL) {
3388 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3392 bt_ag_slconn_t *slconn = bt_ag_info->slc;
3395 g_variant_get(parameters, "(b)", &enable);
3396 DBG("VoiceDail enable = %d\n", enable);
3398 if ((slconn && !(slconn->hs_features &
3399 BT_HF_FEATURE_VOICE_RECOGNITION)))
3400 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3401 else if (bt_ag_info->vr_blacklisted)
3402 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3404 ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
3407 slconn->is_voice_recognition_running = enable;
3411 g_dbus_method_invocation_return_value(invocation, NULL);
3412 } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
3414 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3415 if (bt_ag_info == NULL) {
3416 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3420 g_variant_get(parameters, "(&s)", &cmd);
3422 ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
3426 DBG("vendor cmd = %s", cmd);
3428 ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
3431 g_dbus_method_invocation_return_value(invocation, NULL);
3432 } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
3433 DBG("Already pass dbus SMACK for bt-service::platform");
3434 /* Return success */
3435 g_dbus_method_invocation_return_value(invocation, NULL);
3436 } else if (g_strcmp0(method_name, "SwapHeadset") == 0) {
3439 char address[BT_ADDRESS_STRING_SIZE];
3440 char remote_addr[BT_ADDRESS_STRING_SIZE];
3441 gboolean device_found = FALSE;
3443 g_variant_get(parameters, "(s)", &addr);
3444 g_strlcpy(address, addr, sizeof(address));
3445 DBG("Sender = %s", sender);
3447 /* Loop through connected headset list
3448 * If found, update the remote_dev_path.
3450 for (l = active_devices ; l; l = l->next) {
3451 bt_ag_info_t *data = l->data;
3452 g_strlcpy(remote_addr, data->remote_addr, sizeof(remote_addr));
3453 if (g_strcmp0(remote_addr, address) == 0) {
3454 DBG("Active device found");
3455 if (data->path == NULL) {
3456 DBG("device path is null");
3457 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3460 remote_dev_path = g_strdup(data->path);
3461 DBG("Setting device path %s as active device path", remote_dev_path);
3462 device_found = TRUE;
3467 if (!device_found) {
3468 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3472 g_dbus_method_invocation_return_value(invocation, NULL);
3479 err = __bt_ag_agent_set_error(ret);
3480 g_dbus_method_invocation_return_gerror(invocation, err);
3485 static const GDBusInterfaceVTable method_table = {
3486 __bt_ag_agent_method,
3491 static GDBusNodeInfo *__bt_ag_create_method_node_info
3492 (const gchar *introspection_data)
3495 GDBusNodeInfo *node_info = NULL;
3497 if (introspection_data == NULL)
3500 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
3503 ERR("Unable to create node: %s", err->message);
3504 g_clear_error(&err);
3509 static GDBusConnection *__bt_ag_get_gdbus_connection(void)
3515 if (ag_dbus_conn == NULL)
3516 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
3518 if (!ag_dbus_conn) {
3520 ERR("Unable to connect to dbus: %s", err->message);
3521 g_clear_error(&err);
3527 return ag_dbus_conn;
3530 static gboolean __bt_ag_register_profile_methods(void)
3533 GError *error = NULL;
3535 GDBusNodeInfo *node_info = NULL;
3538 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
3540 G_BUS_NAME_OWNER_FLAGS_NONE,
3544 DBG("owner_id is [%d]", owner_id);
3546 node_info = __bt_ag_create_method_node_info(
3547 ag_agent_bluez_introspection_xml);
3548 if (node_info == NULL)
3551 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3552 DBG("path is [%s]", path);
3554 hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3555 node_info->interfaces[0],
3557 NULL, NULL, &error);
3558 if (hf_bluez_id == 0) {
3559 ERR("Failed to register: %s", error->message);
3560 g_error_free(error);
3562 g_dbus_node_info_unref(node_info);
3567 /* Ag register profile methods for HSP*/
3569 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
3570 DBG("path is [%s]", path);
3572 hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3573 node_info->interfaces[0],
3575 NULL, NULL, &error);
3576 if (hs_bluez_id == 0) {
3577 ERR("Failed to register: %s", error->message);
3578 g_error_free(error);
3580 g_dbus_node_info_unref(node_info);
3584 g_dbus_node_info_unref(node_info);
3586 node_info = __bt_ag_create_method_node_info
3587 (ag_agent_app_introspection_xml);
3588 if (node_info == NULL)
3591 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3592 DBG("path is [%s]", path);
3594 app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3595 node_info->interfaces[0],
3597 NULL, NULL, &error);
3599 ERR("Failed to register: %s", error->message);
3600 g_error_free(error);
3602 g_dbus_node_info_unref(node_info);
3606 g_dbus_node_info_unref(node_info);
3612 static void __bt_ag_unregister_profile_methods(void)
3616 if (hf_bluez_id > 0) {
3617 g_dbus_connection_unregister_object(ag_dbus_conn,
3622 if (hs_bluez_id > 0) {
3623 g_dbus_connection_unregister_object(ag_dbus_conn,
3629 g_dbus_connection_unregister_object(ag_dbus_conn,
3635 static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
3636 const gchar *path, const gchar *interface)
3638 return (service_gproxy) ? service_gproxy :
3639 __bt_ag_gdbus_init_service_proxy(service,
3643 static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
3644 char *profile_uuid, const char* profile_name)
3649 GError *error = NULL;
3650 GVariantBuilder *builder;
3652 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3653 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3658 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3660 g_variant_builder_add(builder, "{sv}",
3661 "Name", g_variant_new("s",
3663 g_variant_builder_add(builder, "{sv}",
3664 "Version", g_variant_new("q", profile_version));
3665 /*g_variant_builder_add(builder, "{sv}",
3666 "Role", g_variant_new("s","client"));*/
3667 if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
3668 g_variant_builder_add(builder, "{sv}",
3669 "features", g_variant_new("q", ag.sdp_features));
3672 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3673 g_variant_new("(osa{sv})", path,
3674 profile_uuid, builder),
3675 G_DBUS_CALL_FLAGS_NONE, -1,
3677 g_variant_builder_unref(builder);
3678 /* set the name and role for the profile*/
3680 /* dBUS-RPC is failed */
3681 ERR("dBUS-RPC is failed");
3683 if (error != NULL) {
3684 /* dBUS gives error cause */
3685 ERR("D-Bus API failure: errCode[%x], message[%s]",
3686 error->code, error->message);
3688 g_clear_error(&error);
3693 g_variant_unref(ret);
3700 static void __bt_ag_agent_unregister(gchar *path)
3705 GError *error = NULL;
3707 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3708 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3713 ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
3714 g_variant_new("(o)", path),
3715 G_DBUS_CALL_FLAGS_NONE, -1,
3718 /* set the name and role for the profile*/
3720 /* dBUS-RPC is failed */
3721 ERR("dBUS-RPC is failed");
3723 if (error != NULL) {
3724 /* dBUS gives error cause */
3725 ERR("D-Bus API failure: errCode[%x], message[%s]",
3726 error->code, error->message);
3728 g_clear_error(&error);
3732 g_variant_unref(ret);
3742 static void __bt_ag_agent_battery_status_cb(keynode_t *node)
3744 int batt = vconf_keynode_get_int(node);
3746 _bt_hfp_set_property_value("BatteryBarsChanged", batt);
3749 static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
3751 int signal_bar = vconf_keynode_get_int(node);
3753 BT_CHECK_SIGNAL_STRENGTH(signal_bar);
3754 _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
3757 #ifdef TIZEN_FEATURE_BT_LUNAR_DEVICE
3758 static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
3760 gboolean status = vconf_keynode_get_bool(node);
3762 DBG("status = %d", status);
3764 if (status == TRUE) {
3765 for (l = active_devices; l; l = l->next) {
3766 bt_ag_info_t *data = l->data;
3767 _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
3773 static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
3775 int service = vconf_keynode_get_int(node);
3776 bt_hfp_agent_network_registration_status_t network_service;
3780 DBG("Current Signal Level = [%d] \n", service);
3783 case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
3784 case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
3785 case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
3793 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
3795 ERR("Get roaming status failed err = %d\n", ret);
3799 if (roam_status == 0 && service == 1)
3800 network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
3801 else if (roam_status == 1 && service == 1)
3802 network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
3804 network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
3806 _bt_hfp_set_property_value("RegistrationChanged", network_service);
3809 static void __bt_ag_agent_subscribe_vconf_updates(void)
3815 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3816 (void *)__bt_ag_agent_battery_status_cb, NULL);
3818 ERR("Subsrciption to battery status failed err = [%d]\n", ret);
3820 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
3821 (void *)__bt_ag_agent_network_signal_status_cb, NULL);
3823 ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
3825 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3826 (void *)__bt_ag_agent_network_register_status_cb, NULL);
3828 ERR("Subsrciption to network failed err = [%d]\n", ret);
3830 #ifdef TIZEN_FEATURE_BT_LUNAR_DEVICE
3831 ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
3832 (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
3834 ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
3839 static void __bt_ag_agent_release_vconf_updates(void)
3845 ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3846 (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
3848 ERR("vconf_ignore_key_changed failed\n");
3850 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
3851 (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
3853 ERR("vconf_ignore_key_changed failed\n");
3855 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3856 (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
3858 ERR("vconf_ignore_key_changed failed\n");
3861 static gboolean __bt_ag_agent_send_subscriber_number_changed(
3864 const char *property = g_strdup("SubscriberNumberChanged");
3868 DBG("Number is %s", number);
3870 if (!_bt_hfp_set_property_name(property, number)) {
3871 DBG("Error- set property for subscriber no change - ERROR\n");
3872 g_free((void *)property);
3875 g_free((void *)property);
3879 static void __bt_ag_agent_sigterm_handler(int signo)
3884 ERR_C("***** Signal handler came with signal %d *****", signo);
3886 for (l = active_devices ; l; l = l->next) {
3887 bt_ag_info_t *data = l->data;
3888 if (!__bt_ag_agent_connection_release(data))
3889 ERR("__bt_ag_agent_connection_release failed");
3892 g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
3895 g_main_loop_quit(gmain_loop);
3899 INFO("Terminating AG agent");
3903 if (signo == SIGTERM)
3906 for (i = 0; i < BT_AG_SIG_NUM; i++)
3907 sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
3912 static void __bt_ag_agent_tel_cb(TapiHandle *handle,
3917 TelSimMsisdnList_t *number;
3918 gchar *subscriber_number;
3920 ERR("*********** result = %d", result);
3922 if (result == TAPI_API_SIM_LOCKED ||
3923 result == TAPI_API_SIM_NOT_INITIALIZED ||
3924 result == TAPI_API_SERVICE_NOT_READY) {
3925 DBG("initializing the tapi event for SIM status");
3926 __bt_ag_agent_reg_sim_event(handle, user_data);
3933 number = (TelSimMsisdnList_t *)data;
3934 subscriber_number = g_strdup(number->list[0].num);
3935 __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
3936 g_free(subscriber_number);
3939 static void __bt_ag_agent_on_noti_sim_status(TapiHandle *handle,
3940 const char *noti_id, void *data, void *user_data)
3942 TelSimCardStatus_t *status = data;
3945 DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
3947 if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
3948 __bt_ag_agent_dereg_sim_event(handle);
3949 tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
3951 if (tapi_result != TAPI_API_SUCCESS)
3952 ERR("Fail to get sim info: %d", tapi_result);
3956 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data)
3959 ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
3960 __bt_ag_agent_on_noti_sim_status, user_data);
3962 if (ret != TAPI_API_SUCCESS)
3963 ERR("event register failed(%d)", ret);
3966 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle)
3969 ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
3971 if (ret != TAPI_API_SUCCESS)
3972 ERR("event deregister failed(%d)", ret);
3975 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
3976 const gchar *sender_name,
3977 const gchar *object_path,
3978 const gchar *interface_name,
3979 const gchar *signal_name,
3980 GVariant *parameters,
3984 char *name_owner = NULL;
3985 char *old_owner = NULL;
3986 char *new_owner = NULL;
3988 if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
3991 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
3993 _bt_hfp_release_all_calls_by_sender(name_owner);
3995 if (sco_owner == NULL)
3998 if (strcasecmp(name_owner, sco_owner) == 0) {
3999 if (name_owner_sig_id != -1)
4000 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4002 name_owner_sig_id = -1;
4006 for (l = active_devices ; l; l = l->next) {
4007 bt_ag_info_t *data = l->data;
4010 __bt_ag_close_sco(data);
4011 _bt_ag_set_headset_state(data,
4012 HEADSET_STATE_CONNECTED);
4019 static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
4020 const gchar *sender_name,
4021 const gchar *object_path,
4022 const gchar *interface_name,
4023 const gchar *signal_name,
4024 GVariant *parameters,
4029 GVariant *optional_param = NULL;
4031 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
4033 g_variant_get(parameters, "(&o@a{sa{sv}})",
4034 &path, &optional_param);
4037 g_variant_unref(optional_param);
4038 ERR("Invalid adapter path");
4042 INFO("Adapter Path = [%s]", path);
4043 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4044 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4045 __bt_ag_agent_register(path, hfp_ver,
4046 HFP_AG_UUID, "Hands-Free Audio Gateway");
4048 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4049 __bt_ag_agent_register(path, hsp_ver,
4050 HSP_AG_UUID, "Headset Audio Gateway");
4052 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
4053 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
4056 g_variant_unref(optional_param);
4057 ERR("Invalid adapter path");
4061 INFO("Adapter Path = [%s]", path);
4062 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4063 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4064 __bt_ag_agent_unregister(path);
4066 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4067 __bt_ag_agent_unregister(path);
4072 g_variant_unref(optional_param);
4077 static void __bt_ag_agent_dbus_deinit(void)
4080 if (service_gproxy) {
4081 g_object_unref(service_gproxy);
4082 service_gproxy = NULL;
4086 g_object_unref(app_gproxy);
4091 __bt_ag_unregister_profile_methods();
4093 if (owner_sig_id != -1)
4094 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4097 if (name_owner_sig_id != -1)
4098 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4100 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4101 if (media_sig_id != -1)
4102 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4105 if (media_state_sig_id != -1)
4106 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4107 media_state_sig_id);
4109 name_owner_sig_id = -1;
4113 g_object_unref(ag_dbus_conn);
4114 ag_dbus_conn = NULL;
4119 static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
4122 GDBusProxy *manager_proxy = NULL;
4123 GVariant *result = NULL;
4124 char *adapter_path = NULL;
4127 return BT_HFP_AGENT_ERROR_INTERNAL;
4129 manager_proxy = g_dbus_proxy_new_sync(conn,
4130 G_DBUS_PROXY_FLAGS_NONE, NULL,
4133 BT_MANAGER_INTERFACE,
4136 if (!manager_proxy) {
4137 ERR("Unable to create proxy: %s", err->message);
4141 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
4142 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
4145 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
4147 ERR("Fail to get DefaultAdapter");
4152 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
4153 ERR("Incorrect result\n");
4157 g_variant_get(result, "(&o)", &adapter_path);
4159 if (adapter_path == NULL ||
4160 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
4161 ERR("Adapter path is inproper\n");
4166 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
4168 g_variant_unref(result);
4169 g_object_unref(manager_proxy);
4174 g_clear_error(&err);
4177 g_variant_unref(result);
4180 g_object_unref(manager_proxy);
4182 return BT_HFP_AGENT_ERROR_INTERNAL;
4186 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4187 void _bt_ag_agent_check_transport_state(void)
4191 if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
4195 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
4196 G_DBUS_PROXY_FLAGS_NONE, NULL,
4197 "org.PulseAudio2", A2DP_SOURCE_ENDPOINT,
4198 BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
4202 ERR("Unable to create proxy: %s", err->message);
4203 g_clear_error(&err);
4207 INFO_C("SuspendMedia initiated");
4209 g_dbus_proxy_call(proxy,
4210 "SuspendMedia", NULL,
4211 G_DBUS_CALL_FLAGS_NONE, 2000,
4213 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4219 static void __bt_ag_agent_transport_state_update(const char *value)
4222 if (!g_strcmp0(value, "idle"))
4223 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4224 else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
4225 transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
4227 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4229 INFO_C("transport_state %d", transport_state);
4232 static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
4233 const gchar *sender_name,
4234 const gchar *object_path,
4235 const gchar *interface_name,
4236 const gchar *signal_name,
4237 GVariant *parameters,
4242 GVariant *dict_param = NULL;
4243 GVariant *optional_param = NULL;
4245 if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
4246 if (g_strcmp0(g_variant_get_type_string(parameters),
4248 ERR("Incorrect parameters\n");
4252 g_variant_get(parameters, "(&s@a{sv}@as)",
4253 &inter, &dict_param, &optional_param);
4254 if (dict_param && (!g_strcmp0(inter,
4255 BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
4256 GVariantIter *iter = NULL;
4257 const gchar *key = NULL;
4258 GVariant *value_var = NULL;
4259 gchar *value = NULL;
4260 g_variant_get(dict_param, "a{sv}", &iter);
4261 while (g_variant_iter_loop(
4262 iter, "{sv}", &key, &value_var)) {
4264 if (g_strcmp0(key, "State") == 0) {
4265 value = (gchar *)g_variant_get_string(
4268 DBG("value %s", value);
4269 __bt_ag_agent_transport_state_update(value);
4273 g_variant_iter_free(iter);
4274 g_variant_unref(dict_param);
4276 } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
4277 char *profile_uuid = NULL;
4280 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
4281 if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
4282 (state == BT_PROFILE_STATE_DISCONNECTED)) {
4283 DBG("Updating the transport state");
4284 __bt_ag_agent_transport_state_update("Disconnect");
4289 g_variant_unref(dict_param);
4292 g_variant_unref(optional_param);
4297 static void __bt_ag_agent_dbus_init(void)
4301 if (__bt_ag_get_gdbus_connection() == NULL) {
4302 ERR("Error in creating the gdbus connection\n");
4305 if (!__bt_ag_register_profile_methods()) {
4306 ERR("Error in HFP / HSP register_profile_methods\n");
4310 if (!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
4312 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4313 __bt_ag_agent_register(path, hfp_ver,
4314 HFP_AG_UUID, "Hands-Free Audio Gateway");
4316 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4317 __bt_ag_agent_register(path, hsp_ver,
4318 HSP_AG_UUID, "Headset Audio Gateway");
4321 owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4322 NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
4323 __bt_ag_agent_filter_cb, NULL, NULL);
4324 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4325 media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4326 NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
4327 NULL, 0, __bt_ag_agent_media_filter_cb,
4330 media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4331 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
4332 NULL, 0, __bt_ag_agent_media_filter_cb,
4335 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4341 static uint32_t __bt_ag_agent_get_ag_features(void)
4344 uint32_t ag_features = BT_AG_FEATURE_EC_AND_NR |
4345 BT_AG_FEATURE_REJECT_CALL |
4346 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4347 BT_AG_FEATURE_THREE_WAY_CALL |
4348 #ifndef TIZEN_FEATURE_BT_KIRAN_DEVICE
4349 BT_AG_FEATURE_VOICE_RECOGNITION |
4351 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4354 #if defined(TIZEN_FEATURE_BT_HFP_AG)
4355 hfp_ver = HFP_VERSION_1_6;
4357 hfp_ver = HFP_VERSION_1_5;
4359 hsp_ver = HSP_VERSION_1_2;
4361 if (hfp_ver == HFP_VERSION_1_6)
4362 ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
4366 void *__bt_ag_agent_telephony_init(void *arg)
4370 uint32_t ag_features = *((uint32_t *)arg);
4372 INFO_C("Initializing the telephony info");
4374 _bt_hfp_initialize_telephony_manager(ag_features);
4375 __bt_ag_agent_subscribe_vconf_updates();
4377 tapi_handle = tel_init(NULL);
4378 tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
4380 if (tapi_result != TAPI_API_SUCCESS)
4381 ERR("Fail to get sim info: %d", tapi_result);
4388 uint32_t ag_features;
4389 struct sigaction sa;
4390 pthread_t thread_id;
4392 INFO_C("### Starting Bluetooth AG agent");
4394 ag_features = __bt_ag_agent_get_ag_features();
4396 ag.sdp_features = (uint16_t) ag_features & 0x1F;
4398 if (hfp_ver == HFP_VERSION_1_6 && wbs_en == TRUE)
4399 ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
4401 memset(&sa, 0, sizeof(sa));
4402 sa.sa_flags = SA_NOCLDSTOP;
4403 sa.sa_handler = __bt_ag_agent_sigterm_handler;
4405 for (i = 0; i < BT_AG_SIG_NUM; i++)
4406 sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
4408 gmain_loop = g_main_loop_new(NULL, FALSE);
4410 if (gmain_loop == NULL) {
4411 ERR("GMainLoop create failed");
4412 return EXIT_FAILURE;
4415 __bt_ag_agent_dbus_init();
4416 if (pthread_create(&thread_id, NULL,
4417 (void *)&__bt_ag_agent_telephony_init,
4418 &ag_features) < 0) {
4419 ERR("pthread_create() is failed");
4420 return EXIT_FAILURE;
4423 if (pthread_detach(thread_id) < 0)
4424 ERR("pthread_detach() is failed");
4426 g_main_loop_run(gmain_loop);
4430 tel_deinit(tapi_handle);
4432 __bt_ag_agent_dbus_deinit();
4433 _bt_hfp_deinitialize_telephony_manager();
4434 __bt_ag_agent_release_vconf_updates();
4436 if (remote_dev_path)
4437 g_free(remote_dev_path);
4440 g_main_loop_unref(gmain_loop);
4442 INFO_C("### Terminating Bluetooth AG agent");