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 /* LCOV_EXCL_START */
229 static void __bt_convert_addr_type_to_rev_string(char *address,
232 ret_if(address == NULL);
233 ret_if(addr == NULL);
235 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
236 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
237 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
240 static GDBusProxy *__bt_ag_gdbus_init_service_proxy(const gchar *service,
241 const gchar *path, const gchar *interface)
248 if (ag_dbus_conn == NULL)
249 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
253 ERR("Unable to connect to gdbus: %s", err->message);
259 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
260 G_DBUS_PROXY_FLAGS_NONE, NULL,
262 interface, NULL, &err);
266 ERR("Unable to create proxy: %s", err->message);
276 static GDBusProxy *__bt_ag_gdbus_get_app_proxy(const gchar *service,
277 const gchar *path, const gchar *interface)
279 return (app_gproxy) ? app_gproxy :
280 __bt_ag_gdbus_init_service_proxy(service,
284 static int __bt_ag_agent_gdbus_method_send(const char *service,
285 const gchar *path, const char *interface,
286 const char *method, gboolean response,
287 GVariant *parameters)
293 GError *error = NULL;
295 proxy = __bt_ag_gdbus_get_app_proxy(service, path, interface);
297 return BT_HFP_AGENT_ERROR_INTERNAL;
300 ret = g_dbus_proxy_call_sync(proxy,
302 G_DBUS_CALL_FLAGS_NONE, -1,
305 /* dBUS-RPC is failed */
306 ERR("dBUS-RPC is failed");
308 /* dBUS gives error cause */
309 ERR("D-Bus API failure: errCode[%x], message[%s]",
310 error->code, error->message);
312 g_clear_error(&error);
314 return BT_HFP_AGENT_ERROR_INTERNAL;
317 g_variant_unref(ret);
319 g_dbus_proxy_call(proxy,
321 G_DBUS_CALL_FLAGS_NONE, 2000,
324 return BT_HFP_AGENT_ERROR_NONE;
328 gboolean _bt_ag_agent_emit_signal(
329 GDBusConnection *connection,
331 const char *interface,
337 GError *error = NULL;
339 ret = g_dbus_connection_emit_signal(connection,
340 NULL, path, interface,
345 /* LCOV_EXCL_START */
346 /* dBUS gives error cause */
347 ERR("D-Bus API failure: errCode[%x], message[%s]",
348 error->code, error->message);
349 g_clear_error(&error);
353 INFO_C("Emit Signal done = [%s]", name);
359 gboolean _bt_ag_agent_emit_property_changed(
360 GDBusConnection *connection,
362 const char *interface,
371 var_data = g_variant_new("(sv)", name, property);
373 ret = _bt_ag_agent_emit_signal(connection,
375 "PropertyChanged", var_data);
380 /* LCOV_EXCL_START */
381 static void __bt_ag_agent_start_watch(bt_ag_info_t *bt_ag_info)
383 bt_ag_info->watch_id = g_io_add_watch(bt_ag_info->io_chan,
384 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
385 (GIOFunc) __bt_ag_event_handler, bt_ag_info);
388 static void __bt_ag_agent_remove_watch(guint *watch_id)
390 DBG("Remove IO watch ID %d", *watch_id);
392 g_source_remove(*watch_id);
397 #if defined(TIZEN_SUPPORT_DUAL_HF)
398 gboolean __bt_ag_agent_is_companion_device(const char *addr)
400 #if defined(TIZEN_PROFILE_WEARABLE)
401 char *host_device_address = NULL;
402 host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR);
404 if (!host_device_address) {
405 INFO("Failed to get a companion device address");
409 if (g_strcmp0(host_device_address, addr) == 0) {
410 INFO("addr[%s] is companion device", addr);
416 /* TODO : Need to add companion device check condition for Phone models */
421 void __bt_convert_device_path_to_address(const gchar *device_path,
422 char *device_address)
424 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
427 ret_if(device_path == NULL);
428 ret_if(device_address == NULL);
430 dev_addr = strstr(device_path, "dev_");
431 if (dev_addr != NULL) {
434 g_strlcpy(address, dev_addr, sizeof(address));
436 while ((pos = strchr(address, '_')) != NULL)
439 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
443 static gboolean __bt_ag_agent_is_companion_device_connected(void)
447 for (l = active_devices ; l; l = l->next) {
448 bt_ag_info_t *data = l->data;
450 if (data->is_companion_device) {
451 DBG("Companion device found");
459 gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
461 char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
462 gboolean is_companion_device;
464 __bt_convert_device_path_to_address(device_path, device_address);
465 is_companion_device = __bt_ag_agent_is_companion_device(device_address);
467 DBG(" device_address[%s]", device_address);
468 DBG(" is_companion_device[%d]", is_companion_device);
470 if (__bt_ag_agent_is_companion_device_connected()) {
471 if (is_companion_device)
474 if (!is_companion_device)
479 #endif /* TIZEN_SUPPORT_DUAL_HF */
482 static gboolean __bt_is_phone_locked(int *phone_lock_state)
487 if (NULL == phone_lock_state)
490 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, phone_lock_state);
492 /* LCOV_EXCL_START */
493 ERR("Failed to read [%s]\n", VCONFKEY_IDLE_LOCK_STATE);
502 static gboolean __bt_get_outgoing_callapp_type(int *callapp_type)
506 if (NULL == callapp_type)
509 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
510 *callapp_type = BT_VOICE_CALL;
517 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT,
520 ERR("Failed to read [%s]\n",
521 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT);
525 INFO(" [%s] = [%d]\n",
526 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT, *callapp_type);
528 /* The vconf value does not include in platform. */
529 *callapp_type = BT_VOICE_CALL;
535 static gboolean __bt_get_outgoing_call_condition(int *condition)
539 if (NULL == condition)
542 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
543 *condition = BT_MO_ONLY_UNLOCKED;
550 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT,
553 ERR("Failed to read [%s]\n",
554 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT);
558 /* The vconf value does not include in platform. */
559 *condition = BT_MO_ONLY_UNLOCKED;
565 /* LCOV_EXCL_START */
566 static gboolean __bt_ag_agent_launch_call_app(const char *number)
571 DBG_SECURE("number(%s)", number);
575 ERR("bundle_create() Failed");
579 bundle_add(b, "launch-type", "MO");
580 bundle_add(b, "dial-type", "HEADSET");
582 if (strlen(number) != 0)
583 bundle_add(b, "number", number);
585 aul_launch_app_async(CALL_APP_ID, b);
592 static void *__bt_ag_agent_launch_call_req(void *arg)
595 bundle *b = (bundle *)arg;
596 if (appsvc_run_service(b, 0, NULL, NULL) < 0)
597 ERR("Unable to run app svc");
599 call_launch_requested = FALSE;
604 static gboolean __bt_ag_agent_make_call(const char *number)
608 char telnum[BT_MAX_TEL_NUM_STRING];
612 if (TIZEN_PROFILE_WEARABLE)
613 return __bt_ag_agent_launch_call_app(number);
615 if (call_launch_requested == TRUE) {
616 DBG("Launch request is in progress");
624 appsvc_set_operation(b, APPSVC_OPERATION_CALL);
625 snprintf(telnum, sizeof(telnum), "tel:%s", number);
626 appsvc_set_uri(b, telnum);
627 appsvc_add_data(b, "ctindex", "-1");
629 call_launch_requested = TRUE;
630 if (pthread_create(&thread_id, NULL,
631 (void *)&__bt_ag_agent_launch_call_req,
633 ERR("pthread_create() is failed");
634 call_launch_requested = FALSE;
637 if (pthread_detach(thread_id) < 0)
638 ERR("pthread_detach() is failed");
644 static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
649 kb = bundle_create();
653 bundle_add(kb, "KEY_CALL_TYPE", "MO");
654 bundle_add(kb, "number", mo_number);
655 aul_launch_app("org.tizen.vtmain", kb);
662 gboolean _bt_ag_agent_answer_call(unsigned int call_id,
663 const gchar *path, const gchar *sender)
667 if (path == NULL || sender == NULL) {
668 DBG("Invalid Arguments");
672 DBG("Application path = %s", path);
673 DBG("Call Id = %d", call_id);
674 DBG("Sender = %s", sender);
676 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
677 BT_AG_SERVICE_NAME, "Answer",
678 g_variant_new("(u)", call_id));
683 gboolean _bt_ag_agent_reject_call(unsigned int call_id,
684 const gchar *path, const gchar *sender)
688 if (path == NULL || sender == NULL) {
689 DBG("Invalid Arguments");
693 DBG("Application path = %s", path);
694 DBG("Call Id = %d", call_id);
695 DBG("Sender = %s", sender);
697 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
698 BT_AG_SERVICE_NAME, "Reject",
699 g_variant_new("(u)", call_id));
704 gboolean _bt_ag_agent_release_call(unsigned int call_id,
705 const gchar *path, const gchar *sender)
709 if (path == NULL || sender == NULL) {
710 DBG("Invalid Arguments");
714 DBG("Application path = %s", path);
715 DBG("Call Id = %d", call_id);
716 DBG("Sender = %s", sender);
718 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
719 BT_AG_SERVICE_NAME, "Release",
720 g_variant_new("(u)", call_id));
727 bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
729 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
731 int phone_lock_state;
736 if (number == NULL) {
737 ERR("Invalid Argument");
738 error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
742 DBG("Number = %s", number);
743 DBG("flags = %d", flags);
745 if (!__bt_is_phone_locked(&phone_lock_state)) {
746 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
750 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
751 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
755 if (!__bt_get_outgoing_call_condition(&condition)) {
756 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
760 if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
761 VCONFKEY_IDLE_LOCK) {
762 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
766 /* LCOV_EXCL_START */
767 if (callapp_type == BT_VIDEO_CALL) {
768 if (!__bt_ag_agent_make_video_call(number)) {
769 ERR("Problem launching application");
770 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
774 if (!__bt_ag_agent_make_call(number)) {
775 ERR("Problem launching application");
776 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
787 bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
789 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
791 contacts_filter_h filter = NULL;
792 contacts_query_h query = NULL;
793 contacts_list_h list = NULL;
794 contacts_record_h record = NULL;
795 unsigned int projections[] = {
796 _contacts_speeddial.number,
801 DBG("location = %d", location);
803 /*Get number from contacts location*/
804 if (contacts_connect() != CONTACTS_ERROR_NONE) {
805 ERR(" contacts_connect failed");
806 return BT_HFP_AGENT_ERROR_INTERNAL;
809 /* LCOV_EXCL_START */
810 contacts_filter_create(_contacts_speeddial._uri, &filter);
815 if (contacts_filter_add_int(filter,
816 _contacts_speeddial.speeddial_number,
817 CONTACTS_MATCH_EQUAL, location) !=
818 CONTACTS_ERROR_NONE) {
819 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
823 contacts_query_create(_contacts_speeddial._uri, &query);
828 contacts_query_set_filter(query, filter);
830 if (contacts_query_set_projection(query, projections,
831 sizeof(projections)/sizeof(unsigned int)) !=
832 CONTACTS_ERROR_NONE) {
833 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
837 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
838 CONTACTS_ERROR_NONE) {
839 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
843 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
844 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
848 if (contacts_list_get_current_record_p(list, &record) !=
849 CONTACTS_ERROR_NONE) {
850 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
857 if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
858 != CONTACTS_ERROR_NONE) {
859 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
863 if (number == NULL) {
864 ERR("No number at the location");
865 error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
869 DBG("number %s", number);
872 if (!__bt_ag_agent_make_call(number)) {
873 ERR("Problem launching application");
874 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
880 contacts_list_destroy(list, TRUE);
883 contacts_filter_destroy(filter);
886 contacts_query_destroy(query);
888 contacts_disconnect();
896 /* LCOV_EXCL_START */
897 bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
898 const gchar *path, const gchar *sender)
900 bt_hfp_agent_error_t ret;
904 if (dtmf == NULL || path == NULL || sender == NULL) {
905 ERR("Invalid Argument");
906 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
909 DBG("Dtmf = %s", dtmf);
910 DBG("Application path = %s", path);
911 DBG("Sender = %s", sender);
913 ret = __bt_ag_agent_gdbus_method_send(sender,
914 path, TELEPHONY_APP_INTERFACE,
916 g_variant_new("(s)", dtmf));
921 gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
922 const gchar *path, const gchar *sender)
926 if (path == NULL || sender == NULL) {
927 DBG("Invalid Arguments");
931 DBG("Application path = %s", path);
932 DBG("Value = %d", chld_value);
933 DBG("Sender = %s", sender);
935 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
936 /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
937 if not return FALSE */
938 if (chld_value != 0 && chld_value != 1 && chld_value != 2)
941 if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
945 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
946 BT_AG_SERVICE_NAME, "Threeway",
947 g_variant_new("(u)", chld_value));
953 bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
955 bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
956 char *last_num = NULL;
959 int phone_lock_state;
961 contacts_list_h list = NULL;
962 contacts_query_h query = NULL;
963 contacts_filter_h filter = NULL;
964 contacts_record_h record = NULL;
965 unsigned int projections[] = {
966 _contacts_phone_log.address,
967 _contacts_phone_log.log_type,
972 if (contacts_connect() != CONTACTS_ERROR_NONE) {
973 ERR(" contacts_connect failed");
974 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
978 /* LCOV_EXCL_START */
979 contacts_filter_create(_contacts_phone_log._uri, &filter);
984 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
985 CONTACTS_MATCH_EQUAL,
986 CONTACTS_PLOG_TYPE_VOICE_OUTGOING) !=
987 CONTACTS_ERROR_NONE) {
988 ERR(" contacts_filter_add_int failed");
989 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
993 if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) !=
994 CONTACTS_ERROR_NONE) {
995 ERR(" contacts_filter_add_operator failed");
996 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1000 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
1001 CONTACTS_MATCH_EQUAL,
1002 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) !=
1003 CONTACTS_ERROR_NONE) {
1004 ERR(" contacts_filter_add_int failed");
1005 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1009 contacts_query_create(_contacts_phone_log._uri, &query);
1014 contacts_query_set_filter(query, filter);
1016 if (contacts_query_set_projection(query, projections,
1017 sizeof(projections)/sizeof(unsigned int)) !=
1018 CONTACTS_ERROR_NONE) {
1019 ERR(" contacts_query_set_projection failed");
1020 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1024 if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false)
1025 != CONTACTS_ERROR_NONE) {
1026 ERR(" contacts_query_set_sort failed");
1027 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1031 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
1032 CONTACTS_ERROR_NONE) {
1033 ERR(" contacts_db_get_records_with_query failed");
1034 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1038 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
1039 ERR(" contacts_list_first failed");
1040 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1044 if (contacts_list_get_current_record_p(list, &record) !=
1045 CONTACTS_ERROR_NONE) {
1046 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1053 if (contacts_record_get_str(record, _contacts_phone_log.address,
1054 &last_num) != CONTACTS_ERROR_NONE) {
1055 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1059 if (last_num == NULL) {
1060 ERR("No last number");
1061 err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
1065 if (!__bt_is_phone_locked(&phone_lock_state)) {
1066 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1070 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
1071 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1075 if (!__bt_get_outgoing_call_condition(&condition)) {
1076 ERR(" Failed to get the call condition");
1077 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1081 if (condition == BT_MO_ONLY_UNLOCKED &&
1082 phone_lock_state == VCONFKEY_IDLE_LOCK) {
1083 ERR(" call condition and phone lock state check fail");
1084 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1088 switch (callapp_type) {
1090 if (!__bt_ag_agent_make_call(last_num)) {
1091 ERR("Problem launching application");
1092 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1096 if (!__bt_ag_agent_make_video_call(last_num)) {
1097 ERR("Problem launching application");
1098 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1101 case BT_FOLLOW_CALL_LOG:
1102 if (contacts_record_get_int(record,
1103 _contacts_phone_log.log_type,
1104 &type) != CONTACTS_ERROR_NONE) {
1105 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1108 if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
1109 if (!__bt_ag_agent_make_call(last_num)) {
1110 ERR("Problem launching application");
1111 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1113 } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
1114 if (!__bt_ag_agent_make_video_call(last_num)) {
1115 ERR("Problem launching application");
1116 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1119 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1123 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1130 contacts_list_destroy(list, TRUE);
1133 contacts_filter_destroy(filter);
1136 contacts_query_destroy(query);
1138 contacts_disconnect();
1140 if (last_num != NULL)
1146 /* LCOV_EXCL_STOP */
1149 /* LCOV_EXCL_START */
1150 bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
1151 const gchar *path, const gchar *sender)
1153 bt_hfp_agent_error_t ret;
1157 if (cmd == NULL || path == NULL || sender == NULL) {
1158 ERR("Invalid Argument");
1159 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
1162 DBG("cmd = %s", cmd);
1163 DBG("Application path = %s", path);
1164 DBG("Sender = %s", sender);
1166 ret = __bt_ag_agent_gdbus_method_send(sender,
1167 path, TELEPHONY_APP_INTERFACE,
1169 g_variant_new("(s)", cmd));
1173 /* LCOV_EXCL_STOP */
1175 gboolean _bt_ag_agent_get_signal_quality(void *device)
1181 if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
1182 DBG("VCONFKEY_TELEPHONY_RSSI failed\n"); /* LCOV_EXCL_LINE */
1186 DBG("RSSI : %d", rssi);
1188 _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
1194 /* LCOV_EXCL_START */
1196 _bt_hfp_signal_quality_reply(-1, -1, device);
1198 /* LCOV_EXCL_STOP */
1201 gboolean _bt_ag_agent_get_battery_status(void *device)
1203 gint battery_chrg_status;
1204 gint battery_capacity;
1208 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
1209 &battery_chrg_status)) {
1210 DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n"); /* LCOV_EXCL_LINE */
1214 DBG("Status : %d\n", battery_chrg_status);
1216 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
1217 &battery_capacity)) {
1218 DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n"); /* LCOV_EXCL_LINE */
1222 DBG("Capacity : %d\n", battery_capacity);
1224 _bt_hfp_battery_property_reply(device,
1225 battery_chrg_status, battery_capacity);
1230 /* LCOV_EXCL_START */
1231 _bt_hfp_battery_property_reply(device, -1, -1);
1234 /* LCOV_EXCL_STOP */
1237 gboolean _bt_ag_agent_get_operator_name(void *device)
1239 char *operator_name;
1242 operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
1243 if (NULL == operator_name) {
1244 /* LCOV_EXCL_START */
1245 DBG("vconf_get_str failed");
1246 _bt_hfp_operator_reply(NULL, device);
1248 /* LCOV_EXCL_STOP */
1251 DBG("operator_name = [%s]", operator_name);
1253 _bt_hfp_operator_reply(operator_name, device);
1255 free(operator_name);
1261 gboolean _bt_hfp_agent_nrec_status(gboolean status,
1265 bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
1267 DBG("NREC status = %d", status);
1269 hs->nrec_status = FALSE;
1271 hs->nrec_status = TRUE;
1274 _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
1275 BT_AG_SERVICE_NAME, "NrecStatusChanged",
1276 g_variant_new("(b)", status));
1281 gboolean _bt_ag_agent_get_imei_number(void *device)
1286 imei_number = tel_get_misc_me_imei_sync(tapi_handle);
1287 if (NULL == imei_number) {
1288 ERR("tel_get_misc_me_imei_sync for imei_number failed");
1292 /* LCOV_EXCL_START */
1293 if (!g_utf8_validate(imei_number, -1, NULL)) {
1295 ERR("get_imei_number : invalid UTF8");
1299 DBG_SECURE("imei_number = [%s]", imei_number);
1300 _bt_hfp_get_imei_number_reply(imei_number, device);
1304 /* LCOV_EXCL_STOP */
1306 _bt_hfp_get_imei_number_reply(NULL, device);
1311 void _bt_ag_agent_get_manufacturer_name(void *device)
1314 char *manufacturer_name;
1317 ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
1318 &manufacturer_name);
1319 if (SYSTEM_INFO_ERROR_NONE != ret) {
1320 /* LCOV_EXCL_START */
1321 ERR("Get manufacturer_name failed : %d", ret);
1322 if (NULL != manufacturer_name)
1323 free(manufacturer_name);
1325 manufacturer_name = g_strdup("Unknown");
1326 /* LCOV_EXCL_STOP */
1327 } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
1328 /* LCOV_EXCL_START */
1329 free(manufacturer_name);
1330 manufacturer_name = g_strdup("Unknown");
1331 ERR("get_manufacturer_name : invalid UTF8");
1332 /* LCOV_EXCL_STOP */
1335 DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
1336 _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
1337 free(manufacturer_name);
1341 void _bt_ag_agent_get_imsi(void *device)
1344 TelSimImsiInfo_t imsi;
1345 memset(&imsi, 0, sizeof(TelSimImsiInfo_t));
1346 if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
1347 ERR("tel_get_sim_imsi failed");
1350 /* LCOV_EXCL_START */
1351 DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
1353 _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
1356 /* LCOV_EXCL_STOP */
1358 _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
1362 /* LCOV_EXCL_START */
1363 int _bt_ag_agent_registration_status_convert(int result)
1366 case TAPI_NETWORK_SERVICE_LEVEL_NO:
1367 return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
1368 case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
1369 return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
1370 case TAPI_NETWORK_SERVICE_LEVEL_FULL:
1371 return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
1372 case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
1373 return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
1375 return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
1379 /* LCOV_EXCL_STOP */
1381 void _bt_ag_agent_get_creg_status(void *device)
1387 int registration_status = 0;
1388 int roam_status = 0;
1390 ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
1392 if (ret != TAPI_API_SUCCESS) {
1393 ERR("tel_get_property_int failed");
1396 /* LCOV_EXCL_START */
1397 registration_status =
1398 _bt_ag_agent_registration_status_convert(result);
1400 DBG_SECURE("Registration status %d", result);
1401 DBG_SECURE("Mapped Status %d", registration_status);
1402 if (registration_status ==
1403 BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
1404 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
1406 ERR("Get roaming status failed err = %d\n", ret);
1409 DBG_SECURE("Roam status %d", roam_status);
1410 if (roam_status == 1) {
1411 registration_status =
1412 BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
1416 _bt_hfp_get_creg_status_reply(n, registration_status, device);
1420 /* LCOV_EXCL_STOP */
1423 void _bt_ag_agent_get_model_name(void *device)
1429 ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
1430 if (SYSTEM_INFO_ERROR_NONE != ret) {
1431 ERR("Get model_name failed: %d", ret);
1432 if (NULL != model_name)
1435 model_name = g_strdup("Unknown");
1436 } else if (!g_utf8_validate(model_name, -1, NULL)) {
1438 model_name = g_strdup("Unknown");
1439 ERR("get_model_name : invalid UTF8");
1442 DBG_SECURE("model_name = [%s]", model_name);
1443 _bt_hfp_get_model_info_reply(model_name, device);
1448 void _bt_ag_agent_get_revision_information(void *device)
1451 char *revision_info;
1454 ret = system_info_get_platform_string("http://tizen.org/system/build.string",
1456 if (SYSTEM_INFO_ERROR_NONE != ret) {
1457 ERR("Get revision_info failed: %d", ret);
1458 if (NULL != revision_info)
1459 free(revision_info);
1461 revision_info = g_strdup("Unknown");
1462 } else if (!g_utf8_validate(revision_info, -1, NULL)) {
1463 free(revision_info);
1464 revision_info = g_strdup("Unknown");
1465 ERR("get_revision_info: invalid UTF8");
1468 DBG_SECURE("revision_info = [%s]", revision_info);
1469 _bt_hfp_get_revision_info_reply(revision_info, device);
1470 free(revision_info);
1474 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
1475 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1480 b = bundle_create();
1482 ERR("bundle_create() Failed");
1486 bundle_add(b, "domain", "bt_headset");
1488 bundle_add(b, "action_type", "deactivate");
1490 aul_launch_app_async("org.tizen.svoice", b);
1496 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1499 app_control_h service = NULL;
1501 app_control_create(&service);
1503 if (service == NULL) {
1504 ERR("Service create failed");
1508 app_control_set_app_id(service, "org.tizen.svoice");
1509 app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
1510 if (app_control_add_extra_data(service, "domain", "bt_headset")
1511 != APP_CONTROL_ERROR_NONE) {
1512 ERR("app_control_add_extra_data failed");
1513 app_control_destroy(service);
1518 if (app_control_add_extra_data(service, "action_type", "deactivate")
1519 != APP_CONTROL_ERROR_NONE) {
1520 ERR("app_control_add_extra_data failed");
1521 app_control_destroy(service);
1525 if (app_control_send_launch_request(service, NULL, NULL) !=
1526 APP_CONTROL_ERROR_NONE) {
1527 ERR("launch failed");
1528 app_control_destroy(service);
1532 app_control_destroy(service);
1538 gboolean _bt_ag_agent_voice_dial(gboolean activate)
1540 DBG("Activate = %d", activate);
1542 return __bt_ag_agent_launch_voice_dial(activate);
1545 /* LCOV_EXCL_START */
1546 static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
1549 hs->codec_info.is_negotiating = FALSE;
1550 hs->codec_info.requested_by_hf = FALSE;
1551 hs->codec_info.sending_codec = 0;
1553 hs->codec_info.remote_codecs = 0;
1554 hs->codec_info.final_codec = 0;
1555 hs->nrec_status = FALSE;
1558 if (hs->codec_info.nego_timer) {
1559 g_source_remove(hs->codec_info.nego_timer);
1560 hs->codec_info.nego_timer = 0;
1562 wbs_opts.wbs_enable = wbs_en;
1565 static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
1567 struct ag_codec *data = (struct ag_codec *)user_data;
1569 if (g_strcmp0(data->codec_status, "finish") == 0) {
1570 DBG("Codec negotiation finished");
1571 __bt_ag_sco_connect(data->bt_ag_info);
1572 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1573 g_free(data->codec_status);
1576 } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
1577 DBG("Timeout is occured in codec negotiation");
1580 if (data->bt_ag_info->codec_info.requested_by_hf) {
1581 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1583 __bt_ag_sco_connect(data->bt_ag_info);
1584 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1586 g_free(data->codec_status);
1592 static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
1597 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
1599 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
1600 G_DBUS_PROXY_FLAGS_NONE, NULL,
1601 BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
1602 BT_ADAPTER_INTERFACE, NULL, &err);
1606 ERR("Unable to create proxy: %s", err->message);
1607 g_clear_error(&err);
1609 return BT_HFP_AGENT_ERROR_INTERNAL;
1612 ret = g_dbus_proxy_call_sync(proxy, method,
1613 g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
1614 G_DBUS_CALL_FLAGS_NONE, -1,
1617 /* dBUS-RPC is failed */
1618 ERR("dBUS-RPC is failed");
1620 /* dBUS gives error cause */
1621 ERR("D-Bus API failure: errCode[%x], message[%s]",
1622 err->code, err->message);
1624 g_clear_error(&err);
1626 return BT_HFP_AGENT_ERROR_INTERNAL;
1628 g_variant_unref(ret);
1630 return BT_HFP_AGENT_ERROR_NONE;
1633 static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
1636 bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
1638 DBG("Codec setup [%x]", codec);
1640 /* 1. Compare sending codec & recieved code */
1641 if (hs->codec_info.sending_codec != codec)
1642 err = BT_HFP_AGENT_ERROR_INTERNAL;
1644 /* 2. Send WB or NB command */
1646 case BT_CVSD_CODEC_ID:
1647 err = __bt_ag_set_codec(hs, "SetNbParameters");
1649 case BT_MSBC_CODEC_ID:
1650 err = __bt_ag_set_codec(hs, "SetWbsParameters");
1653 err = BT_HFP_AGENT_ERROR_INTERNAL;
1657 /* If the vendor specific calling returns error or codec is not correct,
1658 * we send CVSD Codec parameter to MM module. and also returns
1659 * normal value to HF
1661 if (err != BT_HFP_AGENT_ERROR_NONE)
1662 codec = BT_CVSD_CODEC_ID;
1664 hs->codec_info.final_codec = codec;
1669 static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
1670 gboolean init_by_hf)
1673 struct ag_codec *data = NULL;;
1675 if (TIZEN_MODEL_NAME_TM1) {
1676 codec = BT_CVSD_CODEC_ID;
1678 if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
1679 codec = BT_MSBC_CODEC_ID;
1681 codec = BT_CVSD_CODEC_ID;
1684 if (wbs_opts.wbs_enable == FALSE)
1685 codec = BT_CVSD_CODEC_ID;
1689 if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
1690 return BT_HFP_AGENT_ERROR_INTERNAL;
1692 DBG("Send +BCS:%d\n", codec);
1694 /* Send +BCS command to HF, and wait some times */
1695 hs->codec_info.is_negotiating = TRUE;
1696 hs->codec_info.sending_codec = codec;
1697 hs->codec_info.requested_by_hf = init_by_hf;
1698 hs->codec_info.final_codec = codec;
1700 data = g_new0(struct ag_codec, 1);
1702 return BT_HFP_AGENT_ERROR_NO_MEMORY;
1704 data->bt_ag_info = hs;
1705 data->codec_status = g_strdup("timeout");
1707 hs->codec_info.nego_timer = g_timeout_add_seconds(
1708 HFP_CODEC_NEGOTIATION_TIMEOUT,
1709 (GSourceFunc)__bt_ag_codec_negotiation_finished,
1712 return BT_HFP_AGENT_ERROR_NONE;
1716 static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
1717 bt_ag_info_t *hs, gboolean init_by_hf)
1719 DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
1721 if (hs->state < HEADSET_STATE_CONNECTED)
1722 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1724 if (hs->codec_info.is_negotiating == TRUE) {
1725 /* In codec negotiation, return and wait */
1726 ERR("Codec nogotiation is in progress");
1727 return BT_HFP_AGENT_ERROR_BUSY;
1730 /* Not support Codec Negotiation or Not recieved BAC command */
1731 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
1732 hs->codec_info.remote_codecs == 0) {
1733 ERR("No support for Codec Negotiation or receive BAC command");
1735 return BT_HFP_AGENT_ERROR_INTERNAL;
1737 __bt_ag_sco_connect(hs);
1738 return BT_HFP_AGENT_ERROR_INTERNAL;
1742 /* If HF initiated codec connection setup, it should send OK command
1743 * before +BCS command transmission.
1746 return HFP_STATE_MNGR_ERR_NONE;
1748 return __bt_hfp_send_bcs_command(hs, init_by_hf);
1752 static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
1755 *codecs = 0x00000000;
1757 str = strchr(cmd, '=');
1761 while (str != NULL) {
1764 if (atoi(str) == BT_CVSD_CODEC_ID)
1765 *codecs |= BT_CVSD_CODEC_MASK;
1766 else if (atoi(str) == BT_MSBC_CODEC_ID)
1767 *codecs |= BT_MSBC_CODEC_MASK;
1769 str = strchr(str, ',');
1772 if (*codecs == 0x00000000)
1778 /* AT+BAC (Bluetooth Available Codecs) */
1779 static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
1781 uint32_t codecs = 0x00000000;
1782 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1784 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
1785 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1786 } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
1787 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1789 DBG("Update remote available codecs [%x]", codecs);
1790 hs->codec_info.remote_codecs = codecs;
1793 _bt_ag_send_response(hs, err);
1795 /* Reset codec information and
1796 * restart codec connection setup by AG
1798 hs->codec_info.final_codec = 0;
1799 if (hs->codec_info.nego_timer) {
1800 hs->codec_info.is_negotiating = FALSE;
1801 hs->codec_info.requested_by_hf = FALSE;
1802 hs->codec_info.sending_codec = 0;
1803 g_source_remove(hs->codec_info.nego_timer);
1804 __bt_hfp_codec_connection_setup(hs, FALSE);
1810 /* AT+BCC (Bluetooth Codec Connection) */
1811 static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
1813 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1815 err = __bt_hfp_codec_connection_setup(hs, TRUE);
1817 _bt_ag_send_response(hs, err);
1819 if (err == HFP_STATE_MNGR_ERR_NONE)
1820 err = __bt_hfp_send_bcs_command(hs, TRUE);
1822 if (err != HFP_STATE_MNGR_ERR_NONE)
1823 ERR("Fail to request codec connection setup");
1828 /* AT+BCS (Bluetooth Codec Selection) */
1829 static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
1831 uint32_t codec = 0x00000000;
1832 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1833 struct ag_codec *data = g_new0(struct ag_codec, 1);
1836 if (hs->codec_info.nego_timer) {
1837 g_source_remove(hs->codec_info.nego_timer);
1838 hs->codec_info.nego_timer = 0;
1841 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
1842 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1843 else if (__hfp_parse_available_codecs(buf, &codec) < 0)
1844 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1845 else if (__bt_ag_codec_selection_setup(hs, codec) !=
1846 BT_HFP_AGENT_ERROR_NONE)
1847 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1849 data->bt_ag_info = hs;
1850 data->codec_status = g_strdup("finish");
1851 _bt_ag_send_response(hs, err);
1852 __bt_ag_codec_negotiation_finished(data);
1857 static void __bt_ag_str2ba(const char *str, bt_addr *ba)
1860 for (i = 5; i >= 0; i--, str += 3)
1861 ba->b[i] = strtol(str, NULL, 16);
1863 /* LCOV_EXCL_STOP */
1865 static const char *__bt_ag_state2str(hs_state_t state)
1868 case HEADSET_STATE_DISCONNECTED:
1869 return "disconnected";
1870 case HEADSET_STATE_CONNECTING:
1871 return "connecting";
1872 case HEADSET_STATE_CONNECTED:
1874 case HEADSET_STATE_PLAY_IN_PROGRESS:
1875 return "Play In Progress";
1876 case HEADSET_STATE_ON_CALL:
1883 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
1884 const char *address)
1889 ret_if(address == NULL);
1890 ret_if(addr == NULL);
1892 for (i = 0; i < 6; i++) {
1893 addr[5 - i] = strtol(address, &ptr, 16);
1894 if (ptr[0] != '\0') {
1903 /* LCOV_EXCL_START */
1904 static gboolean __bt_ag_check_nval(GIOChannel *chan)
1906 struct pollfd file_desc;
1908 memset(&file_desc, 0, sizeof(file_desc));
1909 file_desc.fd = g_io_channel_unix_get_fd(chan);
1910 file_desc.events = POLLNVAL;
1912 if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
1918 static int __bt_ag_sco_connect(bt_ag_info_t *hs)
1920 struct sco_socket_addr sco_addr;
1925 bt_ag_slconn_t *slconn = hs->slc;
1928 if (hs->state == HEADSET_STATE_ON_CALL)
1929 return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED;
1931 if (hs->state != HEADSET_STATE_CONNECTED)
1932 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1933 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
1934 _bt_ag_agent_check_transport_state();
1937 /* Create Sco socket */
1938 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
1940 ERR("ERROR: Create socket failed.\n");
1941 return BT_HFP_AGENT_ERROR_INTERNAL;
1944 /* Bind Sco Socket to Local BD addr */
1945 memset(&sco_addr, 0, sizeof(sco_addr));
1946 sco_addr.sco_family = AF_BLUETOOTH;
1948 __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
1949 DBG("Local BD address: %s", local_addr);
1951 err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1953 ERR("ERROR: sco socket binding failed");
1954 ERR("Close SCO skt");
1956 return BT_HFP_AGENT_ERROR_INTERNAL;
1959 DBG("Socket FD : %d", sco_skt);
1961 io = g_io_channel_unix_new(sco_skt);
1962 g_io_channel_set_close_on_unref(io, TRUE);
1963 /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
1964 g_io_channel_set_buffered(io, FALSE);
1965 g_io_channel_set_encoding(io, NULL, NULL);*/
1967 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
1968 (slconn && (slconn->hs_features &
1969 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
1970 wbs_opts.wbs_enable == TRUE) {
1971 bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
1972 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
1974 DBG("set Bluetooth voice: %d", bt_vo.setting);
1975 err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
1976 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
1978 ERR("ERROR: sco socket set socket option failed");
1979 ERR("Close SCO skt");
1980 g_io_channel_unref(io);
1982 return BT_HFP_AGENT_ERROR_INTERNAL;
1985 DBG("Set NB codec parameter");
1986 __bt_ag_set_codec(hs, "SetNbParameters");
1989 memset(&sco_addr, 0, sizeof(sco_addr));
1990 sco_addr.sco_family = AF_BLUETOOTH;
1991 __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
1992 DBG("remotel BD address: %s", hs->remote_addr);
1994 err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1995 if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
1996 ERR("ERROR: sco socket connect failed : %d", err);
1997 ERR("Close SCO skt");
1998 g_io_channel_unref(io);
2000 return BT_HFP_AGENT_ERROR_INTERNAL;
2003 /* Disabling the watch since SCO is connected */
2004 /*watch_id = __bt_ag_set_watch(io,
2005 (GIOFunc) __bt_ag_sco_connect_cb, hs);
2007 DBG("SCO watch set Success");*/
2011 _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
2012 return BT_HFP_AGENT_ERROR_NONE;
2015 static void __bt_ag_close_sco(bt_ag_info_t *hs)
2019 int sock = g_io_channel_unix_get_fd(hs->sco);
2020 shutdown(sock, SHUT_RDWR);
2021 g_io_channel_unref(hs->sco);
2026 __bt_ag_agent_remove_watch(&hs->sco_id);
2028 if (hs->sco_incoming_id)
2029 __bt_ag_agent_remove_watch(&hs->sco_incoming_id);
2032 static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
2033 GIOCondition cond, gpointer user_data)
2035 bt_ag_info_t *ag_info = user_data;
2038 if (cond & G_IO_NVAL)
2041 if (cond & (G_IO_HUP | G_IO_ERR)) {
2042 ag_info->sco = NULL;
2043 if (ag_info->sco_id)
2044 __bt_ag_agent_remove_watch(&ag_info->sco_id);
2046 if (ag_info->sco_incoming_id)
2047 __bt_ag_agent_remove_watch(&ag_info->sco_incoming_id);
2049 if (ag_info->watch_id)
2050 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
2056 static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
2057 GIOCondition cond, gpointer user_data)
2059 bt_ag_info_t *ag_info = user_data;
2063 bt_ag_slconn_t *slconn = ag_info->slc;
2067 if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
2068 __bt_ag_check_nval(chan)) {
2069 ERR("cond or chan is not valid");
2073 INFO_C("Incoming SCO....");
2075 if (ag_info->state < HEADSET_STATE_CONNECTED)
2076 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
2078 sco_skt = g_io_channel_unix_get_fd(chan);
2080 cli_sco_sock = accept(sco_skt, NULL, NULL);
2081 if (cli_sco_sock < 0) {
2082 ERR("accept is failed");
2086 sco_io = g_io_channel_unix_new(cli_sco_sock);
2087 g_io_channel_set_close_on_unref(sco_io, TRUE);
2088 g_io_channel_set_encoding(sco_io, NULL, NULL);
2089 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2090 g_io_channel_set_buffered(sco_io, FALSE);
2092 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2093 (slconn && (slconn->hs_features &
2094 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
2095 wbs_opts.wbs_enable == TRUE) {
2096 bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
2097 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
2099 DBG("set Bluetooth voice: %d", bt_vo.setting);
2100 err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
2101 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
2103 ERR("Sco socket set socket option failed");
2104 close(cli_sco_sock);
2109 ag_info->sco = sco_io;
2110 ag_info->sco_incoming_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2111 __bt_ag_sco_server_conn_cb, ag_info);
2113 if (remote_dev_path)
2114 g_free(remote_dev_path);
2116 remote_dev_path = g_strdup(ag_info->path);
2118 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
2122 /* LCOV_EXCL_STOP */
2124 static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
2126 DBG("Start SCO server");
2127 struct sco_socket_addr addr;
2130 bdaddr_t bd_addr = {{0},};
2132 if (hs->sco_server_started) {
2133 DBG("Already exsist");
2134 return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
2138 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
2140 ERR("Can't create socket:\n");
2141 return BT_HFP_AGENT_ERROR_INTERNAL;
2144 /* Bind to local address */
2145 memset(&addr, 0, sizeof(addr));
2146 addr.sco_family = AF_BLUETOOTH;
2148 _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
2149 DBG("Bind to address %s", hs->remote_addr);
2150 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2152 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2153 ERR("Can't bind socket:\n");
2157 if (listen(sco_skt, 1)) {
2158 ERR("Can not listen on the socket:\n");
2162 sco_io = g_io_channel_unix_new(sco_skt);
2163 g_io_channel_set_close_on_unref(sco_io, TRUE);
2164 g_io_channel_set_encoding(sco_io, NULL, NULL);
2165 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2166 g_io_channel_set_buffered(sco_io, FALSE);
2168 hs->sco_server = sco_io;
2169 hs->sco_watch_id = g_io_add_watch(sco_io,
2170 G_IO_IN | G_IO_HUP | G_IO_ERR |
2171 G_IO_NVAL, __bt_ag_sco_server_cb, hs);
2173 hs->sco_server_started = TRUE;
2174 return BT_HFP_AGENT_ERROR_NONE;
2178 return BT_HFP_AGENT_ERROR_INTERNAL;
2181 /* LCOV_EXCL_START */
2182 void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
2184 DBG("Stop SCO server");
2185 if (hs->sco_server) {
2186 g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
2187 g_io_channel_unref(hs->sco_server);
2188 hs->sco_server = NULL;
2190 hs->sco_server_started = FALSE;
2193 static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
2195 GIOChannel *rfcomm = hs->rfcomm;
2198 g_io_channel_shutdown(rfcomm, TRUE, NULL);
2199 g_io_channel_unref(rfcomm);
2209 static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
2212 if (cond & G_IO_NVAL)
2215 if (name_owner_sig_id != -1)
2216 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
2218 name_owner_sig_id = -1;
2222 DBG("Audio connection disconnected");
2223 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2228 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
2230 bt_ag_slconn_t *slconn = hs->slc;
2231 const char *hs_state;
2232 hs_state_t org_state = hs->state;
2233 gboolean val = FALSE;
2235 if (org_state == state)
2238 hs_state = __bt_ag_state2str(state);
2241 case HEADSET_STATE_CONNECTING:
2242 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2244 BT_HEADSET_INTERFACE, "State",
2245 g_variant_new("s", hs_state));
2249 case HEADSET_STATE_CONNECTED:
2250 if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
2251 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2253 BT_HEADSET_INTERFACE, "State",
2254 g_variant_new("s", hs_state));
2256 if (hs->state < state) {
2258 active_devices = g_slist_append(active_devices, hs);
2259 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2261 BT_HEADSET_INTERFACE,
2263 g_variant_new("b", val));
2265 DBG("Device %s connected\n", hs->remote_addr);
2266 #if defined(TIZEN_SUPPORT_DUAL_HF)
2267 if (!hs->is_companion_device)
2268 __bt_ag_start_sco_server(hs);
2270 __bt_ag_start_sco_server(hs);
2273 /* Set default code as Gateway NB */
2274 __bt_ag_set_codec(hs, "SetNbParameters");
2275 } else if (hs->state == HEADSET_STATE_ON_CALL) {
2277 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2279 BT_HEADSET_INTERFACE,
2281 g_variant_new("b", val));
2286 case HEADSET_STATE_DISCONNECTED:
2287 __bt_ag_close_sco(hs);
2288 __bt_ag_headset_close_rfcomm(hs);
2290 if (hs->state == HEADSET_STATE_ON_CALL) {
2292 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2294 BT_HEADSET_INTERFACE,
2296 g_variant_new("b", val));
2300 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2302 BT_HEADSET_INTERFACE,
2304 g_variant_new("b", val));
2305 if (hs->state > HEADSET_STATE_CONNECTING)
2306 _bt_hfp_device_disconnected(hs);
2308 active_devices = g_slist_remove(active_devices, hs);
2310 __bt_ag_codec_negotiation_info_reset(hs, TRUE);
2311 #if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
2312 __bt_ag_set_codec(hs, "SetNbParameters");
2316 /* Since SCO server is binded on remote address */
2317 /* Need to stop SCO server once heasdet disconencted*/
2318 if (hs->sco_server_started)
2319 __bt_ag_stop_sco_server(hs);
2321 g_free(hs->remote_addr);
2325 case HEADSET_STATE_PLAY_IN_PROGRESS:
2326 case HEADSET_STATE_ON_CALL:
2328 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2330 BT_HEADSET_INTERFACE, "State",
2331 g_variant_new("s", hs_state));
2333 /*add watch for sco data */
2334 hs->sco_id = g_io_add_watch(hs->sco,
2335 G_IO_ERR | G_IO_NVAL,
2336 (GIOFunc) __bt_ag_sco_cb, hs);
2338 _bt_ag_agent_emit_property_changed(
2339 ag_dbus_conn, hs->path,
2340 BT_HEADSET_INTERFACE, "Playing",
2341 g_variant_new("b", val));
2343 if (slconn->microphone_gain >= 0)
2344 _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
2345 slconn->microphone_gain);
2347 if (slconn->speaker_gain >= 0)
2348 _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
2349 slconn->speaker_gain);
2359 INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
2360 __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
2362 /* LCOV_EXCL_STOP */
2364 static struct event at_event_callbacks[] = {
2365 { "AT+BRSF", _bt_hfp_supported_features },
2366 { "AT+CIND", _bt_hfp_report_indicators },
2367 { "AT+CMER", _bt_hfp_enable_indicators },
2368 { "AT+CHLD", _bt_hfp_call_hold },
2369 { "ATA", _bt_hfp_answer_call },
2370 { "ATD", _bt_hfp_dial_number },
2371 { "AT+VG", _bt_hfp_signal_gain_setting },
2372 { "AT+CHUP", _bt_hfp_terminate_call },
2373 { "AT+CKPD", _bt_hfp_key_press },
2374 { "AT+CLIP", _bt_hfp_cli_notification },
2375 { "AT+BTRH", _bt_hfp_response_and_hold },
2376 { "AT+BLDN", _bt_hfp_last_dialed_number },
2377 { "AT+VTS", _bt_hfp_dtmf_tone },
2378 { "AT+CNUM", _bt_hfp_subscriber_number },
2379 { "AT+CLCC", _bt_hfp_list_current_calls },
2380 { "AT+CMEE", _bt_hfp_extended_errors },
2381 { "AT+CCWA", _bt_hfp_call_waiting_notify },
2382 { "AT+COPS", _bt_hfp_operator_selection },
2383 { "AT+NREC", _bt_hfp_nr_and_ec },
2384 { "AT+BVRA", _bt_hfp_voice_dial },
2385 { "AT+XAPL", _bt_hfp_apl_command },
2386 { "AT+IPHONEACCEV", _bt_hfp_apl_command },
2387 { "AT+BIA", _bt_hfp_indicators_activation },
2388 { "AT+CPBS", _bt_hfp_select_pb_memory },
2389 { "AT+CPBR", _bt_hfp_read_pb_entries},
2390 { "AT+CPBF", _bt_hfp_find_pb_entires },
2391 { "AT+CSCS", _bt_hfp_select_character_set },
2392 { "AT+CSQ", _bt_hfp_get_signal_quality },
2393 { "AT+CBC", _bt_hfp_get_battery_charge_status },
2394 { "AT+CPAS", _bt_hfp_get_activity_status },
2395 { "AT+CGSN", _bt_hfp_get_equipment_identity },
2396 { "AT+CGMM", _bt_hfp_get_model_information },
2397 { "AT+CGMI", _bt_hfp_get_device_manufacturer },
2398 { "AT+CGMR", _bt_hfp_get_revision_information },
2399 { "AT+BAC", __bt_hfp_available_codecs },
2400 { "AT+BCC", __bt_hfp_codec_connection },
2401 { "AT+BCS", __bt_hfp_codec_selection },
2402 { "AT+XSAT", _bt_hfp_vendor_cmd },
2403 { "AT+CIMI", _bt_hfp_get_imsi },
2404 { "AT+CREG", _bt_hfp_get_creg_status },
2408 int num_of_secure_command = 4;
2409 static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
2411 /* LCOV_EXCL_START */
2412 static void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
2416 char s[MAX_BUFFER_SIZE] = {0, };
2417 gboolean hide = FALSE;
2419 gboolean is_security_command = FALSE;
2422 strncpy(s, buf, MAX_BUFFER_SIZE - 1);
2424 for (i = 0; i < num_of_secure_command; i++) {
2425 if (strstr(buf, secure_command[i])) {
2426 is_security_command = TRUE;
2431 /* +XSAT: 11,DISC */
2432 xsat_ptr = strstr(s, "11,DISC,");
2434 xsat_ptr = xsat_ptr + 8;
2436 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2442 /* AT+XSAT=11,Q_CT,X,XXXX */
2443 xsat_ptr = strstr(s, "11,Q_CT,");
2445 xsat_ptr = xsat_ptr + 8;
2447 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2448 if (x > 1) /* ignore 0 and 1 position */
2455 while (s[i] != '\0') {
2456 if (s[i] == '\r' || s[i] == '\n') {
2460 hide = hide ? FALSE : TRUE;
2461 else if (is_security_command && hide) {
2469 INFO("%s Buffer = [%s], Len(%zd)", message, s, strlen(s));
2474 static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
2478 __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
2480 for (ev = at_event_callbacks; ev->cmd; ev++) {
2481 if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
2482 return ev->callback(hs, buf);
2487 /* LCOV_EXCL_STOP */
2489 static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
2492 ssize_t final_written, count;
2493 char rsp_buffer[MAX_BUFFER_SIZE];
2497 count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
2499 ERR("count is %zd", count);
2503 if (!hdset->io_chan) {
2504 ERR("__bt_ag_send_at_valist: headset not connected");
2510 fd = g_io_channel_unix_get_fd(hdset->io_chan);
2513 while (final_written < count) {
2517 written = write(fd, rsp_buffer + final_written,
2518 count - final_written);
2519 } while (written < 0 && errno == EINTR);
2523 ERR("write failed : %s (%d)", strerror(-err), -err);
2527 final_written += written;
2530 /* Synchronize the sending buffer */
2534 ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
2538 __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
2543 int __attribute__((format(printf, 2, 3)))
2544 _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
2549 va_start(ap, format);
2550 ret = __bt_ag_send_at_valist(hs, ap, format);
2556 void __attribute__((format(printf, 3, 4)))
2557 _bt_ag_send_foreach_headset(GSList *devices,
2558 int (*cmp) (bt_ag_info_t *hs),
2564 for (l = devices; l != NULL; l = l->next) {
2565 bt_ag_info_t *hs = l->data;
2568 if (cmp && cmp(hs) != 0)
2571 va_start(ap, format);
2572 ret = __bt_ag_send_at_valist(hs, ap, format);
2574 ERR("Failed to send to headset: %s (%d)",
2575 strerror(-ret), -ret);
2580 int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
2582 if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
2583 return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
2586 case HFP_STATE_MNGR_ERR_NONE:
2587 return _bt_ag_send_at(hs, "\r\nOK\r\n");
2588 case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
2589 return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
2591 return _bt_ag_send_at(hs, "\r\nERROR\r\n");
2595 /* LCOV_EXCL_START */
2596 static gboolean __bt_ag_event_handler(GIOChannel *channel,
2597 GIOCondition cond, void *user_data)
2599 bt_ag_slconn_t *slconn;
2600 unsigned char event_buf[MAX_BUFFER_SIZE];
2602 size_t available_buffer;
2604 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2608 if (cond & G_IO_NVAL)
2611 slconn = bt_ag_info->slc;
2612 if (cond & (G_IO_ERR | G_IO_HUP)) {
2613 if (bt_ag_info->watch_id)
2614 __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
2616 ERR("ERR or HUP on RFCOMM socket");
2617 INFO_C("Disconnected [AG role] [Terminated by remote dev]");
2621 fd = g_io_channel_unix_get_fd(channel);
2622 len = read(fd, event_buf, sizeof(event_buf) - 1);
2626 available_buffer = sizeof(slconn->buffer) - (slconn->start) -
2627 (slconn->length) - 1;
2628 if (available_buffer < (size_t) len) {
2629 ERR("Buffer over flow");
2633 memcpy(&slconn->buffer[slconn->start + slconn->length], event_buf, len);
2634 slconn->length += len;
2636 slconn->buffer[slconn->start + slconn->length] = '\0';
2638 while (slconn->length > 0) {
2643 get_cr = strchr(&slconn->buffer[slconn->start], '\r');
2645 ERR("Broken AT command received, break");
2649 cmd_len = 1 + (off_t) get_cr -
2650 (off_t) &slconn->buffer[slconn->start];
2654 DBG("Call AT handler");
2655 err = __bt_ag_at_handler(bt_ag_info,
2656 &slconn->buffer[slconn->start]);
2658 ERR("Failed to call AT handler");
2665 err_return = HFP_STATE_MNGR_ERR_NOT_SUPPORTED;
2668 err_return = HFP_STATE_MNGR_ERR_NOT_ALLOWED;
2671 err_return = HFP_STATE_MNGR_ERR_NOT_SUPPORTED;
2674 ERR("Error handling command %s: %s (%d)",
2675 &slconn->buffer[slconn->start],
2676 strerror(-err), -err);
2677 err = _bt_ag_send_response(bt_ag_info,
2683 slconn->start += cmd_len;
2684 slconn->length -= cmd_len;
2686 if (slconn->length <= 0)
2691 ERR("Failed in event handler - SLC Disconnect");
2692 _bt_ag_set_headset_state(bt_ag_info,
2693 HEADSET_STATE_DISCONNECTED);
2697 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
2698 const gchar *object_path)
2702 bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
2703 struct sockaddr_remote address;
2704 socklen_t address_len;
2706 INFO_C("Connected [AG role]");
2707 bt_ag_info->rfcomm = NULL;
2708 bt_ag_info->slc = NULL;
2709 bt_ag_info->hfp_active = TRUE;
2710 bt_ag_info->vr_blacklisted = FALSE;
2711 bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
2712 bt_ag_info->sco_server_started = FALSE;
2713 __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
2715 bt_ag_info->path = device_path;
2716 DBG("device_path = [%s]", device_path);
2718 address_len = sizeof(address);
2719 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2720 ERR("BD_ADDR is NULL");
2722 DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
2723 bt_ag_info->fd = fd;
2724 bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
2725 flags = g_io_channel_get_flags(bt_ag_info->io_chan);
2727 flags &= ~G_IO_FLAG_NONBLOCK;
2728 flags &= G_IO_FLAG_MASK;
2729 g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
2730 g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
2731 g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
2733 bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
2735 bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2736 __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
2737 address.remote_bdaddr.b);
2739 #if defined(TIZEN_SUPPORT_DUAL_HF)
2740 bt_ag_info->is_companion_device =
2741 __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
2744 DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
2746 if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
2747 DBG("HSP connection completed");
2748 _bt_ag_set_headset_state(bt_ag_info,
2749 HEADSET_STATE_CONNECTED);
2751 DBG("HFP connection connecting");
2752 _bt_ag_set_headset_state(bt_ag_info,
2753 HEADSET_STATE_CONNECTING);
2756 __bt_ag_agent_start_watch(bt_ag_info);
2758 bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
2759 bt_ag_info->slc->speaker_gain = 15;
2760 bt_ag_info->slc->microphone_gain = 15;
2761 bt_ag_info->slc->is_nrec = TRUE;
2766 static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
2775 fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
2778 ERR("Unable to open VR blacklist file");
2782 fseek(fp, 0, SEEK_END);
2785 ERR("size is not a positive number");
2792 buffer = g_malloc0(sizeof(char) * size);
2793 if (buffer == NULL) {
2794 ERR("g_malloc0 is failed");
2798 result = fread((char *)buffer, 1, size, fp);
2800 if (result != size) {
2806 token = strtok_r(buffer, "=", &saveptr);
2807 if (token == NULL) {
2812 while ((token = strtok_r(NULL, ",", &saveptr))) {
2813 if (strlen(token) > 8)
2815 if (0 == g_strcmp0(token, lap_addr)) {
2816 INFO("Voice Recognition blacklisted");
2825 static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
2827 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2828 sco_open_timer_id = 0;
2829 DBG("sco_open_request (%d)", sco_open_request);
2831 if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
2832 bt_ag_slconn_t *slconn = bt_ag_info->slc;
2834 INFO("try to open SCO");
2835 sco_open_request = FALSE;
2837 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2838 (slconn && (slconn->hs_features &
2839 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
2840 switch (bt_ag_info->codec_info.final_codec) {
2841 case BT_CVSD_CODEC_ID:
2842 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
2843 __bt_ag_sco_connect(bt_ag_info);
2845 case BT_MSBC_CODEC_ID:
2846 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
2847 __bt_ag_sco_connect(bt_ag_info);
2850 __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
2854 __bt_ag_sco_connect(bt_ag_info);
2859 /* LCOV_EXCL_STOP */
2862 * Service level connection complete
2863 * indication and state management
2865 void _bt_ag_slconn_complete(bt_ag_info_t *hs)
2867 char lap_address[BT_LOWER_ADDRESS_LENGTH];
2869 DBG("HFP Service Level Connection established\n");
2871 /* Check device Voice Recognition blacklist status */
2872 g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
2873 hs->vr_blacklisted =
2874 __bt_ag_agent_is_device_vr_blacklisted(lap_address);
2876 if (sco_open_timer_id > 0) {
2877 g_source_remove(sco_open_timer_id);
2878 sco_open_timer_id = 0;
2881 sco_open_request = FALSE;
2882 sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
2883 __bt_sco_open_delay_timeout_cb, hs);
2885 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2888 /* LCOV_EXCL_START */
2889 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
2892 g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
2893 g_io_channel_unref(hs->io_chan);
2897 __bt_ag_close_sco(hs);
2898 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2900 __bt_ag_agent_remove_watch(&hs->watch_id);
2902 _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
2906 static GQuark __bt_ag_agent_error_quark(void)
2910 static GQuark quark = 0;
2912 quark = g_quark_from_static_string("ag-agent");
2918 static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
2921 ERR("error[%d]\n", error);
2924 case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
2925 return g_error_new(BT_AG_AGENT_ERROR, error,
2926 BT_ERROR_NOT_AVAILABLE);
2927 case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
2928 return g_error_new(BT_AG_AGENT_ERROR, error,
2929 BT_ERROR_NOT_CONNECTED);
2930 case BT_HFP_AGENT_ERROR_BUSY:
2931 return g_error_new(BT_AG_AGENT_ERROR, error,
2933 case BT_HFP_AGENT_ERROR_INVALID_PARAM:
2934 return g_error_new(BT_AG_AGENT_ERROR, error,
2935 BT_ERROR_INVALID_PARAM);
2936 case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
2937 return g_error_new(BT_AG_AGENT_ERROR, error,
2938 BT_ERROR_ALREADY_EXSIST);
2939 case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
2940 return g_error_new(BT_AG_AGENT_ERROR, error,
2941 BT_ERROR_ALREADY_CONNECTED);
2942 case BT_HFP_AGENT_ERROR_NO_MEMORY:
2943 return g_error_new(BT_AG_AGENT_ERROR, error,
2944 BT_ERROR_NO_MEMORY);
2945 case BT_HFP_AGENT_ERROR_I_O_ERROR:
2946 return g_error_new(BT_AG_AGENT_ERROR, error,
2947 BT_ERROR_I_O_ERROR);
2948 case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
2949 return g_error_new(BT_AG_AGENT_ERROR, error,
2950 BT_ERROR_OPERATION_NOT_AVAILABLE);
2951 case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
2952 return g_error_new(BT_AG_AGENT_ERROR, error,
2954 case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
2955 return g_error_new(BT_AG_AGENT_ERROR, error,
2957 case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
2958 return g_error_new(BT_AG_AGENT_ERROR, error,
2959 BT_ERROR_NO_CALL_LOG);
2960 case BT_HFP_AGENT_ERROR_INTERNAL:
2962 return g_error_new(BT_AG_AGENT_ERROR, error,
2968 static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
2972 for (l = active_devices ; l; l = l->next) {
2973 bt_ag_info_t *data = l->data;
2974 if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
2976 if (g_strcmp0(data->path, device_path) == 0) {
2977 INFO("Active device found");
2982 INFO("Active device not found");
2986 static void __bt_ag_agent_method(GDBusConnection *connection,
2987 const gchar *sender,
2988 const gchar *object_path,
2989 const gchar *interface_name,
2990 const gchar *method_name,
2991 GVariant *parameters,
2992 GDBusMethodInvocation *invocation,
2997 INFO("method %s", method_name);
2998 INFO("object_path %s", object_path);
2999 int ret = BT_HFP_AGENT_ERROR_NONE;
3001 const gchar *device_path = NULL;
3003 if (g_strcmp0(method_name, "NewConnection") == 0) {
3007 GUnixFDList *fd_list;
3008 GVariant *options = NULL;
3009 int device_count = 0;
3011 device_count = g_slist_length(active_devices);
3013 INFO("device_count %d", device_count);
3015 if (device_count >= MAX_CONNECTED_DEVICES) {
3016 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3020 g_variant_get(parameters, "(oha{sv})",
3021 &device_path, &index, &options);
3023 #if defined(TIZEN_SUPPORT_DUAL_HF) && defined(TIZEN_PROFILE_WEARABLE)
3025 * Below code is not required for dual HF support for
3029 __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
3030 INFO("not allow to connect 2nd HF connection");
3031 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3035 msg = g_dbus_method_invocation_get_message(invocation);
3036 fd_list = g_dbus_message_get_unix_fd_list(msg);
3037 if (fd_list == NULL) {
3038 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3042 fd = g_unix_fd_list_get(fd_list, index, NULL);
3044 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3048 DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
3050 if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
3051 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3055 g_dbus_method_invocation_return_value(invocation, NULL);
3056 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
3059 g_variant_get(parameters, "(o)", &device_path);
3060 INFO("device_path %s", device_path);
3062 for (l = active_devices; l; l = l->next) {
3063 bt_ag_info_t *data = l->data;
3065 INFO("data->path %s", data->path);
3066 if (g_strcmp0(data->path, device_path) == 0) {
3067 if (!__bt_ag_agent_connection_release(data)) {
3068 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3071 INFO_C("Disconnected [AG role] [Terminated by local host]");
3072 g_dbus_method_invocation_return_value(invocation, NULL);
3075 } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
3077 gchar *address = NULL;
3078 g_variant_get(parameters, "(&s&s)", &path, &address);
3079 /*local_addr = malloc(strlen(address));
3080 memcpy(local_addr, address, strlen(address));*/
3082 DBG("Sender = %s, Application path = %s\n", sender, path);
3083 ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
3088 local_addr = g_strdup(address);
3089 DBG("Address = %s\n", local_addr);
3090 g_dbus_method_invocation_return_value(invocation, NULL);
3091 } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
3093 g_variant_get(parameters, "(&s)", &path);
3095 DBG("Application path = %s\n", path);
3096 DBG("Sender = %s\n", sender);
3098 ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
3102 g_dbus_method_invocation_return_value(invocation, NULL);
3103 } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
3105 gchar *number = NULL;
3108 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3110 DBG("Application path = %s", path);
3111 DBG_SECURE("Phone number = %s", number);
3112 DBG("Call id = %d", call_id);
3114 DBG("Sender = %s", sender);
3116 ret = _bt_hfp_incoming_call(path, number, call_id, sender);
3119 g_dbus_method_invocation_return_value(invocation, NULL);
3120 } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
3122 gchar *number = NULL;
3125 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3127 DBG("Application path = %s", path);
3128 DBG_SECURE("Phone number = %s", number);
3129 DBG("Call id = %d", call_id);
3131 DBG("Sender = %s", sender);
3133 ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
3136 g_dbus_method_invocation_return_value(invocation, NULL);
3137 } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
3139 gchar *number = NULL;
3144 g_variant_get(parameters, "(&s&sii)",
3145 &path, &number, &status, &call_id);
3146 DBG("Application path = %s\n", path);
3147 DBG_SECURE("Number = %s\n", number);
3148 DBG("Status = %d\n", status);
3149 DBG("Call id = %d\n", call_id);
3150 DBG("Sender = %s\n", sender);
3152 ret = _bt_hfp_change_call_status(path,
3153 number, status, call_id, sender);
3155 if (_bt_hfp_is_call_exist() == FALSE) {
3156 for (l = active_devices; l; l = l->next) {
3157 bt_ag_info_t *data = l->data;
3159 if (data->state == HEADSET_STATE_ON_CALL) {
3160 __bt_ag_close_sco(data);
3161 _bt_ag_set_headset_state(data,
3162 HEADSET_STATE_CONNECTED);
3169 g_dbus_method_invocation_return_value(invocation, NULL);
3170 } else if (g_strcmp0(method_name, "GetProperties") == 0) {
3171 GVariantBuilder *builder;
3173 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3176 gchar *codec = g_strdup("codec");
3177 gchar *nrec = g_strdup("nrec");
3179 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3181 g_variant_builder_add(builder, "{sv}",
3182 codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
3183 g_variant_builder_add(builder, "{sv}",
3184 nrec, g_variant_new("b", bt_ag_info->nrec_status));
3186 var_data = g_variant_new("(a{sv})", builder);
3187 g_variant_builder_unref(builder);
3188 g_dbus_method_invocation_return_value(invocation, var_data);
3193 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3196 } else if (g_strcmp0(method_name, "Disconnect") == 0) {
3197 char hdset_address[18] = { 0, };
3200 for (l = active_devices; l; l = l->next) {
3201 bt_ag_info_t *data = l->data;
3203 __bt_convert_addr_type_to_rev_string(hdset_address,
3204 (unsigned char *)data->remote_addr);
3206 DBG("Disconnect Headset %s, %s\n",
3207 hdset_address, data->path);
3208 _bt_ag_set_headset_state(data,
3209 HEADSET_STATE_DISCONNECTED);
3211 g_dbus_method_invocation_return_value(invocation, NULL);
3212 } else if (g_strcmp0(method_name, "IsConnected") == 0) {
3213 gboolean is_connected = FALSE;
3216 for (l = active_devices; l; l = l->next) {
3217 bt_ag_info_t *data = l->data;
3219 if (data->state == HEADSET_STATE_CONNECTED)
3220 is_connected = TRUE;
3222 DBG("is_connected : %s",
3223 is_connected ? "Connected" : "Disconnected");
3225 g_dbus_method_invocation_return_value(invocation,
3226 g_variant_new("(b)", is_connected));
3227 } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
3230 if (0 == g_slist_length(active_devices)) {
3231 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3235 if (ag.ring_timer) {
3236 DBG("IndicateCall received when already indicating");
3237 g_dbus_method_invocation_return_value(invocation, NULL);
3240 for (l = active_devices; l; l = l->next) {
3241 bt_ag_info_t *data = l->data;
3243 if (data->state >= HEADSET_STATE_CONNECTED)
3244 _bt_ag_send_at(data, "\r\nRING\r\n");
3247 __bt_ring_timer_cb(NULL);
3248 ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
3249 __bt_ring_timer_cb, NULL);
3250 g_dbus_method_invocation_return_value(invocation, NULL);
3251 } else if (g_strcmp0(method_name, "CancelCall") == 0) {
3252 if (0 == g_slist_length(active_devices)) {
3253 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3257 if (ag.ring_timer) {
3258 g_source_remove(ag.ring_timer);
3261 DBG("Got CancelCall method call but no call is active");
3263 g_dbus_method_invocation_return_value(invocation, NULL);
3264 } else if (g_strcmp0(method_name, "Play") == 0) {
3265 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3266 bt_ag_slconn_t *slconn = NULL;
3269 slconn = bt_ag_info->slc;
3271 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3275 #ifndef __TIZEN_OPEN__
3278 if (slconn && FALSE == slconn->is_voice_recognition_running &&
3279 mdm_get_service() == MDM_RESULT_SUCCESS) {
3280 mode = mdm_get_allow_bluetooth_outgoing_call();
3281 mdm_release_service();
3283 if (mode == MDM_RESTRICTED) {
3284 ERR("[MDM] Not allow the outgoing call");
3285 ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
3292 switch (bt_ag_info->state) {
3293 case HEADSET_STATE_CONNECTING:
3294 case HEADSET_STATE_DISCONNECTED:
3295 ERR("HEADSET_STATE ERROR");
3296 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3298 case HEADSET_STATE_CONNECTED:
3300 case HEADSET_STATE_PLAY_IN_PROGRESS:
3301 ERR("Play In Progress");
3302 ret = BT_HFP_AGENT_ERROR_BUSY;
3310 if (sco_open_timer_id > 0) {
3311 INFO("SCO open delay");
3312 sco_open_request = TRUE;
3313 g_dbus_method_invocation_return_value(invocation, NULL);
3317 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
3318 (slconn && (slconn->hs_features &
3319 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
3320 switch (bt_ag_info->codec_info.final_codec) {
3321 case BT_CVSD_CODEC_ID:
3322 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
3323 ret = __bt_ag_sco_connect(bt_ag_info);
3325 case BT_MSBC_CODEC_ID:
3326 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
3327 ret = __bt_ag_sco_connect(bt_ag_info);
3330 ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
3334 ret = __bt_ag_sco_connect(bt_ag_info);
3340 sco_owner = g_strdup(sender);
3342 g_dbus_method_invocation_return_value(invocation, NULL);
3344 name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
3345 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
3346 __bt_ag_name_owner_changed_cb, NULL, NULL);
3347 } else if (g_strcmp0(method_name, "Stop") == 0) {
3350 for (l = active_devices; l; l = l->next) {
3351 bt_ag_info_t *data = l->data;
3353 if (data->state > HEADSET_STATE_CONNECTED) {
3354 __bt_ag_close_sco(data);
3355 _bt_ag_set_headset_state(data,
3356 HEADSET_STATE_CONNECTED);
3360 g_dbus_method_invocation_return_value(invocation, NULL);
3361 } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
3362 gboolean is_playing = FALSE;
3365 for (l = active_devices; l; l = l->next) {
3366 bt_ag_info_t *data = l->data;
3368 if (data->state == HEADSET_STATE_ON_CALL)
3371 DBG("is_playing : %s", is_playing ? "Playing" : "Not Playing");
3373 g_dbus_method_invocation_return_value(invocation,
3374 g_variant_new("(b)", is_playing));
3375 } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
3376 bt_ag_slconn_t *slconn = NULL;
3377 guint16 gain_value = 0;
3378 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3380 if (bt_ag_info == NULL) {
3381 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3385 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3386 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3390 slconn = bt_ag_info->slc;
3392 gain_value = (guint16) slconn->speaker_gain;
3394 g_dbus_method_invocation_return_value(invocation,
3395 g_variant_new("(q)", gain_value));
3396 } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
3398 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3400 g_variant_get(parameters, "(q)", &gain);
3401 DBG("Speaker gain = %d\n", gain);
3403 if (bt_ag_info == NULL) {
3404 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3408 ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
3411 g_dbus_method_invocation_return_value(invocation, NULL);
3412 } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
3413 bt_ag_slconn_t *slconn = NULL;
3414 guint16 gain_value = 0;
3415 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3417 if (bt_ag_info == NULL) {
3418 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3422 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3423 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3427 slconn = bt_ag_info->slc;
3429 gain_value = (guint16) slconn->microphone_gain;
3431 g_dbus_method_invocation_return_value(invocation,
3432 g_variant_new("(q)", gain_value));
3433 } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
3435 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3437 g_variant_get(parameters, "(q)", &gain);
3438 DBG("Microphone gain = %d\n", gain);
3440 if (bt_ag_info == NULL) {
3441 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3445 ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
3448 g_dbus_method_invocation_return_value(invocation, NULL);
3449 } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
3450 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3451 if (bt_ag_info == NULL) {
3452 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3456 bt_ag_slconn_t *slconn = bt_ag_info->slc;
3459 g_variant_get(parameters, "(b)", &enable);
3460 DBG("VoiceDail enable = %d\n", enable);
3462 if ((slconn && !(slconn->hs_features &
3463 BT_HF_FEATURE_VOICE_RECOGNITION)))
3464 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3465 else if (bt_ag_info->vr_blacklisted)
3466 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3468 ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
3471 slconn->is_voice_recognition_running = enable;
3475 g_dbus_method_invocation_return_value(invocation, NULL);
3476 } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
3478 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3479 if (bt_ag_info == NULL) {
3480 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3484 g_variant_get(parameters, "(&s)", &cmd);
3486 ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
3490 DBG("vendor cmd = %s", cmd);
3492 ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
3495 g_dbus_method_invocation_return_value(invocation, NULL);
3496 } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
3497 DBG("Already pass dbus SMACK for bt-service::platform");
3498 /* Return success */
3499 g_dbus_method_invocation_return_value(invocation, NULL);
3500 } else if (g_strcmp0(method_name, "SwapHeadset") == 0) {
3503 char address[BT_ADDRESS_STRING_SIZE];
3504 char remote_addr[BT_ADDRESS_STRING_SIZE];
3505 gboolean device_found = FALSE;
3507 g_variant_get(parameters, "(s)", &addr);
3508 g_strlcpy(address, addr, sizeof(address));
3509 DBG("Sender = %s", sender);
3511 /* Loop through connected headset list
3512 * If found, update the remote_dev_path.
3514 for (l = active_devices ; l; l = l->next) {
3515 bt_ag_info_t *data = l->data;
3516 g_strlcpy(remote_addr, data->remote_addr, sizeof(remote_addr));
3517 if (g_strcmp0(remote_addr, address) == 0) {
3518 DBG("Active device found");
3519 if (data->path == NULL) {
3520 DBG("device path is null");
3521 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3524 remote_dev_path = g_strdup(data->path);
3525 DBG("Setting device path %s as active device path", remote_dev_path);
3526 device_found = TRUE;
3531 if (!device_found) {
3532 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3536 g_dbus_method_invocation_return_value(invocation, NULL);
3543 err = __bt_ag_agent_set_error(ret);
3544 g_dbus_method_invocation_return_gerror(invocation, err);
3549 static const GDBusInterfaceVTable method_table = {
3550 __bt_ag_agent_method,
3555 static GDBusNodeInfo *__bt_ag_create_method_node_info
3556 (const gchar *introspection_data)
3559 GDBusNodeInfo *node_info = NULL;
3561 if (introspection_data == NULL)
3564 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
3567 ERR("Unable to create node: %s", err->message);
3568 g_clear_error(&err);
3573 static GDBusConnection *__bt_ag_get_gdbus_connection(void)
3579 if (ag_dbus_conn == NULL)
3580 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
3582 if (!ag_dbus_conn) {
3584 ERR("Unable to connect to dbus: %s", err->message);
3585 g_clear_error(&err);
3591 return ag_dbus_conn;
3594 static gboolean __bt_ag_register_profile_methods(void)
3597 GError *error = NULL;
3599 GDBusNodeInfo *node_info = NULL;
3602 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
3604 G_BUS_NAME_OWNER_FLAGS_NONE,
3608 DBG("owner_id is [%d]", owner_id);
3610 node_info = __bt_ag_create_method_node_info(
3611 ag_agent_bluez_introspection_xml);
3612 if (node_info == NULL)
3615 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3616 DBG("path is [%s]", path);
3618 hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3619 node_info->interfaces[0],
3621 NULL, NULL, &error);
3622 if (hf_bluez_id == 0) {
3623 ERR("Failed to register: %s", error->message);
3624 g_error_free(error);
3626 g_dbus_node_info_unref(node_info);
3631 /* Ag register profile methods for HSP*/
3633 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
3634 DBG("path is [%s]", path);
3636 hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3637 node_info->interfaces[0],
3639 NULL, NULL, &error);
3640 if (hs_bluez_id == 0) {
3641 ERR("Failed to register: %s", error->message);
3642 g_error_free(error);
3644 g_dbus_node_info_unref(node_info);
3648 g_dbus_node_info_unref(node_info);
3650 node_info = __bt_ag_create_method_node_info
3651 (ag_agent_app_introspection_xml);
3652 if (node_info == NULL)
3655 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3656 DBG("path is [%s]", path);
3658 app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3659 node_info->interfaces[0],
3661 NULL, NULL, &error);
3663 ERR("Failed to register: %s", error->message);
3664 g_error_free(error);
3666 g_dbus_node_info_unref(node_info);
3670 g_dbus_node_info_unref(node_info);
3676 static void __bt_ag_unregister_profile_methods(void)
3680 if (hf_bluez_id > 0) {
3681 g_dbus_connection_unregister_object(ag_dbus_conn,
3686 if (hs_bluez_id > 0) {
3687 g_dbus_connection_unregister_object(ag_dbus_conn,
3693 g_dbus_connection_unregister_object(ag_dbus_conn,
3699 static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
3700 const gchar *path, const gchar *interface)
3702 return (service_gproxy) ? service_gproxy :
3703 __bt_ag_gdbus_init_service_proxy(service,
3707 static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
3708 char *profile_uuid, const char* profile_name)
3713 GError *error = NULL;
3714 GVariantBuilder *builder;
3716 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3717 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3722 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3724 g_variant_builder_add(builder, "{sv}",
3725 "Name", g_variant_new("s",
3727 g_variant_builder_add(builder, "{sv}",
3728 "Version", g_variant_new("q", profile_version));
3729 /*g_variant_builder_add(builder, "{sv}",
3730 "Role", g_variant_new("s","client"));*/
3731 if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
3732 g_variant_builder_add(builder, "{sv}",
3733 "features", g_variant_new("q", ag.sdp_features));
3736 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3737 g_variant_new("(osa{sv})", path,
3738 profile_uuid, builder),
3739 G_DBUS_CALL_FLAGS_NONE, -1,
3741 g_variant_builder_unref(builder);
3742 /* set the name and role for the profile*/
3744 /* dBUS-RPC is failed */
3745 ERR("dBUS-RPC is failed");
3747 if (error != NULL) {
3748 /* dBUS gives error cause */
3749 ERR("D-Bus API failure: errCode[%x], message[%s]",
3750 error->code, error->message);
3752 g_clear_error(&error);
3757 g_variant_unref(ret);
3764 static void __bt_ag_agent_unregister(gchar *path)
3769 GError *error = NULL;
3771 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3772 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3777 ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
3778 g_variant_new("(o)", path),
3779 G_DBUS_CALL_FLAGS_NONE, -1,
3782 /* set the name and role for the profile*/
3784 /* dBUS-RPC is failed */
3785 ERR("dBUS-RPC is failed");
3787 if (error != NULL) {
3788 /* dBUS gives error cause */
3789 ERR("D-Bus API failure: errCode[%x], message[%s]",
3790 error->code, error->message);
3792 g_clear_error(&error);
3796 g_variant_unref(ret);
3806 static void __bt_ag_agent_battery_status_cb(keynode_t *node)
3808 int batt = vconf_keynode_get_int(node);
3810 _bt_hfp_set_property_value("BatteryBarsChanged", batt);
3813 static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
3815 int signal_bar = vconf_keynode_get_int(node);
3817 BT_CHECK_SIGNAL_STRENGTH(signal_bar);
3818 _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
3821 static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
3823 gboolean status = vconf_keynode_get_bool(node);
3825 DBG("status = %d", status);
3827 if (status == TRUE) {
3828 for (l = active_devices; l; l = l->next) {
3829 bt_ag_info_t *data = l->data;
3830 _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
3835 static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
3837 int service = vconf_keynode_get_int(node);
3838 bt_hfp_agent_network_registration_status_t network_service;
3842 DBG("Current Signal Level = [%d] \n", service);
3845 case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
3846 case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
3847 case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
3855 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
3857 ERR("Get roaming status failed err = %d\n", ret);
3861 if (roam_status == 0 && service == 1)
3862 network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
3863 else if (roam_status == 1 && service == 1)
3864 network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
3866 network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
3868 _bt_hfp_set_property_value("RegistrationChanged", network_service);
3871 static void __bt_ag_agent_subscribe_vconf_updates(void)
3877 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3878 (void *)__bt_ag_agent_battery_status_cb, NULL);
3880 ERR("Subsrciption to battery status failed err = [%d]\n", ret);
3882 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
3883 (void *)__bt_ag_agent_network_signal_status_cb, NULL);
3885 ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
3887 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3888 (void *)__bt_ag_agent_network_register_status_cb, NULL);
3890 ERR("Subsrciption to network failed err = [%d]\n", ret);
3892 if (TIZEN_PROFILE_WEARABLE) {
3893 ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
3894 (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
3896 ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
3900 static void __bt_ag_agent_release_vconf_updates(void)
3906 ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3907 (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
3909 ERR("vconf_ignore_key_changed failed\n");
3911 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
3912 (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
3914 ERR("vconf_ignore_key_changed failed\n");
3916 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3917 (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
3919 ERR("vconf_ignore_key_changed failed\n");
3922 static gboolean __bt_ag_agent_send_subscriber_number_changed(
3925 const char *property = g_strdup("SubscriberNumberChanged");
3929 DBG("Number is %s", number);
3931 if (!_bt_hfp_set_property_name(property, number)) {
3932 DBG("Error- set property for subscriber no change - ERROR\n");
3933 g_free((void *)property);
3936 g_free((void *)property);
3940 static void __bt_ag_agent_sigterm_handler(int signo)
3945 ERR_C("***** Signal handler came with signal %d *****", signo);
3947 for (l = active_devices ; l; l = l->next) {
3948 bt_ag_info_t *data = l->data;
3949 if (!__bt_ag_agent_connection_release(data))
3950 ERR("__bt_ag_agent_connection_release failed");
3953 g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
3956 g_main_loop_quit(gmain_loop);
3960 INFO("Terminating AG agent");
3964 if (signo == SIGTERM)
3967 for (i = 0; i < BT_AG_SIG_NUM; i++)
3968 sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
3973 static void __bt_ag_agent_tel_cb(TapiHandle *handle,
3978 TelSimMsisdnList_t *number;
3979 gchar *subscriber_number;
3981 ERR("*********** result = %d", result);
3983 if (result == TAPI_API_SIM_LOCKED ||
3984 result == TAPI_API_SIM_NOT_INITIALIZED ||
3985 result == TAPI_API_SERVICE_NOT_READY) {
3986 DBG("initializing the tapi event for SIM status");
3987 __bt_ag_agent_reg_sim_event(handle, user_data);
3994 number = (TelSimMsisdnList_t *)data;
3995 subscriber_number = g_strdup(number->list[0].num);
3996 __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
3997 g_free(subscriber_number);
4000 static void __bt_ag_agent_on_noti_sim_status(TapiHandle *handle,
4001 const char *noti_id, void *data, void *user_data)
4003 TelSimCardStatus_t *status = data;
4006 DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
4008 if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
4009 __bt_ag_agent_dereg_sim_event(handle);
4010 tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
4012 if (tapi_result != TAPI_API_SUCCESS)
4013 ERR("Fail to get sim info: %d", tapi_result);
4017 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data)
4020 ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
4021 __bt_ag_agent_on_noti_sim_status, user_data);
4023 if (ret != TAPI_API_SUCCESS)
4024 ERR("event register failed(%d)", ret);
4027 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle)
4030 ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
4032 if (ret != TAPI_API_SUCCESS)
4033 ERR("event deregister failed(%d)", ret);
4036 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
4037 const gchar *sender_name,
4038 const gchar *object_path,
4039 const gchar *interface_name,
4040 const gchar *signal_name,
4041 GVariant *parameters,
4045 char *name_owner = NULL;
4046 char *old_owner = NULL;
4047 char *new_owner = NULL;
4049 if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
4052 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
4054 _bt_hfp_release_all_calls_by_sender(name_owner);
4056 if (sco_owner == NULL)
4059 if (strcasecmp(name_owner, sco_owner) == 0) {
4060 if (name_owner_sig_id != -1)
4061 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4063 name_owner_sig_id = -1;
4067 for (l = active_devices ; l; l = l->next) {
4068 bt_ag_info_t *data = l->data;
4071 __bt_ag_close_sco(data);
4072 _bt_ag_set_headset_state(data,
4073 HEADSET_STATE_CONNECTED);
4080 static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
4081 const gchar *sender_name,
4082 const gchar *object_path,
4083 const gchar *interface_name,
4084 const gchar *signal_name,
4085 GVariant *parameters,
4090 GVariant *optional_param = NULL;
4092 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
4093 g_variant_get(parameters, "(&o@a{sa{sv}})", &path, &optional_param);
4096 g_variant_unref(optional_param);
4097 ERR("Invalid adapter path");
4101 INFO("Adapter Path = [%s]", path);
4102 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4103 gchar *obj_path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4104 __bt_ag_agent_register(obj_path, hfp_ver,
4105 HFP_AG_UUID, "Hands-Free Audio Gateway");
4107 obj_path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4108 __bt_ag_agent_register(obj_path, hsp_ver,
4109 HSP_AG_UUID, "Headset Audio Gateway");
4111 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
4112 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
4115 g_variant_unref(optional_param);
4116 ERR("Invalid adapter path");
4120 INFO("Adapter Path = [%s]", path);
4121 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4122 gchar *obj_path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4123 __bt_ag_agent_unregister(obj_path);
4125 obj_path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4126 __bt_ag_agent_unregister(obj_path);
4131 g_variant_unref(optional_param);
4136 static void __bt_ag_agent_dbus_deinit(void)
4139 if (service_gproxy) {
4140 g_object_unref(service_gproxy);
4141 service_gproxy = NULL;
4145 g_object_unref(app_gproxy);
4150 __bt_ag_unregister_profile_methods();
4152 if (interface_added_sig_id)
4153 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4154 interface_added_sig_id);
4156 if (interface_removed_sig_id)
4157 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4158 interface_removed_sig_id);
4160 if (name_owner_sig_id)
4161 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4163 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4165 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4169 if (media_state_sig_id)
4170 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4171 media_state_sig_id);
4172 media_state_sig_id = 0;
4175 interface_added_sig_id = 0;
4176 interface_removed_sig_id = 0;
4177 name_owner_sig_id = 0;
4181 g_object_unref(ag_dbus_conn);
4182 ag_dbus_conn = NULL;
4187 static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
4190 GDBusProxy *manager_proxy = NULL;
4191 GVariant *result = NULL;
4192 char *adapter_path = NULL;
4195 return BT_HFP_AGENT_ERROR_INTERNAL;
4197 manager_proxy = g_dbus_proxy_new_sync(conn,
4198 G_DBUS_PROXY_FLAGS_NONE, NULL,
4201 BT_MANAGER_INTERFACE,
4204 if (!manager_proxy) {
4205 ERR("Unable to create proxy: %s", err->message);
4209 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
4210 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
4213 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
4215 ERR("Fail to get DefaultAdapter");
4220 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
4221 ERR("Incorrect result\n");
4225 g_variant_get(result, "(&o)", &adapter_path);
4227 if (adapter_path == NULL ||
4228 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
4229 ERR("Adapter path is inproper\n");
4234 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
4236 g_variant_unref(result);
4237 g_object_unref(manager_proxy);
4242 g_clear_error(&err);
4245 g_variant_unref(result);
4248 g_object_unref(manager_proxy);
4250 return BT_HFP_AGENT_ERROR_INTERNAL;
4253 /* LCOV_EXCL_STOP */
4255 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4256 void _bt_ag_agent_check_transport_state(void)
4260 if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
4264 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
4265 G_DBUS_PROXY_FLAGS_NONE, NULL,
4266 "org.pulseaudio.Server", A2DP_SOURCE_ENDPOINT,
4267 BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
4271 ERR("Unable to create proxy: %s", err->message);
4272 g_clear_error(&err);
4276 INFO_C("SuspendMedia initiated");
4278 g_dbus_proxy_call(proxy,
4279 "SuspendMedia", NULL,
4280 G_DBUS_CALL_FLAGS_NONE, 2000,
4282 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4288 static void __bt_ag_agent_transport_state_update(const char *value)
4291 if (!g_strcmp0(value, "idle"))
4292 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4293 else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
4294 transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
4296 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4298 INFO_C("transport_state %d", transport_state);
4301 static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
4302 const gchar *sender_name,
4303 const gchar *object_path,
4304 const gchar *interface_name,
4305 const gchar *signal_name,
4306 GVariant *parameters,
4311 GVariant *dict_param = NULL;
4312 GVariant *optional_param = NULL;
4314 if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
4315 if (g_strcmp0(g_variant_get_type_string(parameters),
4317 ERR("Incorrect parameters\n");
4321 g_variant_get(parameters, "(&s@a{sv}@as)",
4322 &inter, &dict_param, &optional_param);
4323 if (dict_param && (!g_strcmp0(inter,
4324 BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
4325 GVariantIter *iter = NULL;
4326 const gchar *key = NULL;
4327 GVariant *value_var = NULL;
4328 gchar *value = NULL;
4329 g_variant_get(dict_param, "a{sv}", &iter);
4330 while (g_variant_iter_loop(
4331 iter, "{sv}", &key, &value_var)) {
4333 if (g_strcmp0(key, "State") == 0) {
4334 value = (gchar *)g_variant_get_string(
4337 DBG("value %s", value);
4338 __bt_ag_agent_transport_state_update(value);
4342 g_variant_iter_free(iter);
4344 } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
4345 char *profile_uuid = NULL;
4348 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
4349 if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
4350 (state == BT_PROFILE_STATE_DISCONNECTED)) {
4351 DBG("Updating the transport state");
4352 __bt_ag_agent_transport_state_update("Disconnect");
4357 g_variant_unref(dict_param);
4360 g_variant_unref(optional_param);
4366 /* LCOV_EXCL_START */
4367 static void __bt_ag_agent_dbus_init(void)
4371 if (__bt_ag_get_gdbus_connection() == NULL) {
4372 ERR("Error in creating the gdbus connection\n");
4375 if (!__bt_ag_register_profile_methods()) {
4376 ERR("Error in HFP / HSP register_profile_methods\n");
4380 if (!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
4382 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4383 __bt_ag_agent_register(path, hfp_ver,
4384 HFP_AG_UUID, "Hands-Free Audio Gateway");
4386 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4387 __bt_ag_agent_register(path, hsp_ver,
4388 HSP_AG_UUID, "Headset Audio Gateway");
4391 interface_added_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4392 NULL, BT_MANAGER_INTERFACE,
4393 BT_INTERFACES_ADDED, NULL, NULL, 0,
4394 __bt_ag_agent_filter_cb, NULL, NULL);
4396 interface_removed_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4397 NULL, BT_MANAGER_INTERFACE,
4398 BT_INTERFACES_REMOVED, NULL, NULL, 0,
4399 __bt_ag_agent_filter_cb, NULL, NULL);
4401 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4402 media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4403 NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
4404 NULL, 0, __bt_ag_agent_media_filter_cb,
4407 media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4408 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
4409 NULL, 0, __bt_ag_agent_media_filter_cb,
4412 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4417 /* LCOV_EXCL_STOP */
4419 static uint32_t __bt_ag_agent_get_ag_features(void)
4422 uint32_t ag_features;
4424 if (TIZEN_MODEL_NAME_TM1) {
4425 ag_features = BT_AG_FEATURE_EC_AND_NR |
4426 BT_AG_FEATURE_REJECT_CALL |
4427 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4428 BT_AG_FEATURE_THREE_WAY_CALL |
4429 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4431 ag_features = BT_AG_FEATURE_EC_AND_NR |
4432 BT_AG_FEATURE_REJECT_CALL |
4433 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4434 BT_AG_FEATURE_THREE_WAY_CALL |
4435 BT_AG_FEATURE_VOICE_RECOGNITION |
4436 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4440 #if defined(TIZEN_FEATURE_BT_HFP_AG)
4441 hfp_ver = HFP_VERSION_1_7;
4443 hfp_ver = HFP_VERSION_1_5;
4445 hsp_ver = HSP_VERSION_1_2;
4447 if (hfp_ver > HFP_VERSION_1_5)
4448 ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
4449 if (hfp_ver == HFP_VERSION_1_7)
4450 ag_features |= BT_AG_FEATURE_ESCO_S4_T2_SUPPORT;
4455 /* LCOV_EXCL_START */
4456 void *__bt_ag_agent_telephony_init(void *arg)
4460 uint32_t ag_features = *((uint32_t *)arg);
4462 INFO_C("Initializing the telephony info");
4464 _bt_hfp_initialize_telephony_manager(ag_features);
4465 __bt_ag_agent_subscribe_vconf_updates();
4467 tapi_handle = tel_init(NULL);
4468 tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
4470 if (tapi_result != TAPI_API_SUCCESS)
4471 ERR("Fail to get sim info: %d", tapi_result);
4478 uint32_t ag_features;
4479 struct sigaction sa;
4480 pthread_t thread_id = 0;
4482 INFO_C("### Starting Bluetooth AG agent");
4484 ag_features = __bt_ag_agent_get_ag_features();
4486 ag.sdp_features = (uint16_t) ag_features & 0x1F;
4488 if (hfp_ver >= HFP_VERSION_1_6 && wbs_en == TRUE)
4489 ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
4491 memset(&sa, 0, sizeof(sa));
4492 sa.sa_flags = SA_NOCLDSTOP;
4493 sa.sa_handler = __bt_ag_agent_sigterm_handler;
4495 for (i = 0; i < BT_AG_SIG_NUM; i++)
4496 sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
4498 gmain_loop = g_main_loop_new(NULL, FALSE);
4500 if (gmain_loop == NULL) {
4501 ERR("GMainLoop create failed");
4502 return EXIT_FAILURE;
4505 __bt_ag_agent_dbus_init();
4506 if (pthread_create(&thread_id, NULL,
4507 (void *)&__bt_ag_agent_telephony_init,
4508 &ag_features) < 0) {
4509 ERR("pthread_create() is failed");
4510 return EXIT_FAILURE;
4513 if (pthread_detach(thread_id) < 0)
4514 ERR("pthread_detach() is failed");
4516 g_main_loop_run(gmain_loop);
4520 tel_deinit(tapi_handle);
4522 __bt_ag_agent_dbus_deinit();
4523 _bt_hfp_deinitialize_telephony_manager();
4524 __bt_ag_agent_release_vconf_updates();
4526 if (remote_dev_path)
4527 g_free(remote_dev_path);
4530 g_main_loop_unref(gmain_loop);
4532 INFO_C("### Terminating Bluetooth AG agent");
4535 /* LCOV_EXCL_STOP */