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"
32 #include "bluetooth-agent-profile.h"
34 #include <TapiUtility.h>
36 #include <ITapiModem.h>
37 #include <TelNetwork.h>
40 #include <system_info.h>
45 static GMainLoop *gmain_loop = NULL;
46 static GDBusProxy *service_gproxy;
47 static guint interface_added_sig_id = 0;
48 static guint interface_removed_sig_id = 0;
49 static guint name_owner_sig_id = 0;
50 GDBusConnection *ag_dbus_conn = NULL;
51 gchar *remote_dev_path = NULL;
55 static TapiHandle *tapi_handle;
56 extern wbs_options wbs_opts;
57 GSList *active_devices = NULL;
58 static gchar *local_addr = NULL;
59 static GDBusProxy *app_gproxy;
60 static gboolean call_launch_requested = FALSE;
61 static gchar* sco_owner = NULL;
62 static guint sco_open_timer_id = 0;
63 static gboolean sco_open_request = FALSE;
64 static guint hf_bluez_id;
65 static guint hs_bluez_id;
67 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
68 static guint media_sig_id = 0;
69 static guint media_state_sig_id = 0;
70 static bt_ag_media_transport_state_t transport_state;
73 #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
74 #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
75 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
76 #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
78 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
79 #define VCONF_KEY_BT_LUNAR_ENABLED "db/wms/bt_loop_device_hfp_connected"
81 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
82 #define CALL_APP_ID "org.tizen.call-ui"
85 #if defined(TIZEN_SUPPORT_DUAL_HF)
86 #define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac"
87 #define MAX_CONNECTED_DEVICES 2
89 #define MAX_CONNECTED_DEVICES 1
92 #define BT_AG_SIG_NUM 3
93 static struct sigaction bt_ag_sigoldact[BT_AG_SIG_NUM];
94 static int bt_ag_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
96 /*Below Inrospection data is exposed to bluez from agent*/
97 static const gchar ag_agent_bluez_introspection_xml[] =
99 " <interface name='org.bluez.Profile1'>"
100 " <method name='NewConnection'>"
101 " <arg type='o' name='device' direction='in'/>"
102 " <arg type='h' name='fd' direction='in'/>"
103 " <arg type='a{sv}' name='options' direction='in'/>"
105 " <method name='RequestDisconnection'>"
106 " <arg type='o' name='device' direction='in'/>"
111 /*Below Introspection data is exposed to application from agent*/
112 static const gchar ag_agent_app_introspection_xml[] =
114 " <interface name='Org.Hfp.App.Interface'>"
115 " <method name='RegisterApplication'>"
116 " <arg type='s' name='path' direction='in'/>"
117 " <arg type='s' name='address' direction='in'/>"
119 " <method name='UnregisterApplication'>"
120 " <arg type='s' name='path' direction='in'/>"
122 " <method name='IncomingCall'>"
123 " <arg type='s' name='path' direction='in'/>"
124 " <arg type='s' name='number' direction='in'/>"
125 " <arg type='i' name='id' direction='in'/>"
127 " <method name='OutgoingCall'>"
128 " <arg type='s' name='path' direction='in'/>"
129 " <arg type='s' name='number' direction='in'/>"
130 " <arg type='i' name='id' direction='in'/>"
132 " <method name='ChangeCallStatus'>"
133 " <arg type='s' name='path' direction='in'/>"
134 " <arg type='s' name='number' direction='in'/>"
135 " <arg type='i' name='status' direction='in'/>"
136 " <arg type='i' name='id' direction='in'/>"
138 " <method name='GetProperties'>"
139 " <arg type='a{sv}' name='properties' direction='out'/>"
141 " <method name='Disconnect'>"
143 " <method name='IsConnected'>"
144 " <arg type='b' name='connected' direction='out'/>"
146 " <method name='IndicateCall'>"
148 " <method name='CancelCall'>"
150 " <method name='Play'>"
152 " <method name='Stop'>"
154 " <method name='IsPlaying'>"
155 " <arg type='b' name='playing' direction='out'/>"
157 " <method name='GetSpeakerGain'>"
158 " <arg type='q' name='gain' direction='out'/>"
160 " <method name='GetMicrophoneGain'>"
161 " <arg type='q' name='gain' direction='out'/>"
163 " <method name='SetSpeakerGain'>"
164 " <arg type='q' name='gain' direction='in'/>"
166 " <method name='SetMicrophoneGain'>"
167 " <arg type='q' name='gain' direction='in'/>"
169 " <method name='SetVoiceDial'>"
170 " <arg type='b' name='enable' direction='in'/>"
172 " <method name='CheckPrivilege'>"
174 " <method name='SwapHeadset'>"
175 " <arg type='s' name='remote_addr' direction='in'/>"
182 int (*callback)(bt_ag_info_t *hs, const char *buf);
185 struct sco_socket_addr {
186 sa_family_t sco_family;
195 bt_ag_info_t *bt_ag_info;
199 bt_ag_status_t ag = {
200 .telephony_ready = FALSE,
204 .rh = BT_RSP_HOLD_NOT_SUPPORTED,
210 static void __bt_ag_agent_sigterm_handler(int signo);
211 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
212 const gchar *object_path);
213 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs);
214 static gboolean __bt_ag_event_handler(GIOChannel *channel, GIOCondition cond,
216 static int __bt_ag_sco_connect(bt_ag_info_t *hs);
217 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state);
218 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data);
219 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle);
220 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
221 const gchar *sender_name,
222 const gchar *object_path,
223 const gchar *interface_name,
224 const gchar *signal_name,
225 GVariant *parameters,
228 static void __bt_convert_addr_type_to_rev_string(char *address,
231 ret_if(address == NULL);
232 ret_if(addr == NULL);
234 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
235 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
236 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
239 static GDBusProxy *__bt_ag_gdbus_init_service_proxy(const gchar *service,
240 const gchar *path, const gchar *interface)
247 if (ag_dbus_conn == NULL)
248 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
252 ERR("Unable to connect to gdbus: %s", err->message);
258 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
259 G_DBUS_PROXY_FLAGS_NONE, NULL,
261 interface, NULL, &err);
265 ERR("Unable to create proxy: %s", err->message);
275 static GDBusProxy *__bt_ag_gdbus_get_app_proxy(const gchar *service,
276 const gchar *path, const gchar *interface)
278 return (app_gproxy) ? app_gproxy :
279 __bt_ag_gdbus_init_service_proxy(service,
283 static int __bt_ag_agent_gdbus_method_send(const char *service,
284 const gchar *path, const char *interface,
285 const char *method, gboolean response,
286 GVariant *parameters)
292 GError *error = NULL;
294 proxy = __bt_ag_gdbus_get_app_proxy(service, path, interface);
296 return BT_HFP_AGENT_ERROR_INTERNAL;
299 ret = g_dbus_proxy_call_sync(proxy,
301 G_DBUS_CALL_FLAGS_NONE, -1,
304 /* dBUS-RPC is failed */
305 ERR("dBUS-RPC is failed");
307 /* dBUS gives error cause */
308 ERR("D-Bus API failure: errCode[%x], message[%s]",
309 error->code, error->message);
311 g_clear_error(&error);
313 return BT_HFP_AGENT_ERROR_INTERNAL;
316 g_variant_unref(ret);
318 g_dbus_proxy_call(proxy,
320 G_DBUS_CALL_FLAGS_NONE, 2000,
323 return BT_HFP_AGENT_ERROR_NONE;
326 gboolean _bt_ag_agent_emit_signal(
327 GDBusConnection *connection,
329 const char *interface,
335 GError *error = NULL;
337 ret = g_dbus_connection_emit_signal(connection,
338 NULL, path, interface,
343 /* dBUS gives error cause */
344 ERR("D-Bus API failure: errCode[%x], message[%s]",
345 error->code, error->message);
346 g_clear_error(&error);
349 INFO_C("Emit Signal done = [%s]", name);
355 gboolean _bt_ag_agent_emit_property_changed(
356 GDBusConnection *connection,
358 const char *interface,
367 var_data = g_variant_new("(sv)", name, property);
369 ret = _bt_ag_agent_emit_signal(connection,
371 "PropertyChanged", var_data);
376 static void __bt_ag_agent_start_watch(bt_ag_info_t *bt_ag_info)
378 bt_ag_info->watch_id = g_io_add_watch(bt_ag_info->io_chan,
379 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
380 (GIOFunc) __bt_ag_event_handler, bt_ag_info);
383 static void __bt_ag_agent_remove_watch(guint *watch_id)
385 DBG("Remove IO watch ID %d", *watch_id);
387 g_source_remove(*watch_id);
392 #if defined(TIZEN_SUPPORT_DUAL_HF)
393 gboolean __bt_ag_agent_is_companion_device(const char *addr)
395 #if defined(TIZEN_PROFILE_WEARABLE)
396 char *host_device_address = NULL;
397 host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR);
399 if (!host_device_address) {
400 INFO("Failed to get a companion device address");
404 if (g_strcmp0(host_device_address, addr) == 0) {
405 INFO("addr[%s] is companion device", addr);
411 /* TODO : Need to add companion device check condition for Phone models */
416 void __bt_convert_device_path_to_address(const gchar *device_path,
417 char *device_address)
419 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
422 ret_if(device_path == NULL);
423 ret_if(device_address == NULL);
425 dev_addr = strstr(device_path, "dev_");
426 if (dev_addr != NULL) {
429 g_strlcpy(address, dev_addr, sizeof(address));
431 while ((pos = strchr(address, '_')) != NULL)
434 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
438 static gboolean __bt_ag_agent_is_companion_device_connected(void)
442 for (l = active_devices ; l; l = l->next) {
443 bt_ag_info_t *data = l->data;
445 if (data->is_companion_device) {
446 DBG("Companion device found");
454 gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
456 char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
457 gboolean is_companion_device;
459 __bt_convert_device_path_to_address(device_path, device_address);
460 is_companion_device = __bt_ag_agent_is_companion_device(device_address);
462 DBG(" device_address[%s]", device_address);
463 DBG(" is_companion_device[%d]", is_companion_device);
465 if (__bt_ag_agent_is_companion_device_connected()) {
466 if (is_companion_device)
469 if (!is_companion_device)
474 #endif /* TIZEN_SUPPORT_DUAL_HF */
476 static gboolean __bt_is_phone_locked(int *phone_lock_state)
481 if (NULL == phone_lock_state)
484 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, phone_lock_state);
486 ERR("Failed to read [%s]\n", VCONFKEY_IDLE_LOCK_STATE);
494 static gboolean __bt_get_outgoing_callapp_type(int *callapp_type)
498 if (NULL == callapp_type)
501 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
502 *callapp_type = BT_VOICE_CALL;
509 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT,
512 ERR("Failed to read [%s]\n",
513 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT);
517 INFO(" [%s] = [%d]\n",
518 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT, *callapp_type);
520 /* The vconf value does not include in platform. */
521 *callapp_type = BT_VOICE_CALL;
527 static gboolean __bt_get_outgoing_call_condition(int *condition)
531 if (NULL == condition)
534 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
535 *condition = BT_MO_ONLY_UNLOCKED;
542 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT,
545 ERR("Failed to read [%s]\n",
546 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT);
550 /* The vconf value does not include in platform. */
551 *condition = BT_MO_ONLY_UNLOCKED;
557 static gboolean __bt_ag_agent_launch_call_app(const char *number)
562 DBG_SECURE("number(%s)", number);
566 ERR("bundle_create() Failed");
570 bundle_add(b, "launch-type", "MO");
571 bundle_add(b, "dial-type", "HEADSET");
573 if (strlen(number) != 0)
574 bundle_add(b, "number", number);
576 aul_launch_app_async(CALL_APP_ID, b);
583 static void *__bt_ag_agent_launch_call_req(void *arg)
586 bundle *b = (bundle *)arg;
587 if (appsvc_run_service(b, 0, NULL, NULL) < 0)
588 ERR("Unable to run app svc");
590 call_launch_requested = FALSE;
595 static gboolean __bt_ag_agent_make_call(const char *number)
599 char telnum[BT_MAX_TEL_NUM_STRING];
603 if (TIZEN_PROFILE_WEARABLE)
604 return __bt_ag_agent_launch_call_app(number);
606 if (call_launch_requested == TRUE) {
607 DBG("Launch request is in progress");
615 appsvc_set_operation(b, APPSVC_OPERATION_CALL);
616 snprintf(telnum, sizeof(telnum), "tel:%s", number);
617 appsvc_set_uri(b, telnum);
618 appsvc_add_data(b, "ctindex", "-1");
620 call_launch_requested = TRUE;
621 if (pthread_create(&thread_id, NULL,
622 (void *)&__bt_ag_agent_launch_call_req,
624 ERR("pthread_create() is failed");
625 call_launch_requested = FALSE;
628 if (pthread_detach(thread_id) < 0)
629 ERR("pthread_detach() is failed");
635 static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
640 kb = bundle_create();
644 bundle_add(kb, "KEY_CALL_TYPE", "MO");
645 bundle_add(kb, "number", mo_number);
646 aul_launch_app("org.tizen.vtmain", kb);
653 gboolean _bt_ag_agent_answer_call(unsigned int call_id,
654 const gchar *path, const gchar *sender)
658 if (path == NULL || sender == NULL) {
659 DBG("Invalid Arguments");
663 DBG("Application path = %s", path);
664 DBG("Call Id = %d", call_id);
665 DBG("Sender = %s", sender);
667 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
668 BT_AG_SERVICE_NAME, "Answer",
669 g_variant_new("(u)", call_id));
674 gboolean _bt_ag_agent_reject_call(unsigned int call_id,
675 const gchar *path, const gchar *sender)
679 if (path == NULL || sender == NULL) {
680 DBG("Invalid Arguments");
684 DBG("Application path = %s", path);
685 DBG("Call Id = %d", call_id);
686 DBG("Sender = %s", sender);
688 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
689 BT_AG_SERVICE_NAME, "Reject",
690 g_variant_new("(u)", call_id));
695 gboolean _bt_ag_agent_release_call(unsigned int call_id,
696 const gchar *path, const gchar *sender)
700 if (path == NULL || sender == NULL) {
701 DBG("Invalid Arguments");
705 DBG("Application path = %s", path);
706 DBG("Call Id = %d", call_id);
707 DBG("Sender = %s", sender);
709 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
710 BT_AG_SERVICE_NAME, "Release",
711 g_variant_new("(u)", call_id));
717 bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
719 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
721 int phone_lock_state;
726 if (number == NULL) {
727 ERR("Invalid Argument");
728 error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
732 DBG("Number = %s", number);
733 DBG("flags = %d", flags);
735 if (!__bt_is_phone_locked(&phone_lock_state)) {
736 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
740 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
741 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
745 if (!__bt_get_outgoing_call_condition(&condition)) {
746 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
750 if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
751 VCONFKEY_IDLE_LOCK) {
752 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
756 if (callapp_type == BT_VIDEO_CALL) {
757 if (!__bt_ag_agent_make_video_call(number)) {
758 ERR("Problem launching application");
759 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
763 if (!__bt_ag_agent_make_call(number)) {
764 ERR("Problem launching application");
765 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
775 bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
777 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
779 contacts_filter_h filter = NULL;
780 contacts_query_h query = NULL;
781 contacts_list_h list = NULL;
782 contacts_record_h record = NULL;
783 unsigned int projections[] = {
784 _contacts_speeddial.number,
789 DBG("location = %d", location);
791 /*Get number from contacts location*/
792 if (contacts_connect() != CONTACTS_ERROR_NONE) {
793 ERR(" contacts_connect failed");
794 return BT_HFP_AGENT_ERROR_INTERNAL;
797 contacts_filter_create(_contacts_speeddial._uri, &filter);
802 if (contacts_filter_add_int(filter,
803 _contacts_speeddial.speeddial_number,
804 CONTACTS_MATCH_EQUAL, location) !=
805 CONTACTS_ERROR_NONE) {
806 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
810 contacts_query_create(_contacts_speeddial._uri, &query);
815 contacts_query_set_filter(query, filter);
817 if (contacts_query_set_projection(query, projections,
818 sizeof(projections)/sizeof(unsigned int)) !=
819 CONTACTS_ERROR_NONE) {
820 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
824 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
825 CONTACTS_ERROR_NONE) {
826 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
830 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
831 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
835 if (contacts_list_get_current_record_p(list, &record) !=
836 CONTACTS_ERROR_NONE) {
837 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
844 if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
845 != CONTACTS_ERROR_NONE) {
846 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
850 if (number == NULL) {
851 ERR("No number at the location");
852 error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
856 DBG("number %s", number);
859 if (!__bt_ag_agent_make_call(number)) {
860 ERR("Problem launching application");
861 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
867 contacts_list_destroy(list, TRUE);
870 contacts_filter_destroy(filter);
873 contacts_query_destroy(query);
875 contacts_disconnect();
882 bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
883 const gchar *path, const gchar *sender)
885 bt_hfp_agent_error_t ret;
889 if (dtmf == NULL || path == NULL || sender == NULL) {
890 ERR("Invalid Argument");
891 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
894 DBG("Dtmf = %s", dtmf);
895 DBG("Application path = %s", path);
896 DBG("Sender = %s", sender);
898 ret = __bt_ag_agent_gdbus_method_send(sender,
899 path, TELEPHONY_APP_INTERFACE,
901 g_variant_new("(s)", dtmf));
906 gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
907 const gchar *path, const gchar *sender)
911 if (path == NULL || sender == NULL) {
912 DBG("Invalid Arguments");
916 DBG("Application path = %s", path);
917 DBG("Value = %d", chld_value);
918 DBG("Sender = %s", sender);
920 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
921 /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
922 if not return FALSE */
923 if (chld_value != 0 && chld_value != 1 && chld_value != 2)
926 if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
930 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
931 BT_AG_SERVICE_NAME, "Threeway",
932 g_variant_new("(u)", chld_value));
937 bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
939 bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
940 char *last_num = NULL;
943 int phone_lock_state;
945 contacts_list_h list = NULL;
946 contacts_query_h query = NULL;
947 contacts_filter_h filter = NULL;
948 contacts_record_h record = NULL;
949 unsigned int projections[] = {
950 _contacts_phone_log.address,
951 _contacts_phone_log.log_type,
956 if (contacts_connect() != CONTACTS_ERROR_NONE) {
957 ERR(" contacts_connect failed");
958 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
962 contacts_filter_create(_contacts_phone_log._uri, &filter);
967 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
968 CONTACTS_MATCH_EQUAL,
969 CONTACTS_PLOG_TYPE_VOICE_OUTGOING) !=
970 CONTACTS_ERROR_NONE) {
971 ERR(" contacts_filter_add_int failed");
972 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
976 if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) !=
977 CONTACTS_ERROR_NONE) {
978 ERR(" contacts_filter_add_operator failed");
979 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
983 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
984 CONTACTS_MATCH_EQUAL,
985 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) !=
986 CONTACTS_ERROR_NONE) {
987 ERR(" contacts_filter_add_int failed");
988 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
992 contacts_query_create(_contacts_phone_log._uri, &query);
997 contacts_query_set_filter(query, filter);
999 if (contacts_query_set_projection(query, projections,
1000 sizeof(projections)/sizeof(unsigned int)) !=
1001 CONTACTS_ERROR_NONE) {
1002 ERR(" contacts_query_set_projection failed");
1003 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1007 if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false)
1008 != CONTACTS_ERROR_NONE) {
1009 ERR(" contacts_query_set_sort failed");
1010 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1014 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
1015 CONTACTS_ERROR_NONE) {
1016 ERR(" contacts_db_get_records_with_query failed");
1017 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1021 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
1022 ERR(" contacts_list_first failed");
1023 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1027 if (contacts_list_get_current_record_p(list, &record) !=
1028 CONTACTS_ERROR_NONE) {
1029 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1036 if (contacts_record_get_str(record, _contacts_phone_log.address,
1037 &last_num) != CONTACTS_ERROR_NONE) {
1038 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1042 if (last_num == NULL) {
1043 ERR("No last number");
1044 err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
1048 if (!__bt_is_phone_locked(&phone_lock_state)) {
1049 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1053 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
1054 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1058 if (!__bt_get_outgoing_call_condition(&condition)) {
1059 ERR(" Failed to get the call condition");
1060 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1064 if (condition == BT_MO_ONLY_UNLOCKED &&
1065 phone_lock_state == VCONFKEY_IDLE_LOCK) {
1066 ERR(" call condition and phone lock state check fail");
1067 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1071 switch (callapp_type) {
1073 if (!__bt_ag_agent_make_call(last_num)) {
1074 ERR("Problem launching application");
1075 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1079 if (!__bt_ag_agent_make_video_call(last_num)) {
1080 ERR("Problem launching application");
1081 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1084 case BT_FOLLOW_CALL_LOG:
1085 if (contacts_record_get_int(record,
1086 _contacts_phone_log.log_type,
1087 &type) != CONTACTS_ERROR_NONE) {
1088 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1091 if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
1092 if (!__bt_ag_agent_make_call(last_num)) {
1093 ERR("Problem launching application");
1094 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1096 } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
1097 if (!__bt_ag_agent_make_video_call(last_num)) {
1098 ERR("Problem launching application");
1099 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1102 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1106 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1113 contacts_list_destroy(list, TRUE);
1116 contacts_filter_destroy(filter);
1119 contacts_query_destroy(query);
1121 contacts_disconnect();
1123 if (last_num != NULL)
1131 bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
1132 const gchar *path, const gchar *sender)
1134 bt_hfp_agent_error_t ret;
1138 if (cmd == NULL || path == NULL || sender == NULL) {
1139 ERR("Invalid Argument");
1140 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
1143 DBG("cmd = %s", cmd);
1144 DBG("Application path = %s", path);
1145 DBG("Sender = %s", sender);
1147 ret = __bt_ag_agent_gdbus_method_send(sender,
1148 path, TELEPHONY_APP_INTERFACE,
1150 g_variant_new("(s)", cmd));
1155 gboolean _bt_ag_agent_get_signal_quality(void *device)
1161 if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
1162 DBG("VCONFKEY_TELEPHONY_RSSI failed\n");
1166 DBG("RSSI : %d", rssi);
1168 _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
1175 _bt_hfp_signal_quality_reply(-1, -1, device);
1179 gboolean _bt_ag_agent_get_battery_status(void *device)
1181 gint battery_chrg_status;
1182 gint battery_capacity;
1186 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
1187 &battery_chrg_status)) {
1188 DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n");
1192 DBG("Status : %d\n", battery_chrg_status);
1194 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
1195 &battery_capacity)) {
1196 DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n");
1200 DBG("Capacity : %d\n", battery_capacity);
1202 _bt_hfp_battery_property_reply(device,
1203 battery_chrg_status, battery_capacity);
1208 _bt_hfp_battery_property_reply(device, -1, -1);
1213 gboolean _bt_ag_agent_get_operator_name(void *device)
1215 char *operator_name;
1218 operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
1219 if (NULL == operator_name) {
1220 DBG("vconf_get_str failed");
1221 _bt_hfp_operator_reply(NULL, device);
1225 DBG("operator_name = [%s]", operator_name);
1227 _bt_hfp_operator_reply(operator_name, device);
1229 free(operator_name);
1235 gboolean _bt_hfp_agent_nrec_status(gboolean status,
1239 bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
1241 DBG("NREC status = %d", status);
1243 hs->nrec_status = FALSE;
1245 hs->nrec_status = TRUE;
1248 _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
1249 BT_AG_SERVICE_NAME, "NrecStatusChanged",
1250 g_variant_new("(b)", status));
1255 gboolean _bt_ag_agent_get_imei_number(void *device)
1260 imei_number = tel_get_misc_me_imei_sync(tapi_handle);
1261 if (NULL == imei_number) {
1262 ERR("tel_get_misc_me_imei_sync for imei_number failed");
1266 if (!g_utf8_validate(imei_number, -1, NULL)) {
1268 ERR("get_imei_number : invalid UTF8");
1272 DBG_SECURE("imei_number = [%s]", imei_number);
1273 _bt_hfp_get_imei_number_reply(imei_number, device);
1279 _bt_hfp_get_imei_number_reply(NULL, device);
1284 void _bt_ag_agent_get_manufacturer_name(void *device)
1287 char *manufacturer_name;
1290 ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
1291 &manufacturer_name);
1292 if (SYSTEM_INFO_ERROR_NONE != ret) {
1293 ERR("Get manufacturer_name failed : %d", ret);
1294 if (NULL != manufacturer_name)
1295 free(manufacturer_name);
1297 manufacturer_name = g_strdup("Unknown");
1298 } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
1299 free(manufacturer_name);
1300 manufacturer_name = g_strdup("Unknown");
1301 ERR("get_manufacturer_name : invalid UTF8");
1304 DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
1305 _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
1306 free(manufacturer_name);
1310 void _bt_ag_agent_get_imsi(void *device)
1313 TelSimImsiInfo_t imsi;
1314 memset(&imsi, 0, sizeof(TelSimImsiInfo_t));
1315 if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
1316 ERR("tel_get_sim_imsi failed");
1319 DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
1321 _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
1325 _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
1329 int _bt_ag_agent_registration_status_convert(int result)
1332 case TAPI_NETWORK_SERVICE_LEVEL_NO:
1333 return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
1334 case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
1335 return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
1336 case TAPI_NETWORK_SERVICE_LEVEL_FULL:
1337 return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
1338 case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
1339 return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
1341 return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
1346 void _bt_ag_agent_get_creg_status(void *device)
1352 int registration_status = 0;
1353 int roam_status = 0;
1355 ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
1357 if (ret != TAPI_API_SUCCESS) {
1358 ERR("tel_get_property_int failed");
1361 registration_status =
1362 _bt_ag_agent_registration_status_convert(result);
1364 DBG_SECURE("Registration status %d", result);
1365 DBG_SECURE("Mapped Status %d", registration_status);
1366 if (registration_status ==
1367 BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
1368 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
1370 ERR("Get roaming status failed err = %d\n", ret);
1373 DBG_SECURE("Roam status %d", roam_status);
1374 if (roam_status == 1) {
1375 registration_status =
1376 BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
1380 _bt_hfp_get_creg_status_reply(n, registration_status, device);
1386 void _bt_ag_agent_get_model_name(void *device)
1392 ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
1393 if (SYSTEM_INFO_ERROR_NONE != ret) {
1394 ERR("Get model_name failed: %d", ret);
1395 if (NULL != model_name)
1398 model_name = g_strdup("Unknown");
1399 } else if (!g_utf8_validate(model_name, -1, NULL)) {
1401 model_name = g_strdup("Unknown");
1402 ERR("get_model_name : invalid UTF8");
1405 DBG_SECURE("model_name = [%s]", model_name);
1406 _bt_hfp_get_model_info_reply(model_name, device);
1411 void _bt_ag_agent_get_revision_information(void *device)
1414 char *revision_info;
1417 ret = system_info_get_platform_string("http://tizen.org/system/build.string",
1419 if (SYSTEM_INFO_ERROR_NONE != ret) {
1420 ERR("Get revision_info failed: %d", ret);
1421 if (NULL != revision_info)
1422 free(revision_info);
1424 revision_info = g_strdup("Unknown");
1425 } else if (!g_utf8_validate(revision_info, -1, NULL)) {
1426 free(revision_info);
1427 revision_info = g_strdup("Unknown");
1428 ERR("get_revision_info: invalid UTF8");
1431 DBG_SECURE("revision_info = [%s]", revision_info);
1432 _bt_hfp_get_revision_info_reply(revision_info, device);
1433 free(revision_info);
1437 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
1438 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1443 b = bundle_create();
1445 ERR("bundle_create() Failed");
1449 bundle_add(b, "domain", "bt_headset");
1451 bundle_add(b, "action_type", "deactivate");
1453 aul_launch_app_async("org.tizen.svoice", b);
1459 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1462 app_control_h service = NULL;
1464 app_control_create(&service);
1466 if (service == NULL) {
1467 ERR("Service create failed");
1471 app_control_set_app_id(service, "org.tizen.svoice");
1472 app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
1473 if (app_control_add_extra_data(service, "domain", "bt_headset")
1474 != APP_CONTROL_ERROR_NONE) {
1475 ERR("app_control_add_extra_data failed");
1476 app_control_destroy(service);
1481 if (app_control_add_extra_data(service, "action_type", "deactivate")
1482 != APP_CONTROL_ERROR_NONE) {
1483 ERR("app_control_add_extra_data failed");
1484 app_control_destroy(service);
1488 if (app_control_send_launch_request(service, NULL, NULL) !=
1489 APP_CONTROL_ERROR_NONE) {
1490 ERR("launch failed");
1491 app_control_destroy(service);
1495 app_control_destroy(service);
1501 gboolean _bt_ag_agent_voice_dial(gboolean activate)
1503 DBG("Activate = %d", activate);
1505 return __bt_ag_agent_launch_voice_dial(activate);
1508 static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
1511 hs->codec_info.is_negotiating = FALSE;
1512 hs->codec_info.requested_by_hf = FALSE;
1513 hs->codec_info.sending_codec = 0;
1515 hs->codec_info.remote_codecs = 0;
1516 hs->codec_info.final_codec = 0;
1517 hs->nrec_status = FALSE;
1520 if (hs->codec_info.nego_timer) {
1521 g_source_remove(hs->codec_info.nego_timer);
1522 hs->codec_info.nego_timer = 0;
1524 wbs_opts.wbs_enable = wbs_en;
1527 static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
1529 struct ag_codec *data = (struct ag_codec *)user_data;
1531 if (g_strcmp0(data->codec_status, "finish") == 0) {
1532 DBG("Codec negotiation finished");
1533 __bt_ag_sco_connect(data->bt_ag_info);
1534 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1535 g_free(data->codec_status);
1538 } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
1539 DBG("Timeout is occured in codec negotiation");
1542 if (data->bt_ag_info->codec_info.requested_by_hf) {
1543 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1545 __bt_ag_sco_connect(data->bt_ag_info);
1546 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1548 g_free(data->codec_status);
1554 static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
1559 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
1561 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
1562 G_DBUS_PROXY_FLAGS_NONE, NULL,
1563 BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
1564 BT_ADAPTER_INTERFACE, NULL, &err);
1568 ERR("Unable to create proxy: %s", err->message);
1569 g_clear_error(&err);
1571 return BT_HFP_AGENT_ERROR_INTERNAL;
1574 ret = g_dbus_proxy_call_sync(proxy, method,
1575 g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
1576 G_DBUS_CALL_FLAGS_NONE, -1,
1579 /* dBUS-RPC is failed */
1580 ERR("dBUS-RPC is failed");
1582 /* dBUS gives error cause */
1583 ERR("D-Bus API failure: errCode[%x], message[%s]",
1584 err->code, err->message);
1586 g_clear_error(&err);
1588 return BT_HFP_AGENT_ERROR_INTERNAL;
1590 g_variant_unref(ret);
1592 return BT_HFP_AGENT_ERROR_NONE;
1595 static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
1598 bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
1600 DBG("Codec setup [%x]", codec);
1602 /* 1. Compare sending codec & recieved code */
1603 if (hs->codec_info.sending_codec != codec)
1604 err = BT_HFP_AGENT_ERROR_INTERNAL;
1606 /* 2. Send WB or NB command */
1608 case BT_CVSD_CODEC_ID:
1609 err = __bt_ag_set_codec(hs, "SetNbParameters");
1611 case BT_MSBC_CODEC_ID:
1612 err = __bt_ag_set_codec(hs, "SetWbsParameters");
1615 err = BT_HFP_AGENT_ERROR_INTERNAL;
1619 /* If the vendor specific calling returns error or codec is not correct,
1620 * we send CVSD Codec parameter to MM module. and also returns
1621 * normal value to HF
1623 if (err != BT_HFP_AGENT_ERROR_NONE)
1624 codec = BT_CVSD_CODEC_ID;
1626 hs->codec_info.final_codec = codec;
1631 static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
1632 gboolean init_by_hf)
1635 struct ag_codec *data = NULL;;
1637 if (TIZEN_MODEL_NAME_TM1) {
1638 codec = BT_CVSD_CODEC_ID;
1640 if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
1641 codec = BT_MSBC_CODEC_ID;
1643 codec = BT_CVSD_CODEC_ID;
1646 if (wbs_opts.wbs_enable == FALSE)
1647 codec = BT_CVSD_CODEC_ID;
1651 if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
1652 return BT_HFP_AGENT_ERROR_INTERNAL;
1654 DBG("Send +BCS:%d\n", codec);
1656 /* Send +BCS command to HF, and wait some times */
1657 hs->codec_info.is_negotiating = TRUE;
1658 hs->codec_info.sending_codec = codec;
1659 hs->codec_info.requested_by_hf = init_by_hf;
1660 hs->codec_info.final_codec = codec;
1662 data = g_new0(struct ag_codec, 1);
1664 return BT_HFP_AGENT_ERROR_NO_MEMORY;
1666 data->bt_ag_info = hs;
1667 data->codec_status = g_strdup("timeout");
1669 hs->codec_info.nego_timer = g_timeout_add_seconds(
1670 HFP_CODEC_NEGOTIATION_TIMEOUT,
1671 (GSourceFunc)__bt_ag_codec_negotiation_finished,
1674 return BT_HFP_AGENT_ERROR_NONE;
1678 static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
1679 bt_ag_info_t *hs, gboolean init_by_hf)
1681 DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
1683 if (hs->state < HEADSET_STATE_CONNECTED)
1684 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1686 if (hs->codec_info.is_negotiating == TRUE) {
1687 /* In codec negotiation, return and wait */
1688 ERR("Codec nogotiation is in progress");
1689 return BT_HFP_AGENT_ERROR_BUSY;
1692 /* Not support Codec Negotiation or Not recieved BAC command */
1693 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
1694 hs->codec_info.remote_codecs == 0) {
1695 ERR("No support for Codec Negotiation or receive BAC command");
1697 return BT_HFP_AGENT_ERROR_INTERNAL;
1699 __bt_ag_sco_connect(hs);
1700 return BT_HFP_AGENT_ERROR_INTERNAL;
1704 /* If HF initiated codec connection setup, it should send OK command
1705 * before +BCS command transmission.
1708 return HFP_STATE_MNGR_ERR_NONE;
1710 return __bt_hfp_send_bcs_command(hs, init_by_hf);
1714 static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
1717 *codecs = 0x00000000;
1719 str = strchr(cmd, '=');
1723 while (str != NULL) {
1726 if (atoi(str) == BT_CVSD_CODEC_ID)
1727 *codecs |= BT_CVSD_CODEC_MASK;
1728 else if (atoi(str) == BT_MSBC_CODEC_ID)
1729 *codecs |= BT_MSBC_CODEC_MASK;
1731 str = strchr(str, ',');
1734 if (*codecs == 0x00000000)
1740 /* AT+BAC (Bluetooth Available Codecs) */
1741 static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
1743 uint32_t codecs = 0x00000000;
1744 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1746 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
1747 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1748 } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
1749 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1751 DBG("Update remote available codecs [%x]", codecs);
1752 hs->codec_info.remote_codecs = codecs;
1755 _bt_ag_send_response(hs, err);
1757 /* Reset codec information and
1758 * restart codec connection setup by AG
1760 hs->codec_info.final_codec = 0;
1761 if (hs->codec_info.nego_timer) {
1762 hs->codec_info.is_negotiating = FALSE;
1763 hs->codec_info.requested_by_hf = FALSE;
1764 hs->codec_info.sending_codec = 0;
1765 g_source_remove(hs->codec_info.nego_timer);
1766 __bt_hfp_codec_connection_setup(hs, FALSE);
1772 /* AT+BCC (Bluetooth Codec Connection) */
1773 static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
1775 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1777 err = __bt_hfp_codec_connection_setup(hs, TRUE);
1779 _bt_ag_send_response(hs, err);
1781 if (err == HFP_STATE_MNGR_ERR_NONE)
1782 err = __bt_hfp_send_bcs_command(hs, TRUE);
1784 if (err != HFP_STATE_MNGR_ERR_NONE)
1785 ERR("Fail to request codec connection setup");
1790 /* AT+BCS (Bluetooth Codec Selection) */
1791 static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
1793 uint32_t codec = 0x00000000;
1794 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1795 struct ag_codec *data = g_new0(struct ag_codec, 1);
1798 if (hs->codec_info.nego_timer) {
1799 g_source_remove(hs->codec_info.nego_timer);
1800 hs->codec_info.nego_timer = 0;
1803 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
1804 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1805 else if (__hfp_parse_available_codecs(buf, &codec) < 0)
1806 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1807 else if (__bt_ag_codec_selection_setup(hs, codec) !=
1808 BT_HFP_AGENT_ERROR_NONE)
1809 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1811 data->bt_ag_info = hs;
1812 data->codec_status = g_strdup("finish");
1813 _bt_ag_send_response(hs, err);
1814 __bt_ag_codec_negotiation_finished(data);
1819 static void __bt_ag_str2ba(const char *str, bt_addr *ba)
1822 for (i = 5; i >= 0; i--, str += 3)
1823 ba->b[i] = strtol(str, NULL, 16);
1826 static const char *__bt_ag_state2str(hs_state_t state)
1829 case HEADSET_STATE_DISCONNECTED:
1830 return "disconnected";
1831 case HEADSET_STATE_CONNECTING:
1832 return "connecting";
1833 case HEADSET_STATE_CONNECTED:
1835 case HEADSET_STATE_PLAY_IN_PROGRESS:
1836 return "Play In Progress";
1837 case HEADSET_STATE_ON_CALL:
1844 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
1845 const char *address)
1850 ret_if(address == NULL);
1851 ret_if(addr == NULL);
1853 for (i = 0; i < 6; i++) {
1854 addr[5 - i] = strtol(address, &ptr, 16);
1855 if (ptr[0] != '\0') {
1864 static gboolean __bt_ag_check_nval(GIOChannel *chan)
1866 struct pollfd file_desc;
1868 memset(&file_desc, 0, sizeof(file_desc));
1869 file_desc.fd = g_io_channel_unix_get_fd(chan);
1870 file_desc.events = POLLNVAL;
1872 if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
1878 static int __bt_ag_sco_connect(bt_ag_info_t *hs)
1880 struct sco_socket_addr sco_addr;
1885 bt_ag_slconn_t *slconn = hs->slc;
1888 if (hs->state == HEADSET_STATE_ON_CALL)
1889 return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED;
1891 if (hs->state != HEADSET_STATE_CONNECTED)
1892 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1893 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
1894 _bt_ag_agent_check_transport_state();
1897 /* Create Sco socket */
1898 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
1900 ERR("ERROR: Create socket failed.\n");
1901 return BT_HFP_AGENT_ERROR_INTERNAL;
1904 /* Bind Sco Socket to Local BD addr */
1905 memset(&sco_addr, 0, sizeof(sco_addr));
1906 sco_addr.sco_family = AF_BLUETOOTH;
1908 __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
1909 DBG("Local BD address: %s", local_addr);
1911 err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1913 ERR("ERROR: sco socket binding failed");
1914 ERR("Close SCO skt");
1916 return BT_HFP_AGENT_ERROR_INTERNAL;
1919 DBG("Socket FD : %d", sco_skt);
1921 io = g_io_channel_unix_new(sco_skt);
1922 g_io_channel_set_close_on_unref(io, TRUE);
1923 /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
1924 g_io_channel_set_buffered(io, FALSE);
1925 g_io_channel_set_encoding(io, NULL, NULL);*/
1927 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
1928 (slconn && (slconn->hs_features &
1929 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
1930 wbs_opts.wbs_enable == TRUE) {
1931 bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
1932 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
1934 DBG("set Bluetooth voice: %d", bt_vo.setting);
1935 err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
1936 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
1938 ERR("ERROR: sco socket set socket option failed");
1939 ERR("Close SCO skt");
1940 g_io_channel_unref(io);
1942 return BT_HFP_AGENT_ERROR_INTERNAL;
1945 DBG("Set NB codec parameter");
1946 __bt_ag_set_codec(hs, "SetNbParameters");
1949 memset(&sco_addr, 0, sizeof(sco_addr));
1950 sco_addr.sco_family = AF_BLUETOOTH;
1951 __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
1952 DBG("remotel BD address: %s", hs->remote_addr);
1954 err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1955 if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
1956 ERR("ERROR: sco socket connect failed : %d", err);
1957 ERR("Close SCO skt");
1958 g_io_channel_unref(io);
1960 return BT_HFP_AGENT_ERROR_INTERNAL;
1963 /* Disabling the watch since SCO is connected */
1964 /*watch_id = __bt_ag_set_watch(io,
1965 (GIOFunc) __bt_ag_sco_connect_cb, hs);
1967 DBG("SCO watch set Success");*/
1971 _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
1972 return BT_HFP_AGENT_ERROR_NONE;
1975 static void __bt_ag_close_sco(bt_ag_info_t *hs)
1979 int sock = g_io_channel_unix_get_fd(hs->sco);
1980 shutdown(sock, SHUT_RDWR);
1981 g_io_channel_unref(hs->sco);
1986 __bt_ag_agent_remove_watch(&hs->sco_id);
1988 if (hs->sco_incoming_id)
1989 __bt_ag_agent_remove_watch(&hs->sco_incoming_id);
1992 static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
1993 GIOCondition cond, gpointer user_data)
1995 bt_ag_info_t *ag_info = user_data;
1998 if (cond & G_IO_NVAL)
2001 if (cond & (G_IO_HUP | G_IO_ERR)) {
2002 ag_info->sco = NULL;
2003 if (ag_info->sco_id)
2004 __bt_ag_agent_remove_watch(&ag_info->sco_id);
2006 if (ag_info->sco_incoming_id)
2007 __bt_ag_agent_remove_watch(&ag_info->sco_incoming_id);
2009 if (ag_info->watch_id)
2010 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
2016 static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
2017 GIOCondition cond, gpointer user_data)
2019 bt_ag_info_t *ag_info = user_data;
2023 bt_ag_slconn_t *slconn = ag_info->slc;
2027 if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
2028 __bt_ag_check_nval(chan)) {
2029 ERR("cond or chan is not valid");
2033 INFO_C("Incoming SCO....");
2035 if (ag_info->state < HEADSET_STATE_CONNECTED)
2036 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
2038 sco_skt = g_io_channel_unix_get_fd(chan);
2040 cli_sco_sock = accept(sco_skt, NULL, NULL);
2041 if (cli_sco_sock < 0) {
2042 ERR("accept is failed");
2046 sco_io = g_io_channel_unix_new(cli_sco_sock);
2047 g_io_channel_set_close_on_unref(sco_io, TRUE);
2048 g_io_channel_set_encoding(sco_io, NULL, NULL);
2049 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2050 g_io_channel_set_buffered(sco_io, FALSE);
2052 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2053 (slconn && (slconn->hs_features &
2054 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
2055 wbs_opts.wbs_enable == TRUE) {
2056 bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
2057 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
2059 DBG("set Bluetooth voice: %d", bt_vo.setting);
2060 err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
2061 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
2063 ERR("Sco socket set socket option failed");
2064 close(cli_sco_sock);
2069 ag_info->sco = sco_io;
2070 ag_info->sco_incoming_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2071 __bt_ag_sco_server_conn_cb, ag_info);
2073 if (remote_dev_path)
2074 g_free(remote_dev_path);
2076 remote_dev_path = g_strdup(ag_info->path);
2078 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
2083 static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
2085 DBG("Start SCO server");
2086 struct sco_socket_addr addr;
2089 bdaddr_t bd_addr = {{0},};
2091 if (hs->sco_server_started) {
2092 DBG("Already exsist");
2093 return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
2097 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
2099 ERR("Can't create socket:\n");
2100 return BT_HFP_AGENT_ERROR_INTERNAL;
2103 /* Bind to local address */
2104 memset(&addr, 0, sizeof(addr));
2105 addr.sco_family = AF_BLUETOOTH;
2107 _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
2108 DBG("Bind to address %s", hs->remote_addr);
2109 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2111 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2112 ERR("Can't bind socket:\n");
2116 if (listen(sco_skt, 1)) {
2117 ERR("Can not listen on the socket:\n");
2121 sco_io = g_io_channel_unix_new(sco_skt);
2122 g_io_channel_set_close_on_unref(sco_io, TRUE);
2123 g_io_channel_set_encoding(sco_io, NULL, NULL);
2124 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2125 g_io_channel_set_buffered(sco_io, FALSE);
2127 hs->sco_server = sco_io;
2128 hs->sco_watch_id = g_io_add_watch(sco_io,
2129 G_IO_IN | G_IO_HUP | G_IO_ERR |
2130 G_IO_NVAL, __bt_ag_sco_server_cb, hs);
2132 hs->sco_server_started = TRUE;
2133 return BT_HFP_AGENT_ERROR_NONE;
2137 return BT_HFP_AGENT_ERROR_INTERNAL;
2140 void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
2142 DBG("Stop SCO server");
2143 if (hs->sco_server) {
2144 g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
2145 g_io_channel_unref(hs->sco_server);
2146 hs->sco_server = NULL;
2148 hs->sco_server_started = FALSE;
2151 static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
2153 GIOChannel *rfcomm = hs->rfcomm;
2156 g_io_channel_shutdown(rfcomm, TRUE, NULL);
2157 g_io_channel_unref(rfcomm);
2167 static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
2170 if (cond & G_IO_NVAL)
2173 if (name_owner_sig_id != -1)
2174 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
2176 name_owner_sig_id = -1;
2180 DBG("Audio connection disconnected");
2181 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2186 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
2188 bt_ag_slconn_t *slconn = hs->slc;
2189 const char *hs_state;
2190 hs_state_t org_state = hs->state;
2191 gboolean val = FALSE;
2193 if (org_state == state)
2196 hs_state = __bt_ag_state2str(state);
2199 case HEADSET_STATE_CONNECTING:
2200 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2202 BT_HEADSET_INTERFACE, "State",
2203 g_variant_new("s", hs_state));
2207 case HEADSET_STATE_CONNECTED:
2208 if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
2209 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2211 BT_HEADSET_INTERFACE, "State",
2212 g_variant_new("s", hs_state));
2214 if (hs->state < state) {
2216 active_devices = g_slist_append(active_devices, hs);
2217 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2219 BT_HEADSET_INTERFACE,
2221 g_variant_new("b", val));
2223 DBG("Device %s connected\n", hs->remote_addr);
2224 #if defined(TIZEN_SUPPORT_DUAL_HF)
2225 if (!hs->is_companion_device)
2226 __bt_ag_start_sco_server(hs);
2228 __bt_ag_start_sco_server(hs);
2231 /* Set default code as Gateway NB */
2232 __bt_ag_set_codec(hs, "SetNbParameters");
2233 } else if (hs->state == HEADSET_STATE_ON_CALL) {
2235 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2237 BT_HEADSET_INTERFACE,
2239 g_variant_new("b", val));
2244 case HEADSET_STATE_DISCONNECTED:
2245 __bt_ag_close_sco(hs);
2246 __bt_ag_headset_close_rfcomm(hs);
2248 if (hs->state == HEADSET_STATE_ON_CALL) {
2250 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2252 BT_HEADSET_INTERFACE,
2254 g_variant_new("b", val));
2258 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2260 BT_HEADSET_INTERFACE,
2262 g_variant_new("b", val));
2263 if (hs->state > HEADSET_STATE_CONNECTING)
2264 _bt_hfp_device_disconnected(hs);
2266 active_devices = g_slist_remove(active_devices, hs);
2268 __bt_ag_codec_negotiation_info_reset(hs, TRUE);
2269 #if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
2270 __bt_ag_set_codec(hs, "SetNbParameters");
2274 /* Since SCO server is binded on remote address */
2275 /* Need to stop SCO server once heasdet disconencted*/
2276 if (hs->sco_server_started)
2277 __bt_ag_stop_sco_server(hs);
2279 g_free(hs->remote_addr);
2283 case HEADSET_STATE_PLAY_IN_PROGRESS:
2284 case HEADSET_STATE_ON_CALL:
2286 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2288 BT_HEADSET_INTERFACE, "State",
2289 g_variant_new("s", hs_state));
2291 /*add watch for sco data */
2292 hs->sco_id = g_io_add_watch(hs->sco,
2293 G_IO_ERR | G_IO_NVAL,
2294 (GIOFunc) __bt_ag_sco_cb, hs);
2296 _bt_ag_agent_emit_property_changed(
2297 ag_dbus_conn, hs->path,
2298 BT_HEADSET_INTERFACE, "Playing",
2299 g_variant_new("b", val));
2301 if (slconn->microphone_gain >= 0)
2302 _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
2303 slconn->microphone_gain);
2305 if (slconn->speaker_gain >= 0)
2306 _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
2307 slconn->speaker_gain);
2317 INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
2318 __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
2321 static struct event at_event_callbacks[] = {
2322 { "AT+BRSF", _bt_hfp_supported_features },
2323 { "AT+CIND", _bt_hfp_report_indicators },
2324 { "AT+CMER", _bt_hfp_enable_indicators },
2325 { "AT+CHLD", _bt_hfp_call_hold },
2326 { "ATA", _bt_hfp_answer_call },
2327 { "ATD", _bt_hfp_dial_number },
2328 { "AT+VG", _bt_hfp_signal_gain_setting },
2329 { "AT+CHUP", _bt_hfp_terminate_call },
2330 { "AT+CKPD", _bt_hfp_key_press },
2331 { "AT+CLIP", _bt_hfp_cli_notification },
2332 { "AT+BTRH", _bt_hfp_response_and_hold },
2333 { "AT+BLDN", _bt_hfp_last_dialed_number },
2334 { "AT+VTS", _bt_hfp_dtmf_tone },
2335 { "AT+CNUM", _bt_hfp_subscriber_number },
2336 { "AT+CLCC", _bt_hfp_list_current_calls },
2337 { "AT+CMEE", _bt_hfp_extended_errors },
2338 { "AT+CCWA", _bt_hfp_call_waiting_notify },
2339 { "AT+COPS", _bt_hfp_operator_selection },
2340 { "AT+NREC", _bt_hfp_nr_and_ec },
2341 { "AT+BVRA", _bt_hfp_voice_dial },
2342 { "AT+XAPL", _bt_hfp_apl_command },
2343 { "AT+IPHONEACCEV", _bt_hfp_apl_command },
2344 { "AT+BIA", _bt_hfp_indicators_activation },
2345 { "AT+CPBS", _bt_hfp_select_pb_memory },
2346 { "AT+CPBR", _bt_hfp_read_pb_entries},
2347 { "AT+CPBF", _bt_hfp_find_pb_entires },
2348 { "AT+CSCS", _bt_hfp_select_character_set },
2349 { "AT+CSQ", _bt_hfp_get_signal_quality },
2350 { "AT+CBC", _bt_hfp_get_battery_charge_status },
2351 { "AT+CPAS", _bt_hfp_get_activity_status },
2352 { "AT+CGSN", _bt_hfp_get_equipment_identity },
2353 { "AT+CGMM", _bt_hfp_get_model_information },
2354 { "AT+CGMI", _bt_hfp_get_device_manufacturer },
2355 { "AT+CGMR", _bt_hfp_get_revision_information },
2356 { "AT+BAC", __bt_hfp_available_codecs },
2357 { "AT+BCC", __bt_hfp_codec_connection },
2358 { "AT+BCS", __bt_hfp_codec_selection },
2359 { "AT+XSAT", _bt_hfp_vendor_cmd },
2360 { "AT+CIMI", _bt_hfp_get_imsi },
2361 { "AT+CREG", _bt_hfp_get_creg_status },
2365 int num_of_secure_command = 4;
2366 static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
2368 static void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
2372 char s[MAX_BUFFER_SIZE] = {0, };
2373 gboolean hide = FALSE;
2375 gboolean is_security_command = FALSE;
2378 strncpy(s, buf, MAX_BUFFER_SIZE - 1);
2380 for (i = 0; i < num_of_secure_command; i++) {
2381 if (strstr(buf, secure_command[i])) {
2382 is_security_command = TRUE;
2387 /* +XSAT: 11,DISC */
2388 xsat_ptr = strstr(s, "11,DISC,");
2390 xsat_ptr = xsat_ptr + 8;
2392 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2398 /* AT+XSAT=11,Q_CT,X,XXXX */
2399 xsat_ptr = strstr(s, "11,Q_CT,");
2401 xsat_ptr = xsat_ptr + 8;
2403 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2404 if (x > 1) /* ignore 0 and 1 position */
2411 while (s[i] != '\0') {
2412 if (s[i] == '\r' || s[i] == '\n') {
2416 hide = hide ? FALSE : TRUE;
2417 else if (is_security_command && hide) {
2425 INFO("%s Buffer = [%s], Len(%d)", message, s, strlen(s));
2430 static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
2434 __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
2436 for (ev = at_event_callbacks; ev->cmd; ev++) {
2437 if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
2438 return ev->callback(hs, buf);
2444 static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
2447 ssize_t final_written, count;
2448 char rsp_buffer[MAX_BUFFER_SIZE];
2452 count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
2454 ERR("count is %d", count);
2458 if (!hdset->io_chan) {
2459 ERR("__bt_ag_send_at_valist: headset not connected");
2465 fd = g_io_channel_unix_get_fd(hdset->io_chan);
2468 while (final_written < count) {
2472 written = write(fd, rsp_buffer + final_written,
2473 count - final_written);
2474 } while (written < 0 && errno == EINTR);
2478 ERR("write failed : %s (%d)", strerror(-err), -err);
2482 final_written += written;
2485 /* Synchronize the sending buffer */
2489 ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
2493 __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
2498 int __attribute__((format(printf, 2, 3)))
2499 _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
2504 va_start(ap, format);
2505 ret = __bt_ag_send_at_valist(hs, ap, format);
2511 void __attribute__((format(printf, 3, 4)))
2512 _bt_ag_send_foreach_headset(GSList *devices,
2513 int (*cmp) (bt_ag_info_t *hs),
2519 for (l = devices; l != NULL; l = l->next) {
2520 bt_ag_info_t *hs = l->data;
2523 if (cmp && cmp(hs) != 0)
2526 va_start(ap, format);
2527 ret = __bt_ag_send_at_valist(hs, ap, format);
2529 ERR("Failed to send to headset: %s (%d)",
2530 strerror(-ret), -ret);
2535 int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
2537 if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
2538 return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
2541 case HFP_STATE_MNGR_ERR_NONE:
2542 return _bt_ag_send_at(hs, "\r\nOK\r\n");
2543 case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
2544 return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
2546 return _bt_ag_send_at(hs, "\r\nERROR\r\n");
2550 static gboolean __bt_ag_event_handler(GIOChannel *channel,
2551 GIOCondition cond, void *user_data)
2553 bt_ag_slconn_t *slconn;
2554 unsigned char event_buf[MAX_BUFFER_SIZE];
2556 size_t available_buffer;
2558 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2562 if (cond & G_IO_NVAL)
2565 slconn = bt_ag_info->slc;
2566 if (cond & (G_IO_ERR | G_IO_HUP)) {
2567 if (bt_ag_info->watch_id)
2568 __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
2570 ERR("ERR or HUP on RFCOMM socket");
2571 INFO_C("Disconnected [AG role] [Terminated by remote dev]");
2575 fd = g_io_channel_unix_get_fd(channel);
2576 len = read(fd, event_buf, sizeof(event_buf) - 1);
2580 available_buffer = sizeof(slconn->buffer) - (slconn->start) -
2581 (slconn->length) - 1;
2582 if (available_buffer < (size_t) len) {
2583 ERR("Buffer over flow");
2587 memcpy(&slconn->buffer[slconn->start + slconn->length], event_buf, len);
2588 slconn->length += len;
2590 slconn->buffer[slconn->start + slconn->length] = '\0';
2592 while (slconn->length > 0) {
2597 get_cr = strchr(&slconn->buffer[slconn->start], '\r');
2599 ERR("Broken AT command received, break");
2603 cmd_len = 1 + (off_t) get_cr -
2604 (off_t) &slconn->buffer[slconn->start];
2608 DBG("Call AT handler");
2609 err = __bt_ag_at_handler(bt_ag_info,
2610 &slconn->buffer[slconn->start]);
2612 ERR("Failed to call AT handler");
2619 err_return = HFP_STATE_MNGR_ERR_NOT_SUPPORTED;
2622 err_return = HFP_STATE_MNGR_ERR_NOT_ALLOWED;
2625 err_return = HFP_STATE_MNGR_ERR_NOT_SUPPORTED;
2628 ERR("Error handling command %s: %s (%d)",
2629 &slconn->buffer[slconn->start],
2630 strerror(-err), -err);
2631 err = _bt_ag_send_response(bt_ag_info,
2637 slconn->start += cmd_len;
2638 slconn->length -= cmd_len;
2640 if (slconn->length <= 0)
2645 ERR("Failed in event handler - SLC Disconnect");
2646 _bt_ag_set_headset_state(bt_ag_info,
2647 HEADSET_STATE_DISCONNECTED);
2651 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
2652 const gchar *object_path)
2656 bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
2657 struct sockaddr_remote address;
2658 socklen_t address_len;
2660 INFO_C("Connected [AG role]");
2661 bt_ag_info->rfcomm = NULL;
2662 bt_ag_info->slc = NULL;
2663 bt_ag_info->hfp_active = TRUE;
2664 bt_ag_info->vr_blacklisted = FALSE;
2665 bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
2666 bt_ag_info->sco_server_started = FALSE;
2667 __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
2669 bt_ag_info->path = device_path;
2670 DBG("device_path = [%s]", device_path);
2672 address_len = sizeof(address);
2673 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2674 ERR("BD_ADDR is NULL");
2676 DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
2677 bt_ag_info->fd = fd;
2678 bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
2679 flags = g_io_channel_get_flags(bt_ag_info->io_chan);
2681 flags &= ~G_IO_FLAG_NONBLOCK;
2682 flags &= G_IO_FLAG_MASK;
2683 g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
2684 g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
2685 g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
2687 bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
2689 bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2690 __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
2691 address.remote_bdaddr.b);
2693 #if defined(TIZEN_SUPPORT_DUAL_HF)
2694 bt_ag_info->is_companion_device =
2695 __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
2698 DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
2700 if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
2701 DBG("HSP connection completed");
2702 _bt_ag_set_headset_state(bt_ag_info,
2703 HEADSET_STATE_CONNECTED);
2705 DBG("HFP connection connecting");
2706 _bt_ag_set_headset_state(bt_ag_info,
2707 HEADSET_STATE_CONNECTING);
2710 __bt_ag_agent_start_watch(bt_ag_info);
2712 bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
2713 bt_ag_info->slc->speaker_gain = 15;
2714 bt_ag_info->slc->microphone_gain = 15;
2715 bt_ag_info->slc->is_nrec = TRUE;
2720 static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
2729 fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
2732 ERR("Unable to open VR blacklist file");
2736 fseek(fp, 0, SEEK_END);
2739 ERR("size is not a positive number");
2746 buffer = g_malloc0(sizeof(char) * size);
2747 if (buffer == NULL) {
2748 ERR("g_malloc0 is failed");
2752 result = fread((char *)buffer, 1, size, fp);
2754 if (result != size) {
2760 token = strtok_r(buffer, "=", &saveptr);
2761 if (token == NULL) {
2766 while ((token = strtok_r(NULL, ",", &saveptr))) {
2767 if (strlen(token) > 8)
2769 if (0 == g_strcmp0(token, lap_addr)) {
2770 INFO("Voice Recognition blacklisted");
2779 static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
2781 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2782 sco_open_timer_id = 0;
2783 DBG("sco_open_request (%d)", sco_open_request);
2785 if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
2786 bt_ag_slconn_t *slconn = bt_ag_info->slc;
2788 INFO("try to open SCO");
2789 sco_open_request = FALSE;
2791 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2792 (slconn && (slconn->hs_features &
2793 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
2794 switch (bt_ag_info->codec_info.final_codec) {
2795 case BT_CVSD_CODEC_ID:
2796 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
2797 __bt_ag_sco_connect(bt_ag_info);
2799 case BT_MSBC_CODEC_ID:
2800 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
2801 __bt_ag_sco_connect(bt_ag_info);
2804 __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
2808 __bt_ag_sco_connect(bt_ag_info);
2815 * Service level connection complete
2816 * indication and state management
2818 void _bt_ag_slconn_complete(bt_ag_info_t *hs)
2820 char lap_address[BT_LOWER_ADDRESS_LENGTH];
2822 DBG("HFP Service Level Connection established\n");
2824 /* Check device Voice Recognition blacklist status */
2825 g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
2826 hs->vr_blacklisted =
2827 __bt_ag_agent_is_device_vr_blacklisted(lap_address);
2829 if (sco_open_timer_id > 0) {
2830 g_source_remove(sco_open_timer_id);
2831 sco_open_timer_id = 0;
2834 sco_open_request = FALSE;
2835 sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
2836 __bt_sco_open_delay_timeout_cb, hs);
2838 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2841 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
2844 g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
2845 g_io_channel_unref(hs->io_chan);
2849 __bt_ag_close_sco(hs);
2850 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2852 __bt_ag_agent_remove_watch(&hs->watch_id);
2854 _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
2858 static GQuark __bt_ag_agent_error_quark(void)
2862 static GQuark quark = 0;
2864 quark = g_quark_from_static_string("ag-agent");
2870 static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
2873 ERR("error[%d]\n", error);
2876 case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
2877 return g_error_new(BT_AG_AGENT_ERROR, error,
2878 BT_ERROR_NOT_AVAILABLE);
2879 case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
2880 return g_error_new(BT_AG_AGENT_ERROR, error,
2881 BT_ERROR_NOT_CONNECTED);
2882 case BT_HFP_AGENT_ERROR_BUSY:
2883 return g_error_new(BT_AG_AGENT_ERROR, error,
2885 case BT_HFP_AGENT_ERROR_INVALID_PARAM:
2886 return g_error_new(BT_AG_AGENT_ERROR, error,
2887 BT_ERROR_INVALID_PARAM);
2888 case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
2889 return g_error_new(BT_AG_AGENT_ERROR, error,
2890 BT_ERROR_ALREADY_EXSIST);
2891 case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
2892 return g_error_new(BT_AG_AGENT_ERROR, error,
2893 BT_ERROR_ALREADY_CONNECTED);
2894 case BT_HFP_AGENT_ERROR_NO_MEMORY:
2895 return g_error_new(BT_AG_AGENT_ERROR, error,
2896 BT_ERROR_NO_MEMORY);
2897 case BT_HFP_AGENT_ERROR_I_O_ERROR:
2898 return g_error_new(BT_AG_AGENT_ERROR, error,
2899 BT_ERROR_I_O_ERROR);
2900 case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
2901 return g_error_new(BT_AG_AGENT_ERROR, error,
2902 BT_ERROR_OPERATION_NOT_AVAILABLE);
2903 case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
2904 return g_error_new(BT_AG_AGENT_ERROR, error,
2906 case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
2907 return g_error_new(BT_AG_AGENT_ERROR, error,
2909 case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
2910 return g_error_new(BT_AG_AGENT_ERROR, error,
2911 BT_ERROR_NO_CALL_LOG);
2912 case BT_HFP_AGENT_ERROR_INTERNAL:
2914 return g_error_new(BT_AG_AGENT_ERROR, error,
2920 static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
2924 for (l = active_devices ; l; l = l->next) {
2925 bt_ag_info_t *data = l->data;
2926 if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
2928 if (g_strcmp0(data->path, device_path) == 0) {
2929 INFO("Active device found");
2934 INFO("Active device not found");
2938 static void __bt_ag_agent_method(GDBusConnection *connection,
2939 const gchar *sender,
2940 const gchar *object_path,
2941 const gchar *interface_name,
2942 const gchar *method_name,
2943 GVariant *parameters,
2944 GDBusMethodInvocation *invocation,
2949 INFO("method %s", method_name);
2950 INFO("object_path %s", object_path);
2951 int ret = BT_HFP_AGENT_ERROR_NONE;
2953 const gchar *device_path = NULL;
2955 if (g_strcmp0(method_name, "NewConnection") == 0) {
2959 GUnixFDList *fd_list;
2960 GVariant *options = NULL;
2961 int device_count = 0;
2963 device_count = g_slist_length(active_devices);
2965 INFO("device_count %d", device_count);
2967 if (device_count >= MAX_CONNECTED_DEVICES) {
2968 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2972 g_variant_get(parameters, "(oha{sv})",
2973 &device_path, &index, &options);
2975 #if defined(TIZEN_SUPPORT_DUAL_HF) && defined(TIZEN_PROFILE_WEARABLE)
2977 * Below code is not required for dual HF support for
2981 __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
2982 INFO("not allow to connect 2nd HF connection");
2983 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2987 msg = g_dbus_method_invocation_get_message(invocation);
2988 fd_list = g_dbus_message_get_unix_fd_list(msg);
2989 if (fd_list == NULL) {
2990 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2994 fd = g_unix_fd_list_get(fd_list, index, NULL);
2996 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3000 DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
3002 if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
3003 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3007 g_dbus_method_invocation_return_value(invocation, NULL);
3008 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
3011 g_variant_get(parameters, "(o)", &device_path);
3012 INFO("device_path %s", device_path);
3014 for (l = active_devices; l; l = l->next) {
3015 bt_ag_info_t *data = l->data;
3017 INFO("data->path %s", data->path);
3018 if (g_strcmp0(data->path, device_path) == 0) {
3019 if (!__bt_ag_agent_connection_release(data)) {
3020 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3023 INFO_C("Disconnected [AG role] [Terminated by local host]");
3024 g_dbus_method_invocation_return_value(invocation, NULL);
3027 } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
3029 gchar *address = NULL;
3030 g_variant_get(parameters, "(&s&s)", &path, &address);
3031 /*local_addr = malloc(strlen(address));
3032 memcpy(local_addr, address, strlen(address));*/
3034 DBG("Sender = %s, Application path = %s\n", sender, path);
3035 ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
3040 local_addr = g_strdup(address);
3041 DBG("Address = %s\n", local_addr);
3042 g_dbus_method_invocation_return_value(invocation, NULL);
3043 } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
3045 g_variant_get(parameters, "(&s)", &path);
3047 DBG("Application path = %s\n", path);
3048 DBG("Sender = %s\n", sender);
3050 ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
3054 g_dbus_method_invocation_return_value(invocation, NULL);
3055 } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
3057 gchar *number = NULL;
3060 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3062 DBG("Application path = %s", path);
3063 DBG_SECURE("Phone number = %s", number);
3064 DBG("Call id = %d", call_id);
3066 DBG("Sender = %s", sender);
3068 ret = _bt_hfp_incoming_call(path, number, call_id, sender);
3071 g_dbus_method_invocation_return_value(invocation, NULL);
3072 } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
3074 gchar *number = NULL;
3077 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3079 DBG("Application path = %s", path);
3080 DBG_SECURE("Phone number = %s", number);
3081 DBG("Call id = %d", call_id);
3083 DBG("Sender = %s", sender);
3085 ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
3088 g_dbus_method_invocation_return_value(invocation, NULL);
3089 } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
3091 gchar *number = NULL;
3096 g_variant_get(parameters, "(&s&sii)",
3097 &path, &number, &status, &call_id);
3098 DBG("Application path = %s\n", path);
3099 DBG_SECURE("Number = %s\n", number);
3100 DBG("Status = %d\n", status);
3101 DBG("Call id = %d\n", call_id);
3102 DBG("Sender = %s\n", sender);
3104 ret = _bt_hfp_change_call_status(path,
3105 number, status, call_id, sender);
3107 if (_bt_hfp_is_call_exist() == FALSE) {
3108 for (l = active_devices; l; l = l->next) {
3109 bt_ag_info_t *data = l->data;
3111 if (data->state == HEADSET_STATE_ON_CALL) {
3112 __bt_ag_close_sco(data);
3113 _bt_ag_set_headset_state(data,
3114 HEADSET_STATE_CONNECTED);
3121 g_dbus_method_invocation_return_value(invocation, NULL);
3122 } else if (g_strcmp0(method_name, "GetProperties") == 0) {
3123 GVariantBuilder *builder;
3125 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3128 gchar *codec = g_strdup("codec");
3129 gchar *nrec = g_strdup("nrec");
3131 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3133 g_variant_builder_add(builder, "{sv}",
3134 codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
3135 g_variant_builder_add(builder, "{sv}",
3136 nrec, g_variant_new("b", bt_ag_info->nrec_status));
3138 var_data = g_variant_new("(a{sv})", builder);
3139 g_variant_builder_unref(builder);
3140 g_dbus_method_invocation_return_value(invocation, var_data);
3145 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3148 } else if (g_strcmp0(method_name, "Disconnect") == 0) {
3149 char hdset_address[18] = { 0, };
3152 for (l = active_devices; l; l = l->next) {
3153 bt_ag_info_t *data = l->data;
3155 __bt_convert_addr_type_to_rev_string(hdset_address,
3156 (unsigned char *)data->remote_addr);
3158 DBG("Disconnect Headset %s, %s\n",
3159 hdset_address, data->path);
3160 _bt_ag_set_headset_state(data,
3161 HEADSET_STATE_DISCONNECTED);
3163 g_dbus_method_invocation_return_value(invocation, NULL);
3164 } else if (g_strcmp0(method_name, "IsConnected") == 0) {
3165 gboolean is_connected = FALSE;
3168 for (l = active_devices; l; l = l->next) {
3169 bt_ag_info_t *data = l->data;
3171 if (data->state == HEADSET_STATE_CONNECTED)
3172 is_connected = TRUE;
3174 DBG("is_connected : %s",
3175 is_connected ? "Connected" : "Disconnected");
3177 g_dbus_method_invocation_return_value(invocation,
3178 g_variant_new("(b)", is_connected));
3179 } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
3182 if (0 == g_slist_length(active_devices)) {
3183 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3187 if (ag.ring_timer) {
3188 DBG("IndicateCall received when already indicating");
3189 g_dbus_method_invocation_return_value(invocation, NULL);
3192 for (l = active_devices; l; l = l->next) {
3193 bt_ag_info_t *data = l->data;
3195 if (data->state >= HEADSET_STATE_CONNECTED)
3196 _bt_ag_send_at(data, "\r\nRING\r\n");
3199 __bt_ring_timer_cb(NULL);
3200 ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
3201 __bt_ring_timer_cb, NULL);
3202 g_dbus_method_invocation_return_value(invocation, NULL);
3203 } else if (g_strcmp0(method_name, "CancelCall") == 0) {
3204 if (0 == g_slist_length(active_devices)) {
3205 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3209 if (ag.ring_timer) {
3210 g_source_remove(ag.ring_timer);
3213 DBG("Got CancelCall method call but no call is active");
3215 g_dbus_method_invocation_return_value(invocation, NULL);
3216 } else if (g_strcmp0(method_name, "Play") == 0) {
3217 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3218 bt_ag_slconn_t *slconn = NULL;
3221 slconn = bt_ag_info->slc;
3223 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3227 #ifndef __TIZEN_OPEN__
3230 if (slconn && FALSE == slconn->is_voice_recognition_running &&
3231 mdm_get_service() == MDM_RESULT_SUCCESS) {
3232 mode = mdm_get_allow_bluetooth_outgoing_call();
3233 mdm_release_service();
3235 if (mode == MDM_RESTRICTED) {
3236 ERR("[MDM] Not allow the outgoing call");
3237 ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
3244 switch (bt_ag_info->state) {
3245 case HEADSET_STATE_CONNECTING:
3246 case HEADSET_STATE_DISCONNECTED:
3247 ERR("HEADSET_STATE ERROR");
3248 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3250 case HEADSET_STATE_CONNECTED:
3252 case HEADSET_STATE_PLAY_IN_PROGRESS:
3253 ERR("Play In Progress");
3254 ret = BT_HFP_AGENT_ERROR_BUSY;
3262 if (sco_open_timer_id > 0) {
3263 INFO("SCO open delay");
3264 sco_open_request = TRUE;
3265 g_dbus_method_invocation_return_value(invocation, NULL);
3269 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
3270 (slconn && (slconn->hs_features &
3271 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
3272 switch (bt_ag_info->codec_info.final_codec) {
3273 case BT_CVSD_CODEC_ID:
3274 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
3275 ret = __bt_ag_sco_connect(bt_ag_info);
3277 case BT_MSBC_CODEC_ID:
3278 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
3279 ret = __bt_ag_sco_connect(bt_ag_info);
3282 ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
3286 ret = __bt_ag_sco_connect(bt_ag_info);
3292 sco_owner = g_strdup(sender);
3294 g_dbus_method_invocation_return_value(invocation, NULL);
3296 name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
3297 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
3298 __bt_ag_name_owner_changed_cb, NULL, NULL);
3299 } else if (g_strcmp0(method_name, "Stop") == 0) {
3302 for (l = active_devices; l; l = l->next) {
3303 bt_ag_info_t *data = l->data;
3305 if (data->state > HEADSET_STATE_CONNECTED) {
3306 __bt_ag_close_sco(data);
3307 _bt_ag_set_headset_state(data,
3308 HEADSET_STATE_CONNECTED);
3312 g_dbus_method_invocation_return_value(invocation, NULL);
3313 } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
3314 gboolean is_playing = FALSE;
3317 for (l = active_devices; l; l = l->next) {
3318 bt_ag_info_t *data = l->data;
3320 if (data->state == HEADSET_STATE_ON_CALL)
3323 DBG("is_playing : %s", is_playing ? "Playing" : "Not Playing");
3325 g_dbus_method_invocation_return_value(invocation,
3326 g_variant_new("(b)", is_playing));
3327 } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
3328 bt_ag_slconn_t *slconn = NULL;
3329 guint16 gain_value = 0;
3330 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3332 if (bt_ag_info == NULL) {
3333 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3337 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3338 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3342 slconn = bt_ag_info->slc;
3344 gain_value = (guint16) slconn->speaker_gain;
3346 g_dbus_method_invocation_return_value(invocation,
3347 g_variant_new("(q)", gain_value));
3348 } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
3350 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3352 g_variant_get(parameters, "(q)", &gain);
3353 DBG("Speaker gain = %d\n", gain);
3355 if (bt_ag_info == NULL) {
3356 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3360 ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
3363 g_dbus_method_invocation_return_value(invocation, NULL);
3364 } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
3365 bt_ag_slconn_t *slconn = NULL;
3366 guint16 gain_value = 0;
3367 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3369 if (bt_ag_info == NULL) {
3370 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3374 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3375 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3379 slconn = bt_ag_info->slc;
3381 gain_value = (guint16) slconn->microphone_gain;
3383 g_dbus_method_invocation_return_value(invocation,
3384 g_variant_new("(q)", gain_value));
3385 } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
3387 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3389 g_variant_get(parameters, "(q)", &gain);
3390 DBG("Microphone gain = %d\n", gain);
3392 if (bt_ag_info == NULL) {
3393 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3397 ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
3400 g_dbus_method_invocation_return_value(invocation, NULL);
3401 } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
3402 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3403 if (bt_ag_info == NULL) {
3404 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3408 bt_ag_slconn_t *slconn = bt_ag_info->slc;
3411 g_variant_get(parameters, "(b)", &enable);
3412 DBG("VoiceDail enable = %d\n", enable);
3414 if ((slconn && !(slconn->hs_features &
3415 BT_HF_FEATURE_VOICE_RECOGNITION)))
3416 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3417 else if (bt_ag_info->vr_blacklisted)
3418 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3420 ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
3423 slconn->is_voice_recognition_running = enable;
3427 g_dbus_method_invocation_return_value(invocation, NULL);
3428 } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
3430 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3431 if (bt_ag_info == NULL) {
3432 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3436 g_variant_get(parameters, "(&s)", &cmd);
3438 ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
3442 DBG("vendor cmd = %s", cmd);
3444 ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
3447 g_dbus_method_invocation_return_value(invocation, NULL);
3448 } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
3449 DBG("Already pass dbus SMACK for bt-service::platform");
3450 /* Return success */
3451 g_dbus_method_invocation_return_value(invocation, NULL);
3452 } else if (g_strcmp0(method_name, "SwapHeadset") == 0) {
3455 char address[BT_ADDRESS_STRING_SIZE];
3456 char remote_addr[BT_ADDRESS_STRING_SIZE];
3457 gboolean device_found = FALSE;
3459 g_variant_get(parameters, "(s)", &addr);
3460 g_strlcpy(address, addr, sizeof(address));
3461 DBG("Sender = %s", sender);
3463 /* Loop through connected headset list
3464 * If found, update the remote_dev_path.
3466 for (l = active_devices ; l; l = l->next) {
3467 bt_ag_info_t *data = l->data;
3468 g_strlcpy(remote_addr, data->remote_addr, sizeof(remote_addr));
3469 if (g_strcmp0(remote_addr, address) == 0) {
3470 DBG("Active device found");
3471 if (data->path == NULL) {
3472 DBG("device path is null");
3473 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3476 remote_dev_path = g_strdup(data->path);
3477 DBG("Setting device path %s as active device path", remote_dev_path);
3478 device_found = TRUE;
3483 if (!device_found) {
3484 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3488 g_dbus_method_invocation_return_value(invocation, NULL);
3495 err = __bt_ag_agent_set_error(ret);
3496 g_dbus_method_invocation_return_gerror(invocation, err);
3501 static const GDBusInterfaceVTable method_table = {
3502 __bt_ag_agent_method,
3507 static GDBusNodeInfo *__bt_ag_create_method_node_info
3508 (const gchar *introspection_data)
3511 GDBusNodeInfo *node_info = NULL;
3513 if (introspection_data == NULL)
3516 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
3519 ERR("Unable to create node: %s", err->message);
3520 g_clear_error(&err);
3525 static GDBusConnection *__bt_ag_get_gdbus_connection(void)
3531 if (ag_dbus_conn == NULL)
3532 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
3534 if (!ag_dbus_conn) {
3536 ERR("Unable to connect to dbus: %s", err->message);
3537 g_clear_error(&err);
3543 return ag_dbus_conn;
3546 static gboolean __bt_ag_register_profile_methods(void)
3549 GError *error = NULL;
3551 GDBusNodeInfo *node_info = NULL;
3554 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
3556 G_BUS_NAME_OWNER_FLAGS_NONE,
3560 DBG("owner_id is [%d]", owner_id);
3562 node_info = __bt_ag_create_method_node_info(
3563 ag_agent_bluez_introspection_xml);
3564 if (node_info == NULL)
3567 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3568 DBG("path is [%s]", path);
3570 hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3571 node_info->interfaces[0],
3573 NULL, NULL, &error);
3574 if (hf_bluez_id == 0) {
3575 ERR("Failed to register: %s", error->message);
3576 g_error_free(error);
3578 g_dbus_node_info_unref(node_info);
3583 /* Ag register profile methods for HSP*/
3585 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
3586 DBG("path is [%s]", path);
3588 hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3589 node_info->interfaces[0],
3591 NULL, NULL, &error);
3592 if (hs_bluez_id == 0) {
3593 ERR("Failed to register: %s", error->message);
3594 g_error_free(error);
3596 g_dbus_node_info_unref(node_info);
3600 g_dbus_node_info_unref(node_info);
3602 node_info = __bt_ag_create_method_node_info
3603 (ag_agent_app_introspection_xml);
3604 if (node_info == NULL)
3607 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3608 DBG("path is [%s]", path);
3610 app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3611 node_info->interfaces[0],
3613 NULL, NULL, &error);
3615 ERR("Failed to register: %s", error->message);
3616 g_error_free(error);
3618 g_dbus_node_info_unref(node_info);
3622 g_dbus_node_info_unref(node_info);
3628 static void __bt_ag_unregister_profile_methods(void)
3632 if (hf_bluez_id > 0) {
3633 g_dbus_connection_unregister_object(ag_dbus_conn,
3638 if (hs_bluez_id > 0) {
3639 g_dbus_connection_unregister_object(ag_dbus_conn,
3645 g_dbus_connection_unregister_object(ag_dbus_conn,
3651 static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
3652 const gchar *path, const gchar *interface)
3654 return (service_gproxy) ? service_gproxy :
3655 __bt_ag_gdbus_init_service_proxy(service,
3659 static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
3660 char *profile_uuid, const char* profile_name)
3665 GError *error = NULL;
3666 GVariantBuilder *builder;
3668 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3669 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3674 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3676 g_variant_builder_add(builder, "{sv}",
3677 "Name", g_variant_new("s",
3679 g_variant_builder_add(builder, "{sv}",
3680 "Version", g_variant_new("q", profile_version));
3681 /*g_variant_builder_add(builder, "{sv}",
3682 "Role", g_variant_new("s","client"));*/
3683 if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
3684 g_variant_builder_add(builder, "{sv}",
3685 "features", g_variant_new("q", ag.sdp_features));
3688 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3689 g_variant_new("(osa{sv})", path,
3690 profile_uuid, builder),
3691 G_DBUS_CALL_FLAGS_NONE, -1,
3693 g_variant_builder_unref(builder);
3694 /* set the name and role for the profile*/
3696 /* dBUS-RPC is failed */
3697 ERR("dBUS-RPC is failed");
3699 if (error != NULL) {
3700 /* dBUS gives error cause */
3701 ERR("D-Bus API failure: errCode[%x], message[%s]",
3702 error->code, error->message);
3704 g_clear_error(&error);
3709 g_variant_unref(ret);
3716 static void __bt_ag_agent_unregister(gchar *path)
3721 GError *error = NULL;
3723 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3724 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3729 ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
3730 g_variant_new("(o)", path),
3731 G_DBUS_CALL_FLAGS_NONE, -1,
3734 /* set the name and role for the profile*/
3736 /* dBUS-RPC is failed */
3737 ERR("dBUS-RPC is failed");
3739 if (error != NULL) {
3740 /* dBUS gives error cause */
3741 ERR("D-Bus API failure: errCode[%x], message[%s]",
3742 error->code, error->message);
3744 g_clear_error(&error);
3748 g_variant_unref(ret);
3758 static void __bt_ag_agent_battery_status_cb(keynode_t *node)
3760 int batt = vconf_keynode_get_int(node);
3762 _bt_hfp_set_property_value("BatteryBarsChanged", batt);
3765 static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
3767 int signal_bar = vconf_keynode_get_int(node);
3769 BT_CHECK_SIGNAL_STRENGTH(signal_bar);
3770 _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
3773 static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
3775 gboolean status = vconf_keynode_get_bool(node);
3777 DBG("status = %d", status);
3779 if (status == TRUE) {
3780 for (l = active_devices; l; l = l->next) {
3781 bt_ag_info_t *data = l->data;
3782 _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
3787 static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
3789 int service = vconf_keynode_get_int(node);
3790 bt_hfp_agent_network_registration_status_t network_service;
3794 DBG("Current Signal Level = [%d] \n", service);
3797 case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
3798 case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
3799 case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
3807 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
3809 ERR("Get roaming status failed err = %d\n", ret);
3813 if (roam_status == 0 && service == 1)
3814 network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
3815 else if (roam_status == 1 && service == 1)
3816 network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
3818 network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
3820 _bt_hfp_set_property_value("RegistrationChanged", network_service);
3823 static void __bt_ag_agent_subscribe_vconf_updates(void)
3829 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3830 (void *)__bt_ag_agent_battery_status_cb, NULL);
3832 ERR("Subsrciption to battery status failed err = [%d]\n", ret);
3834 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
3835 (void *)__bt_ag_agent_network_signal_status_cb, NULL);
3837 ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
3839 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3840 (void *)__bt_ag_agent_network_register_status_cb, NULL);
3842 ERR("Subsrciption to network failed err = [%d]\n", ret);
3844 if (TIZEN_PROFILE_WEARABLE) {
3845 ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
3846 (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
3848 ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
3852 static void __bt_ag_agent_release_vconf_updates(void)
3858 ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3859 (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
3861 ERR("vconf_ignore_key_changed failed\n");
3863 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
3864 (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
3866 ERR("vconf_ignore_key_changed failed\n");
3868 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3869 (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
3871 ERR("vconf_ignore_key_changed failed\n");
3874 static gboolean __bt_ag_agent_send_subscriber_number_changed(
3877 const char *property = g_strdup("SubscriberNumberChanged");
3881 DBG("Number is %s", number);
3883 if (!_bt_hfp_set_property_name(property, number)) {
3884 DBG("Error- set property for subscriber no change - ERROR\n");
3885 g_free((void *)property);
3888 g_free((void *)property);
3892 static void __bt_ag_agent_sigterm_handler(int signo)
3897 ERR_C("***** Signal handler came with signal %d *****", signo);
3899 for (l = active_devices ; l; l = l->next) {
3900 bt_ag_info_t *data = l->data;
3901 if (!__bt_ag_agent_connection_release(data))
3902 ERR("__bt_ag_agent_connection_release failed");
3905 g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
3908 g_main_loop_quit(gmain_loop);
3912 INFO("Terminating AG agent");
3916 if (signo == SIGTERM)
3919 for (i = 0; i < BT_AG_SIG_NUM; i++)
3920 sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
3925 static void __bt_ag_agent_tel_cb(TapiHandle *handle,
3930 TelSimMsisdnList_t *number;
3931 gchar *subscriber_number;
3933 ERR("*********** result = %d", result);
3935 if (result == TAPI_API_SIM_LOCKED ||
3936 result == TAPI_API_SIM_NOT_INITIALIZED ||
3937 result == TAPI_API_SERVICE_NOT_READY) {
3938 DBG("initializing the tapi event for SIM status");
3939 __bt_ag_agent_reg_sim_event(handle, user_data);
3946 number = (TelSimMsisdnList_t *)data;
3947 subscriber_number = g_strdup(number->list[0].num);
3948 __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
3949 g_free(subscriber_number);
3952 static void __bt_ag_agent_on_noti_sim_status(TapiHandle *handle,
3953 const char *noti_id, void *data, void *user_data)
3955 TelSimCardStatus_t *status = data;
3958 DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
3960 if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
3961 __bt_ag_agent_dereg_sim_event(handle);
3962 tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
3964 if (tapi_result != TAPI_API_SUCCESS)
3965 ERR("Fail to get sim info: %d", tapi_result);
3969 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data)
3972 ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
3973 __bt_ag_agent_on_noti_sim_status, user_data);
3975 if (ret != TAPI_API_SUCCESS)
3976 ERR("event register failed(%d)", ret);
3979 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle)
3982 ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
3984 if (ret != TAPI_API_SUCCESS)
3985 ERR("event deregister failed(%d)", ret);
3988 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
3989 const gchar *sender_name,
3990 const gchar *object_path,
3991 const gchar *interface_name,
3992 const gchar *signal_name,
3993 GVariant *parameters,
3997 char *name_owner = NULL;
3998 char *old_owner = NULL;
3999 char *new_owner = NULL;
4001 if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
4004 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
4006 _bt_hfp_release_all_calls_by_sender(name_owner);
4008 if (sco_owner == NULL)
4011 if (strcasecmp(name_owner, sco_owner) == 0) {
4012 if (name_owner_sig_id != -1)
4013 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4015 name_owner_sig_id = -1;
4019 for (l = active_devices ; l; l = l->next) {
4020 bt_ag_info_t *data = l->data;
4023 __bt_ag_close_sco(data);
4024 _bt_ag_set_headset_state(data,
4025 HEADSET_STATE_CONNECTED);
4032 static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
4033 const gchar *sender_name,
4034 const gchar *object_path,
4035 const gchar *interface_name,
4036 const gchar *signal_name,
4037 GVariant *parameters,
4042 GVariant *optional_param = NULL;
4044 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
4045 g_variant_get(parameters, "(&o@a{sa{sv}})", &path, &optional_param);
4048 g_variant_unref(optional_param);
4049 ERR("Invalid adapter path");
4053 INFO("Adapter Path = [%s]", path);
4054 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4055 gchar *obj_path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4056 __bt_ag_agent_register(obj_path, hfp_ver,
4057 HFP_AG_UUID, "Hands-Free Audio Gateway");
4059 obj_path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4060 __bt_ag_agent_register(obj_path, hsp_ver,
4061 HSP_AG_UUID, "Headset Audio Gateway");
4063 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
4064 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
4067 g_variant_unref(optional_param);
4068 ERR("Invalid adapter path");
4072 INFO("Adapter Path = [%s]", path);
4073 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4074 gchar *obj_path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4075 __bt_ag_agent_unregister(obj_path);
4077 obj_path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4078 __bt_ag_agent_unregister(obj_path);
4083 g_variant_unref(optional_param);
4088 static void __bt_ag_agent_dbus_deinit(void)
4091 if (service_gproxy) {
4092 g_object_unref(service_gproxy);
4093 service_gproxy = NULL;
4097 g_object_unref(app_gproxy);
4102 __bt_ag_unregister_profile_methods();
4104 if (interface_added_sig_id)
4105 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4106 interface_added_sig_id);
4108 if (interface_removed_sig_id)
4109 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4110 interface_removed_sig_id);
4112 if (name_owner_sig_id)
4113 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4115 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4117 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4121 if (media_state_sig_id)
4122 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4123 media_state_sig_id);
4124 media_state_sig_id = 0;
4127 interface_added_sig_id = 0;
4128 interface_removed_sig_id = 0;
4129 name_owner_sig_id = 0;
4133 g_object_unref(ag_dbus_conn);
4134 ag_dbus_conn = NULL;
4139 static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
4142 GDBusProxy *manager_proxy = NULL;
4143 GVariant *result = NULL;
4144 char *adapter_path = NULL;
4147 return BT_HFP_AGENT_ERROR_INTERNAL;
4149 manager_proxy = g_dbus_proxy_new_sync(conn,
4150 G_DBUS_PROXY_FLAGS_NONE, NULL,
4153 BT_MANAGER_INTERFACE,
4156 if (!manager_proxy) {
4157 ERR("Unable to create proxy: %s", err->message);
4161 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
4162 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
4165 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
4167 ERR("Fail to get DefaultAdapter");
4172 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
4173 ERR("Incorrect result\n");
4177 g_variant_get(result, "(&o)", &adapter_path);
4179 if (adapter_path == NULL ||
4180 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
4181 ERR("Adapter path is inproper\n");
4186 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
4188 g_variant_unref(result);
4189 g_object_unref(manager_proxy);
4194 g_clear_error(&err);
4197 g_variant_unref(result);
4200 g_object_unref(manager_proxy);
4202 return BT_HFP_AGENT_ERROR_INTERNAL;
4206 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4207 void _bt_ag_agent_check_transport_state(void)
4211 if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
4215 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
4216 G_DBUS_PROXY_FLAGS_NONE, NULL,
4217 "org.PulseAudio2", A2DP_SOURCE_ENDPOINT,
4218 BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
4222 ERR("Unable to create proxy: %s", err->message);
4223 g_clear_error(&err);
4227 INFO_C("SuspendMedia initiated");
4229 g_dbus_proxy_call(proxy,
4230 "SuspendMedia", NULL,
4231 G_DBUS_CALL_FLAGS_NONE, 2000,
4233 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4239 static void __bt_ag_agent_transport_state_update(const char *value)
4242 if (!g_strcmp0(value, "idle"))
4243 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4244 else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
4245 transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
4247 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4249 INFO_C("transport_state %d", transport_state);
4252 static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
4253 const gchar *sender_name,
4254 const gchar *object_path,
4255 const gchar *interface_name,
4256 const gchar *signal_name,
4257 GVariant *parameters,
4262 GVariant *dict_param = NULL;
4263 GVariant *optional_param = NULL;
4265 if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
4266 if (g_strcmp0(g_variant_get_type_string(parameters),
4268 ERR("Incorrect parameters\n");
4272 g_variant_get(parameters, "(&s@a{sv}@as)",
4273 &inter, &dict_param, &optional_param);
4274 if (dict_param && (!g_strcmp0(inter,
4275 BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
4276 GVariantIter *iter = NULL;
4277 const gchar *key = NULL;
4278 GVariant *value_var = NULL;
4279 gchar *value = NULL;
4280 g_variant_get(dict_param, "a{sv}", &iter);
4281 while (g_variant_iter_loop(
4282 iter, "{sv}", &key, &value_var)) {
4284 if (g_strcmp0(key, "State") == 0) {
4285 value = (gchar *)g_variant_get_string(
4288 DBG("value %s", value);
4289 __bt_ag_agent_transport_state_update(value);
4293 g_variant_iter_free(iter);
4295 } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
4296 char *profile_uuid = NULL;
4299 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
4300 if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
4301 (state == BT_PROFILE_STATE_DISCONNECTED)) {
4302 DBG("Updating the transport state");
4303 __bt_ag_agent_transport_state_update("Disconnect");
4308 g_variant_unref(dict_param);
4311 g_variant_unref(optional_param);
4316 static void __bt_ag_agent_dbus_init(void)
4320 if (__bt_ag_get_gdbus_connection() == NULL) {
4321 ERR("Error in creating the gdbus connection\n");
4324 if (!__bt_ag_register_profile_methods()) {
4325 ERR("Error in HFP / HSP register_profile_methods\n");
4329 if (!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
4331 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4332 __bt_ag_agent_register(path, hfp_ver,
4333 HFP_AG_UUID, "Hands-Free Audio Gateway");
4335 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4336 __bt_ag_agent_register(path, hsp_ver,
4337 HSP_AG_UUID, "Headset Audio Gateway");
4340 interface_added_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4341 NULL, BT_MANAGER_INTERFACE,
4342 BT_INTERFACES_ADDED, NULL, NULL, 0,
4343 __bt_ag_agent_filter_cb, NULL, NULL);
4345 interface_removed_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4346 NULL, BT_MANAGER_INTERFACE,
4347 BT_INTERFACES_REMOVED, NULL, NULL, 0,
4348 __bt_ag_agent_filter_cb, NULL, NULL);
4350 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4351 media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4352 NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
4353 NULL, 0, __bt_ag_agent_media_filter_cb,
4356 media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4357 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
4358 NULL, 0, __bt_ag_agent_media_filter_cb,
4361 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4367 static uint32_t __bt_ag_agent_get_ag_features(void)
4370 uint32_t ag_features;
4372 if (TIZEN_MODEL_NAME_TM1) {
4373 ag_features = BT_AG_FEATURE_EC_AND_NR |
4374 BT_AG_FEATURE_REJECT_CALL |
4375 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4376 BT_AG_FEATURE_THREE_WAY_CALL |
4377 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4379 ag_features = BT_AG_FEATURE_EC_AND_NR |
4380 BT_AG_FEATURE_REJECT_CALL |
4381 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4382 BT_AG_FEATURE_THREE_WAY_CALL |
4383 BT_AG_FEATURE_VOICE_RECOGNITION |
4384 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4388 #if defined(TIZEN_FEATURE_BT_HFP_AG)
4389 hfp_ver = HFP_VERSION_1_7;
4391 hfp_ver = HFP_VERSION_1_5;
4393 hsp_ver = HSP_VERSION_1_2;
4395 if (hfp_ver > HFP_VERSION_1_5)
4396 ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
4397 if (hfp_ver == HFP_VERSION_1_7)
4398 ag_features |= BT_AG_FEATURE_ESCO_S4_T2_SUPPORT;
4403 void *__bt_ag_agent_telephony_init(void *arg)
4407 uint32_t ag_features = *((uint32_t *)arg);
4409 INFO_C("Initializing the telephony info");
4411 _bt_hfp_initialize_telephony_manager(ag_features);
4412 __bt_ag_agent_subscribe_vconf_updates();
4414 tapi_handle = tel_init(NULL);
4415 tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
4417 if (tapi_result != TAPI_API_SUCCESS)
4418 ERR("Fail to get sim info: %d", tapi_result);
4425 uint32_t ag_features;
4426 struct sigaction sa;
4427 pthread_t thread_id = 0;
4429 INFO_C("### Starting Bluetooth AG agent");
4431 ag_features = __bt_ag_agent_get_ag_features();
4433 ag.sdp_features = (uint16_t) ag_features & 0x1F;
4435 if (hfp_ver >= HFP_VERSION_1_6 && wbs_en == TRUE)
4436 ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
4438 memset(&sa, 0, sizeof(sa));
4439 sa.sa_flags = SA_NOCLDSTOP;
4440 sa.sa_handler = __bt_ag_agent_sigterm_handler;
4442 for (i = 0; i < BT_AG_SIG_NUM; i++)
4443 sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
4445 gmain_loop = g_main_loop_new(NULL, FALSE);
4447 if (gmain_loop == NULL) {
4448 ERR("GMainLoop create failed");
4449 return EXIT_FAILURE;
4452 __bt_ag_agent_dbus_init();
4453 if (pthread_create(&thread_id, NULL,
4454 (void *)&__bt_ag_agent_telephony_init,
4455 &ag_features) < 0) {
4456 ERR("pthread_create() is failed");
4457 return EXIT_FAILURE;
4460 if (pthread_detach(thread_id) < 0)
4461 ERR("pthread_detach() is failed");
4463 g_main_loop_run(gmain_loop);
4467 tel_deinit(tapi_handle);
4469 __bt_ag_agent_dbus_deinit();
4470 _bt_hfp_deinitialize_telephony_manager();
4471 __bt_ag_agent_release_vconf_updates();
4473 if (remote_dev_path)
4474 g_free(remote_dev_path);
4477 g_main_loop_unref(gmain_loop);
4479 INFO_C("### Terminating Bluetooth AG agent");