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);
411 free(host_device_address);
415 free(host_device_address);
419 /* TODO : Need to add companion device check condition for Phone models */
424 void __bt_convert_device_path_to_address(const gchar *device_path,
425 char *device_address)
427 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
430 ret_if(device_path == NULL);
431 ret_if(device_address == NULL);
433 dev_addr = strstr(device_path, "dev_");
434 if (dev_addr != NULL) {
437 g_strlcpy(address, dev_addr, sizeof(address));
439 while ((pos = strchr(address, '_')) != NULL)
442 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
446 static gboolean __bt_ag_agent_is_companion_device_connected(void)
450 for (l = active_devices ; l; l = l->next) {
451 bt_ag_info_t *data = l->data;
453 if (data->is_companion_device) {
454 DBG("Companion device found");
462 gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
464 char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
465 gboolean is_companion_device;
467 __bt_convert_device_path_to_address(device_path, device_address);
468 is_companion_device = __bt_ag_agent_is_companion_device(device_address);
470 DBG(" device_address[%s]", device_address);
471 DBG(" is_companion_device[%d]", is_companion_device);
473 if (__bt_ag_agent_is_companion_device_connected()) {
474 if (is_companion_device)
477 if (!is_companion_device)
482 #endif /* TIZEN_SUPPORT_DUAL_HF */
485 static gboolean __bt_is_phone_locked(int *phone_lock_state)
490 if (NULL == phone_lock_state)
493 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, phone_lock_state);
495 /* LCOV_EXCL_START */
496 ERR("Failed to read [%s]\n", VCONFKEY_IDLE_LOCK_STATE);
505 static gboolean __bt_get_outgoing_callapp_type(int *callapp_type)
509 if (NULL == callapp_type)
512 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
513 *callapp_type = BT_VOICE_CALL;
520 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT,
523 ERR("Failed to read [%s]\n",
524 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT);
528 INFO(" [%s] = [%d]\n",
529 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT, *callapp_type);
531 /* The vconf value does not include in platform. */
532 *callapp_type = BT_VOICE_CALL;
538 static gboolean __bt_get_outgoing_call_condition(int *condition)
542 if (NULL == condition)
545 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
546 *condition = BT_MO_ONLY_UNLOCKED;
553 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT,
556 ERR("Failed to read [%s]\n",
557 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT);
561 /* The vconf value does not include in platform. */
562 *condition = BT_MO_ONLY_UNLOCKED;
568 /* LCOV_EXCL_START */
569 static gboolean __bt_ag_agent_launch_call_app(const char *number)
574 DBG_SECURE("number(%s)", number);
578 ERR("bundle_create() Failed");
582 bundle_add(b, "launch-type", "MO");
583 bundle_add(b, "dial-type", "HEADSET");
585 if (strlen(number) != 0)
586 bundle_add(b, "number", number);
588 aul_launch_app_async(CALL_APP_ID, b);
595 static void *__bt_ag_agent_launch_call_req(void *arg)
598 bundle *b = (bundle *)arg;
599 if (appsvc_run_service(b, 0, NULL, NULL) < 0)
600 ERR("Unable to run app svc");
602 call_launch_requested = FALSE;
607 static gboolean __bt_ag_agent_make_call(const char *number)
611 char telnum[BT_MAX_TEL_NUM_STRING];
615 if (TIZEN_PROFILE_WEARABLE)
616 return __bt_ag_agent_launch_call_app(number);
618 if (call_launch_requested == TRUE) {
619 DBG("Launch request is in progress");
627 appsvc_set_operation(b, APPSVC_OPERATION_CALL);
628 snprintf(telnum, sizeof(telnum), "tel:%s", number);
629 appsvc_set_uri(b, telnum);
630 appsvc_add_data(b, "ctindex", "-1");
632 call_launch_requested = TRUE;
633 if (pthread_create(&thread_id, NULL,
634 (void *)&__bt_ag_agent_launch_call_req,
636 ERR("pthread_create() is failed");
637 call_launch_requested = FALSE;
640 if (pthread_detach(thread_id) < 0)
641 ERR("pthread_detach() is failed");
647 static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
652 kb = bundle_create();
656 bundle_add(kb, "KEY_CALL_TYPE", "MO");
657 bundle_add(kb, "number", mo_number);
658 aul_launch_app("org.tizen.vtmain", kb);
665 gboolean _bt_ag_agent_answer_call(unsigned int call_id,
666 const gchar *path, const gchar *sender)
670 if (path == NULL || sender == NULL) {
671 DBG("Invalid Arguments");
675 DBG("Application path = %s", path);
676 DBG("Call Id = %d", call_id);
677 DBG("Sender = %s", sender);
679 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
680 BT_HEADSET_INTERFACE, "Answer",
681 g_variant_new("(u)", call_id));
686 gboolean _bt_ag_agent_reject_call(unsigned int call_id,
687 const gchar *path, const gchar *sender)
691 if (path == NULL || sender == NULL) {
692 DBG("Invalid Arguments");
696 DBG("Application path = %s", path);
697 DBG("Call Id = %d", call_id);
698 DBG("Sender = %s", sender);
700 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
701 BT_HEADSET_INTERFACE, "Reject",
702 g_variant_new("(u)", call_id));
707 gboolean _bt_ag_agent_release_call(unsigned int call_id,
708 const gchar *path, const gchar *sender)
712 if (path == NULL || sender == NULL) {
713 DBG("Invalid Arguments");
717 DBG("Application path = %s", path);
718 DBG("Call Id = %d", call_id);
719 DBG("Sender = %s", sender);
721 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
722 BT_HEADSET_INTERFACE, "Release",
723 g_variant_new("(u)", call_id));
730 bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
732 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
734 int phone_lock_state;
739 if (number == NULL) {
740 ERR("Invalid Argument");
741 error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
745 DBG("Number = %s", number);
746 DBG("flags = %d", flags);
748 if (!__bt_is_phone_locked(&phone_lock_state)) {
749 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
753 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
754 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
758 if (!__bt_get_outgoing_call_condition(&condition)) {
759 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
763 if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
764 VCONFKEY_IDLE_LOCK) {
765 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
769 /* LCOV_EXCL_START */
770 if (callapp_type == BT_VIDEO_CALL) {
771 if (!__bt_ag_agent_make_video_call(number)) {
772 ERR("Problem launching application");
773 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
777 if (!__bt_ag_agent_make_call(number)) {
778 ERR("Problem launching application");
779 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
790 bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
792 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
794 contacts_filter_h filter = NULL;
795 contacts_query_h query = NULL;
796 contacts_list_h list = NULL;
797 contacts_record_h record = NULL;
798 unsigned int projections[] = {
799 _contacts_speeddial.number,
804 DBG("location = %d", location);
806 /*Get number from contacts location*/
807 if (contacts_connect() != CONTACTS_ERROR_NONE) {
808 ERR(" contacts_connect failed");
809 return BT_HFP_AGENT_ERROR_INTERNAL;
812 /* LCOV_EXCL_START */
813 contacts_filter_create(_contacts_speeddial._uri, &filter);
818 if (contacts_filter_add_int(filter,
819 _contacts_speeddial.speeddial_number,
820 CONTACTS_MATCH_EQUAL, location) !=
821 CONTACTS_ERROR_NONE) {
822 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
826 contacts_query_create(_contacts_speeddial._uri, &query);
831 contacts_query_set_filter(query, filter);
833 if (contacts_query_set_projection(query, projections,
834 sizeof(projections)/sizeof(unsigned int)) !=
835 CONTACTS_ERROR_NONE) {
836 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
840 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
841 CONTACTS_ERROR_NONE) {
842 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
846 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
847 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
851 if (contacts_list_get_current_record_p(list, &record) !=
852 CONTACTS_ERROR_NONE) {
853 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
860 if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
861 != CONTACTS_ERROR_NONE) {
862 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
866 if (number == NULL) {
867 ERR("No number at the location");
868 error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
872 DBG("number %s", number);
875 if (!__bt_ag_agent_make_call(number)) {
876 ERR("Problem launching application");
877 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
883 contacts_list_destroy(list, TRUE);
886 contacts_filter_destroy(filter);
889 contacts_query_destroy(query);
891 contacts_disconnect();
899 /* LCOV_EXCL_START */
900 bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
901 const gchar *path, const gchar *sender)
903 bt_hfp_agent_error_t ret;
907 if (dtmf == NULL || path == NULL || sender == NULL) {
908 ERR("Invalid Argument");
909 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
912 DBG("Dtmf = %s", dtmf);
913 DBG("Application path = %s", path);
914 DBG("Sender = %s", sender);
916 ret = __bt_ag_agent_gdbus_method_send(sender,
917 path, TELEPHONY_APP_INTERFACE,
919 g_variant_new("(s)", dtmf));
924 gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
925 const gchar *path, const gchar *sender)
929 if (path == NULL || sender == NULL) {
930 DBG("Invalid Arguments");
934 DBG("Application path = %s", path);
935 DBG("Value = %d", chld_value);
936 DBG("Sender = %s", sender);
938 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
939 /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
940 if not return FALSE */
941 if (chld_value != 0 && chld_value != 1 && chld_value != 2)
944 if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
948 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
949 BT_HEADSET_INTERFACE, "Threeway",
950 g_variant_new("(u)", chld_value));
956 bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
958 bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
959 char *last_num = NULL;
962 int phone_lock_state;
964 contacts_list_h list = NULL;
965 contacts_query_h query = NULL;
966 contacts_filter_h filter = NULL;
967 contacts_record_h record = NULL;
968 unsigned int projections[] = {
969 _contacts_phone_log.address,
970 _contacts_phone_log.log_type,
975 if (contacts_connect() != CONTACTS_ERROR_NONE) {
976 ERR(" contacts_connect failed");
977 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
981 /* LCOV_EXCL_START */
982 contacts_filter_create(_contacts_phone_log._uri, &filter);
987 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
988 CONTACTS_MATCH_EQUAL,
989 CONTACTS_PLOG_TYPE_VOICE_OUTGOING) !=
990 CONTACTS_ERROR_NONE) {
991 ERR(" contacts_filter_add_int failed");
992 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
996 if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) !=
997 CONTACTS_ERROR_NONE) {
998 ERR(" contacts_filter_add_operator failed");
999 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1003 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
1004 CONTACTS_MATCH_EQUAL,
1005 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) !=
1006 CONTACTS_ERROR_NONE) {
1007 ERR(" contacts_filter_add_int failed");
1008 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1012 contacts_query_create(_contacts_phone_log._uri, &query);
1017 contacts_query_set_filter(query, filter);
1019 if (contacts_query_set_projection(query, projections,
1020 sizeof(projections)/sizeof(unsigned int)) !=
1021 CONTACTS_ERROR_NONE) {
1022 ERR(" contacts_query_set_projection failed");
1023 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1027 if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false)
1028 != CONTACTS_ERROR_NONE) {
1029 ERR(" contacts_query_set_sort failed");
1030 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1034 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
1035 CONTACTS_ERROR_NONE) {
1036 ERR(" contacts_db_get_records_with_query failed");
1037 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1041 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
1042 ERR(" contacts_list_first failed");
1043 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1047 if (contacts_list_get_current_record_p(list, &record) !=
1048 CONTACTS_ERROR_NONE) {
1049 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1056 if (contacts_record_get_str(record, _contacts_phone_log.address,
1057 &last_num) != CONTACTS_ERROR_NONE) {
1058 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1062 if (last_num == NULL) {
1063 ERR("No last number");
1064 err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
1068 if (!__bt_is_phone_locked(&phone_lock_state)) {
1069 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1073 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
1074 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1078 if (!__bt_get_outgoing_call_condition(&condition)) {
1079 ERR(" Failed to get the call condition");
1080 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1084 if (condition == BT_MO_ONLY_UNLOCKED &&
1085 phone_lock_state == VCONFKEY_IDLE_LOCK) {
1086 ERR(" call condition and phone lock state check fail");
1087 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1091 switch (callapp_type) {
1093 if (!__bt_ag_agent_make_call(last_num)) {
1094 ERR("Problem launching application");
1095 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1099 if (!__bt_ag_agent_make_video_call(last_num)) {
1100 ERR("Problem launching application");
1101 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1104 case BT_FOLLOW_CALL_LOG:
1105 if (contacts_record_get_int(record,
1106 _contacts_phone_log.log_type,
1107 &type) != CONTACTS_ERROR_NONE) {
1108 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1111 if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
1112 if (!__bt_ag_agent_make_call(last_num)) {
1113 ERR("Problem launching application");
1114 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1116 } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
1117 if (!__bt_ag_agent_make_video_call(last_num)) {
1118 ERR("Problem launching application");
1119 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1122 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1126 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1133 contacts_list_destroy(list, TRUE);
1136 contacts_filter_destroy(filter);
1139 contacts_query_destroy(query);
1141 contacts_disconnect();
1143 if (last_num != NULL)
1149 /* LCOV_EXCL_STOP */
1152 /* LCOV_EXCL_START */
1153 bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
1154 const gchar *path, const gchar *sender)
1156 bt_hfp_agent_error_t ret;
1160 if (cmd == NULL || path == NULL || sender == NULL) {
1161 ERR("Invalid Argument");
1162 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
1165 DBG("cmd = %s", cmd);
1166 DBG("Application path = %s", path);
1167 DBG("Sender = %s", sender);
1169 ret = __bt_ag_agent_gdbus_method_send(sender,
1170 path, TELEPHONY_APP_INTERFACE,
1172 g_variant_new("(s)", cmd));
1176 /* LCOV_EXCL_STOP */
1178 gboolean _bt_ag_agent_get_signal_quality(void *device)
1184 if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
1185 DBG("VCONFKEY_TELEPHONY_RSSI failed\n"); /* LCOV_EXCL_LINE */
1189 DBG("RSSI : %d", rssi);
1191 _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
1197 /* LCOV_EXCL_START */
1199 _bt_hfp_signal_quality_reply(-1, -1, device);
1201 /* LCOV_EXCL_STOP */
1204 gboolean _bt_ag_agent_get_battery_status(void *device)
1206 gint battery_chrg_status;
1207 gint battery_capacity;
1211 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
1212 &battery_chrg_status)) {
1213 DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n"); /* LCOV_EXCL_LINE */
1217 DBG("Status : %d\n", battery_chrg_status);
1219 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
1220 &battery_capacity)) {
1221 DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n"); /* LCOV_EXCL_LINE */
1225 DBG("Capacity : %d\n", battery_capacity);
1227 _bt_hfp_battery_property_reply(device,
1228 battery_chrg_status, battery_capacity);
1233 /* LCOV_EXCL_START */
1234 _bt_hfp_battery_property_reply(device, -1, -1);
1237 /* LCOV_EXCL_STOP */
1240 gboolean _bt_ag_agent_get_operator_name(void *device)
1242 char *operator_name;
1245 operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
1246 if (NULL == operator_name) {
1247 /* LCOV_EXCL_START */
1248 DBG("vconf_get_str failed");
1249 _bt_hfp_operator_reply(NULL, device);
1251 /* LCOV_EXCL_STOP */
1254 DBG("operator_name = [%s]", operator_name);
1256 _bt_hfp_operator_reply(operator_name, device);
1258 free(operator_name);
1264 gboolean _bt_hfp_agent_nrec_status(gboolean status,
1268 bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
1270 DBG("NREC status = %d", status);
1272 hs->nrec_status = FALSE;
1274 hs->nrec_status = TRUE;
1277 _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
1278 BT_HEADSET_INTERFACE, "NrecStatusChanged",
1279 g_variant_new("(b)", status));
1284 gboolean _bt_ag_agent_get_imei_number(void *device)
1289 imei_number = tel_get_misc_me_imei_sync(tapi_handle);
1290 if (NULL == imei_number) {
1291 ERR("tel_get_misc_me_imei_sync for imei_number failed");
1295 /* LCOV_EXCL_START */
1296 if (!g_utf8_validate(imei_number, -1, NULL)) {
1298 ERR("get_imei_number : invalid UTF8");
1302 DBG_SECURE("imei_number = [%s]", imei_number);
1303 _bt_hfp_get_imei_number_reply(imei_number, device);
1307 /* LCOV_EXCL_STOP */
1309 _bt_hfp_get_imei_number_reply(NULL, device);
1314 void _bt_ag_agent_get_manufacturer_name(void *device)
1317 char *manufacturer_name;
1320 ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
1321 &manufacturer_name);
1322 if (SYSTEM_INFO_ERROR_NONE != ret) {
1323 /* LCOV_EXCL_START */
1324 ERR("Get manufacturer_name failed : %d", ret);
1325 if (NULL != manufacturer_name)
1326 free(manufacturer_name);
1328 manufacturer_name = g_strdup("Unknown");
1329 /* LCOV_EXCL_STOP */
1330 } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
1331 /* LCOV_EXCL_START */
1332 free(manufacturer_name);
1333 manufacturer_name = g_strdup("Unknown");
1334 ERR("get_manufacturer_name : invalid UTF8");
1335 /* LCOV_EXCL_STOP */
1338 DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
1339 _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
1340 free(manufacturer_name);
1344 void _bt_ag_agent_get_imsi(void *device)
1347 TelSimImsiInfo_t imsi;
1348 memset(&imsi, 0, sizeof(TelSimImsiInfo_t));
1349 if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
1350 ERR("tel_get_sim_imsi failed");
1353 /* LCOV_EXCL_START */
1354 DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
1356 _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
1359 /* LCOV_EXCL_STOP */
1361 _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
1365 /* LCOV_EXCL_START */
1366 int _bt_ag_agent_registration_status_convert(int result)
1369 case TAPI_NETWORK_SERVICE_LEVEL_NO:
1370 return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
1371 case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
1372 return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
1373 case TAPI_NETWORK_SERVICE_LEVEL_FULL:
1374 return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
1375 case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
1376 return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
1378 return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
1382 /* LCOV_EXCL_STOP */
1384 void _bt_ag_agent_get_creg_status(void *device)
1390 int registration_status = 0;
1391 int roam_status = 0;
1393 ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
1395 if (ret != TAPI_API_SUCCESS) {
1396 ERR("tel_get_property_int failed");
1399 /* LCOV_EXCL_START */
1400 registration_status =
1401 _bt_ag_agent_registration_status_convert(result);
1403 DBG_SECURE("Registration status %d", result);
1404 DBG_SECURE("Mapped Status %d", registration_status);
1405 if (registration_status ==
1406 BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
1407 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
1409 ERR("Get roaming status failed err = %d\n", ret);
1412 DBG_SECURE("Roam status %d", roam_status);
1413 if (roam_status == 1) {
1414 registration_status =
1415 BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
1419 _bt_hfp_get_creg_status_reply(n, registration_status, device);
1423 /* LCOV_EXCL_STOP */
1426 void _bt_ag_agent_get_model_name(void *device)
1432 ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
1433 if (SYSTEM_INFO_ERROR_NONE != ret) {
1434 ERR("Get model_name failed: %d", ret);
1435 if (NULL != model_name)
1438 model_name = g_strdup("Unknown");
1439 } else if (!g_utf8_validate(model_name, -1, NULL)) {
1441 model_name = g_strdup("Unknown");
1442 ERR("get_model_name : invalid UTF8");
1445 DBG_SECURE("model_name = [%s]", model_name);
1446 _bt_hfp_get_model_info_reply(model_name, device);
1451 void _bt_ag_agent_get_revision_information(void *device)
1454 char *revision_info;
1457 ret = system_info_get_platform_string("http://tizen.org/system/build.string",
1459 if (SYSTEM_INFO_ERROR_NONE != ret) {
1460 ERR("Get revision_info failed: %d", ret);
1461 if (NULL != revision_info)
1462 free(revision_info);
1464 revision_info = g_strdup("Unknown");
1465 } else if (!g_utf8_validate(revision_info, -1, NULL)) {
1466 free(revision_info);
1467 revision_info = g_strdup("Unknown");
1468 ERR("get_revision_info: invalid UTF8");
1471 DBG_SECURE("revision_info = [%s]", revision_info);
1472 _bt_hfp_get_revision_info_reply(revision_info, device);
1473 free(revision_info);
1477 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
1478 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1483 b = bundle_create();
1485 ERR("bundle_create() Failed");
1489 bundle_add(b, "domain", "bt_headset");
1491 bundle_add(b, "action_type", "deactivate");
1493 aul_launch_app_async("org.tizen.svoice", b);
1499 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1502 app_control_h service = NULL;
1504 app_control_create(&service);
1506 if (service == NULL) {
1507 ERR("Service create failed");
1511 app_control_set_app_id(service, "org.tizen.svoice");
1512 app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
1513 if (app_control_add_extra_data(service, "domain", "bt_headset")
1514 != APP_CONTROL_ERROR_NONE) {
1515 ERR("app_control_add_extra_data failed");
1516 app_control_destroy(service);
1521 if (app_control_add_extra_data(service, "action_type", "deactivate")
1522 != APP_CONTROL_ERROR_NONE) {
1523 ERR("app_control_add_extra_data failed");
1524 app_control_destroy(service);
1528 if (app_control_send_launch_request(service, NULL, NULL) !=
1529 APP_CONTROL_ERROR_NONE) {
1530 ERR("launch failed");
1531 app_control_destroy(service);
1535 app_control_destroy(service);
1541 gboolean _bt_ag_agent_voice_dial(gboolean activate)
1543 DBG("Activate = %d", activate);
1545 return __bt_ag_agent_launch_voice_dial(activate);
1548 /* LCOV_EXCL_START */
1549 static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
1552 hs->codec_info.is_negotiating = FALSE;
1553 hs->codec_info.requested_by_hf = FALSE;
1554 hs->codec_info.sending_codec = 0;
1556 hs->codec_info.remote_codecs = 0;
1557 hs->codec_info.final_codec = 0;
1558 hs->nrec_status = FALSE;
1561 if (hs->codec_info.nego_timer) {
1562 g_source_remove(hs->codec_info.nego_timer);
1563 hs->codec_info.nego_timer = 0;
1565 wbs_opts.wbs_enable = wbs_en;
1568 static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
1570 struct ag_codec *data = (struct ag_codec *)user_data;
1572 if (g_strcmp0(data->codec_status, "finish") == 0) {
1573 DBG("Codec negotiation finished");
1574 __bt_ag_sco_connect(data->bt_ag_info);
1575 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1576 g_free(data->codec_status);
1579 } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
1580 DBG("Timeout is occured in codec negotiation");
1583 if (data->bt_ag_info->codec_info.requested_by_hf) {
1584 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1586 __bt_ag_sco_connect(data->bt_ag_info);
1587 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1589 g_free(data->codec_status);
1595 static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
1600 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
1602 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
1603 G_DBUS_PROXY_FLAGS_NONE, NULL,
1604 BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
1605 BT_ADAPTER_INTERFACE, NULL, &err);
1609 ERR("Unable to create proxy: %s", err->message);
1610 g_clear_error(&err);
1612 return BT_HFP_AGENT_ERROR_INTERNAL;
1615 ret = g_dbus_proxy_call_sync(proxy, method,
1616 g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
1617 G_DBUS_CALL_FLAGS_NONE, -1,
1620 /* dBUS-RPC is failed */
1621 ERR("dBUS-RPC is failed");
1623 /* dBUS gives error cause */
1624 ERR("D-Bus API failure: errCode[%x], message[%s]",
1625 err->code, err->message);
1627 g_clear_error(&err);
1629 return BT_HFP_AGENT_ERROR_INTERNAL;
1631 g_variant_unref(ret);
1633 return BT_HFP_AGENT_ERROR_NONE;
1636 static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
1639 bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
1641 DBG("Codec setup [%x]", codec);
1643 /* 1. Compare sending codec & recieved code */
1644 if (hs->codec_info.sending_codec != codec)
1645 err = BT_HFP_AGENT_ERROR_INTERNAL;
1647 /* 2. Send WB or NB command */
1649 case BT_CVSD_CODEC_ID:
1650 err = __bt_ag_set_codec(hs, "SetNbParameters");
1652 case BT_MSBC_CODEC_ID:
1653 err = __bt_ag_set_codec(hs, "SetWbsParameters");
1656 err = BT_HFP_AGENT_ERROR_INTERNAL;
1660 /* If the vendor specific calling returns error or codec is not correct,
1661 * we send CVSD Codec parameter to MM module. and also returns
1662 * normal value to HF
1664 if (err != BT_HFP_AGENT_ERROR_NONE)
1665 codec = BT_CVSD_CODEC_ID;
1667 hs->codec_info.final_codec = codec;
1672 static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
1673 gboolean init_by_hf)
1676 struct ag_codec *data = NULL;;
1678 if (TIZEN_MODEL_NAME_TM1) {
1679 codec = BT_CVSD_CODEC_ID;
1681 if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
1682 codec = BT_MSBC_CODEC_ID;
1684 codec = BT_CVSD_CODEC_ID;
1687 if (wbs_opts.wbs_enable == FALSE)
1688 codec = BT_CVSD_CODEC_ID;
1692 if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
1693 return BT_HFP_AGENT_ERROR_INTERNAL;
1695 DBG("Send +BCS:%d\n", codec);
1697 /* Send +BCS command to HF, and wait some times */
1698 hs->codec_info.is_negotiating = TRUE;
1699 hs->codec_info.sending_codec = codec;
1700 hs->codec_info.requested_by_hf = init_by_hf;
1701 hs->codec_info.final_codec = codec;
1703 data = g_new0(struct ag_codec, 1);
1705 return BT_HFP_AGENT_ERROR_NO_MEMORY;
1707 data->bt_ag_info = hs;
1708 data->codec_status = g_strdup("timeout");
1710 hs->codec_info.nego_timer = g_timeout_add_seconds(
1711 HFP_CODEC_NEGOTIATION_TIMEOUT,
1712 (GSourceFunc)__bt_ag_codec_negotiation_finished,
1715 return BT_HFP_AGENT_ERROR_NONE;
1719 static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
1720 bt_ag_info_t *hs, gboolean init_by_hf)
1722 DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
1724 if (hs->state < HEADSET_STATE_CONNECTED)
1725 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1727 if (hs->codec_info.is_negotiating == TRUE) {
1728 /* In codec negotiation, return and wait */
1729 ERR("Codec nogotiation is in progress");
1730 return BT_HFP_AGENT_ERROR_BUSY;
1733 /* Not support Codec Negotiation or Not recieved BAC command */
1734 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
1735 hs->codec_info.remote_codecs == 0) {
1736 ERR("No support for Codec Negotiation or receive BAC command");
1738 return BT_HFP_AGENT_ERROR_INTERNAL;
1740 __bt_ag_sco_connect(hs);
1741 return BT_HFP_AGENT_ERROR_INTERNAL;
1745 /* If HF initiated codec connection setup, it should send OK command
1746 * before +BCS command transmission.
1749 return HFP_STATE_MNGR_ERR_NONE;
1751 return __bt_hfp_send_bcs_command(hs, init_by_hf);
1755 static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
1758 *codecs = 0x00000000;
1760 str = strchr(cmd, '=');
1764 while (str != NULL) {
1767 if (atoi(str) == BT_CVSD_CODEC_ID)
1768 *codecs |= BT_CVSD_CODEC_MASK;
1769 else if (atoi(str) == BT_MSBC_CODEC_ID)
1770 *codecs |= BT_MSBC_CODEC_MASK;
1772 str = strchr(str, ',');
1775 if (*codecs == 0x00000000)
1781 /* AT+BAC (Bluetooth Available Codecs) */
1782 static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
1784 uint32_t codecs = 0x00000000;
1785 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1787 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
1788 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1789 } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
1790 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1792 DBG("Update remote available codecs [%x]", codecs);
1793 hs->codec_info.remote_codecs = codecs;
1796 _bt_ag_send_response(hs, err);
1798 /* Reset codec information and
1799 * restart codec connection setup by AG
1801 hs->codec_info.final_codec = 0;
1802 if (hs->codec_info.nego_timer) {
1803 hs->codec_info.is_negotiating = FALSE;
1804 hs->codec_info.requested_by_hf = FALSE;
1805 hs->codec_info.sending_codec = 0;
1806 g_source_remove(hs->codec_info.nego_timer);
1807 __bt_hfp_codec_connection_setup(hs, FALSE);
1813 /* AT+BCC (Bluetooth Codec Connection) */
1814 static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
1816 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1818 err = __bt_hfp_codec_connection_setup(hs, TRUE);
1820 _bt_ag_send_response(hs, err);
1822 if (err == HFP_STATE_MNGR_ERR_NONE)
1823 err = __bt_hfp_send_bcs_command(hs, TRUE);
1825 if (err != HFP_STATE_MNGR_ERR_NONE)
1826 ERR("Fail to request codec connection setup");
1831 /* AT+BCS (Bluetooth Codec Selection) */
1832 static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
1834 uint32_t codec = 0x00000000;
1835 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1836 struct ag_codec *data = g_new0(struct ag_codec, 1);
1839 if (hs->codec_info.nego_timer) {
1840 g_source_remove(hs->codec_info.nego_timer);
1841 hs->codec_info.nego_timer = 0;
1844 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
1845 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1846 else if (__hfp_parse_available_codecs(buf, &codec) < 0)
1847 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1848 else if (__bt_ag_codec_selection_setup(hs, codec) !=
1849 BT_HFP_AGENT_ERROR_NONE)
1850 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1852 data->bt_ag_info = hs;
1853 data->codec_status = g_strdup("finish");
1854 _bt_ag_send_response(hs, err);
1855 __bt_ag_codec_negotiation_finished(data);
1860 static void __bt_ag_str2ba(const char *str, bt_addr *ba)
1863 for (i = 5; i >= 0; i--, str += 3)
1864 ba->b[i] = strtol(str, NULL, 16);
1866 /* LCOV_EXCL_STOP */
1868 static const char *__bt_ag_state2str(hs_state_t state)
1871 case HEADSET_STATE_DISCONNECTED:
1872 return "disconnected";
1873 case HEADSET_STATE_CONNECTING:
1874 return "connecting";
1875 case HEADSET_STATE_CONNECTED:
1877 case HEADSET_STATE_PLAY_IN_PROGRESS:
1878 return "Play In Progress";
1879 case HEADSET_STATE_ON_CALL:
1886 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
1887 const char *address)
1892 ret_if(address == NULL);
1893 ret_if(addr == NULL);
1895 for (i = 0; i < 6; i++) {
1896 addr[5 - i] = strtol(address, &ptr, 16);
1897 if (ptr[0] != '\0') {
1906 /* LCOV_EXCL_START */
1907 static gboolean __bt_ag_check_nval(GIOChannel *chan)
1909 struct pollfd file_desc;
1911 memset(&file_desc, 0, sizeof(file_desc));
1912 file_desc.fd = g_io_channel_unix_get_fd(chan);
1913 file_desc.events = POLLNVAL;
1915 if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
1921 static int __bt_ag_sco_connect(bt_ag_info_t *hs)
1923 struct sco_socket_addr sco_addr;
1928 bt_ag_slconn_t *slconn = hs->slc;
1931 if (hs->state == HEADSET_STATE_ON_CALL)
1932 return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED;
1934 if (hs->state != HEADSET_STATE_CONNECTED)
1935 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1936 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
1937 _bt_ag_agent_check_transport_state();
1940 /* Create Sco socket */
1941 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
1943 ERR("ERROR: Create socket failed.\n");
1944 return BT_HFP_AGENT_ERROR_INTERNAL;
1947 /* Bind Sco Socket to Local BD addr */
1948 memset(&sco_addr, 0, sizeof(sco_addr));
1949 sco_addr.sco_family = AF_BLUETOOTH;
1951 __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
1952 DBG("Local BD address: %s", local_addr);
1954 err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1956 ERR("ERROR: sco socket binding failed");
1957 ERR("Close SCO skt");
1959 return BT_HFP_AGENT_ERROR_INTERNAL;
1962 DBG("Socket FD : %d", sco_skt);
1964 io = g_io_channel_unix_new(sco_skt);
1965 g_io_channel_set_close_on_unref(io, TRUE);
1966 /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
1967 g_io_channel_set_buffered(io, FALSE);
1968 g_io_channel_set_encoding(io, NULL, NULL);*/
1970 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
1971 (slconn && (slconn->hs_features &
1972 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
1973 wbs_opts.wbs_enable == TRUE) {
1974 bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
1975 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
1977 DBG("set Bluetooth voice: %d", bt_vo.setting);
1978 err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
1979 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
1981 ERR("ERROR: sco socket set socket option failed");
1982 ERR("Close SCO skt");
1983 g_io_channel_unref(io);
1985 return BT_HFP_AGENT_ERROR_INTERNAL;
1988 DBG("Set NB codec parameter");
1989 __bt_ag_set_codec(hs, "SetNbParameters");
1992 memset(&sco_addr, 0, sizeof(sco_addr));
1993 sco_addr.sco_family = AF_BLUETOOTH;
1994 __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
1995 DBG("remotel BD address: %s", hs->remote_addr);
1997 err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1998 if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
1999 ERR("ERROR: sco socket connect failed : %d", err);
2000 ERR("Close SCO skt");
2001 g_io_channel_unref(io);
2003 return BT_HFP_AGENT_ERROR_INTERNAL;
2006 /* Disabling the watch since SCO is connected */
2007 /*watch_id = __bt_ag_set_watch(io,
2008 (GIOFunc) __bt_ag_sco_connect_cb, hs);
2010 DBG("SCO watch set Success");*/
2014 _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
2015 return BT_HFP_AGENT_ERROR_NONE;
2018 static void __bt_ag_close_sco(bt_ag_info_t *hs)
2022 int sock = g_io_channel_unix_get_fd(hs->sco);
2023 shutdown(sock, SHUT_RDWR);
2024 g_io_channel_unref(hs->sco);
2029 __bt_ag_agent_remove_watch(&hs->sco_id);
2031 if (hs->sco_incoming_id)
2032 __bt_ag_agent_remove_watch(&hs->sco_incoming_id);
2035 static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
2036 GIOCondition cond, gpointer user_data)
2038 bt_ag_info_t *ag_info = user_data;
2041 if (cond & G_IO_NVAL)
2044 if (cond & (G_IO_HUP | G_IO_ERR)) {
2045 ag_info->sco = NULL;
2046 if (ag_info->sco_id)
2047 __bt_ag_agent_remove_watch(&ag_info->sco_id);
2049 if (ag_info->sco_incoming_id)
2050 __bt_ag_agent_remove_watch(&ag_info->sco_incoming_id);
2052 if (ag_info->watch_id)
2053 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
2059 static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
2060 GIOCondition cond, gpointer user_data)
2062 bt_ag_info_t *ag_info = user_data;
2066 bt_ag_slconn_t *slconn = ag_info->slc;
2070 if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
2071 __bt_ag_check_nval(chan)) {
2072 ERR("cond or chan is not valid");
2076 INFO_C("Incoming SCO....");
2078 if (ag_info->state < HEADSET_STATE_CONNECTED)
2079 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
2081 sco_skt = g_io_channel_unix_get_fd(chan);
2083 cli_sco_sock = accept(sco_skt, NULL, NULL);
2084 if (cli_sco_sock < 0) {
2085 ERR("accept is failed");
2089 sco_io = g_io_channel_unix_new(cli_sco_sock);
2090 g_io_channel_set_close_on_unref(sco_io, TRUE);
2091 g_io_channel_set_encoding(sco_io, NULL, NULL);
2092 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2093 g_io_channel_set_buffered(sco_io, FALSE);
2095 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2096 (slconn && (slconn->hs_features &
2097 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
2098 wbs_opts.wbs_enable == TRUE) {
2099 bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
2100 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
2102 DBG("set Bluetooth voice: %d", bt_vo.setting);
2103 err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
2104 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
2106 ERR("Sco socket set socket option failed");
2107 close(cli_sco_sock);
2112 ag_info->sco = sco_io;
2113 ag_info->sco_incoming_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2114 __bt_ag_sco_server_conn_cb, ag_info);
2116 if (remote_dev_path)
2117 g_free(remote_dev_path);
2119 remote_dev_path = g_strdup(ag_info->path);
2121 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
2125 /* LCOV_EXCL_STOP */
2127 static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
2129 DBG("Start SCO server");
2130 struct sco_socket_addr addr;
2133 bdaddr_t bd_addr = {{0},};
2135 if (hs->sco_server_started) {
2136 DBG("Already exsist");
2137 return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
2141 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
2143 ERR("Can't create socket:\n");
2144 return BT_HFP_AGENT_ERROR_INTERNAL;
2147 /* Bind to local address */
2148 memset(&addr, 0, sizeof(addr));
2149 addr.sco_family = AF_BLUETOOTH;
2151 _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
2152 DBG("Bind to address %s", hs->remote_addr);
2153 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2155 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2156 ERR("Can't bind socket:\n");
2160 if (listen(sco_skt, 1)) {
2161 ERR("Can not listen on the socket:\n");
2165 sco_io = g_io_channel_unix_new(sco_skt);
2166 g_io_channel_set_close_on_unref(sco_io, TRUE);
2167 g_io_channel_set_encoding(sco_io, NULL, NULL);
2168 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2169 g_io_channel_set_buffered(sco_io, FALSE);
2171 hs->sco_server = sco_io;
2172 hs->sco_watch_id = g_io_add_watch(sco_io,
2173 G_IO_IN | G_IO_HUP | G_IO_ERR |
2174 G_IO_NVAL, __bt_ag_sco_server_cb, hs);
2176 hs->sco_server_started = TRUE;
2177 return BT_HFP_AGENT_ERROR_NONE;
2181 return BT_HFP_AGENT_ERROR_INTERNAL;
2184 /* LCOV_EXCL_START */
2185 void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
2187 DBG("Stop SCO server");
2188 if (hs->sco_server) {
2189 g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
2190 g_io_channel_unref(hs->sco_server);
2191 hs->sco_server = NULL;
2193 hs->sco_server_started = FALSE;
2196 static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
2198 GIOChannel *rfcomm = hs->rfcomm;
2201 g_io_channel_shutdown(rfcomm, TRUE, NULL);
2202 g_io_channel_unref(rfcomm);
2212 static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
2215 if (cond & G_IO_NVAL)
2218 if (name_owner_sig_id != -1)
2219 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
2221 name_owner_sig_id = -1;
2225 DBG("Audio connection disconnected");
2226 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2231 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
2233 bt_ag_slconn_t *slconn = hs->slc;
2234 const char *hs_state;
2235 hs_state_t org_state = hs->state;
2236 gboolean val = FALSE;
2238 if (org_state == state)
2241 hs_state = __bt_ag_state2str(state);
2244 case HEADSET_STATE_CONNECTING:
2245 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2247 BT_HEADSET_INTERFACE, "State",
2248 g_variant_new("s", hs_state));
2252 case HEADSET_STATE_CONNECTED:
2253 if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
2254 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2256 BT_HEADSET_INTERFACE, "State",
2257 g_variant_new("s", hs_state));
2259 if (hs->state < state) {
2261 active_devices = g_slist_append(active_devices, hs);
2262 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2264 BT_HEADSET_INTERFACE,
2266 g_variant_new("b", val));
2268 DBG("Device %s connected\n", hs->remote_addr);
2269 #if defined(TIZEN_SUPPORT_DUAL_HF)
2270 if (!hs->is_companion_device)
2271 __bt_ag_start_sco_server(hs);
2273 __bt_ag_start_sco_server(hs);
2276 /* Set default code as Gateway NB */
2277 __bt_ag_set_codec(hs, "SetNbParameters");
2278 } else if (hs->state == HEADSET_STATE_ON_CALL) {
2280 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2282 BT_HEADSET_INTERFACE,
2284 g_variant_new("b", val));
2289 case HEADSET_STATE_DISCONNECTED:
2290 __bt_ag_close_sco(hs);
2291 __bt_ag_headset_close_rfcomm(hs);
2293 if (hs->state == HEADSET_STATE_ON_CALL) {
2295 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2297 BT_HEADSET_INTERFACE,
2299 g_variant_new("b", val));
2303 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2305 BT_HEADSET_INTERFACE,
2307 g_variant_new("b", val));
2308 if (hs->state > HEADSET_STATE_CONNECTING)
2309 _bt_hfp_device_disconnected(hs);
2311 active_devices = g_slist_remove(active_devices, hs);
2313 __bt_ag_codec_negotiation_info_reset(hs, TRUE);
2314 #if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
2315 __bt_ag_set_codec(hs, "SetNbParameters");
2319 /* Since SCO server is binded on remote address */
2320 /* Need to stop SCO server once heasdet disconencted*/
2321 if (hs->sco_server_started)
2322 __bt_ag_stop_sco_server(hs);
2324 g_free(hs->remote_addr);
2328 case HEADSET_STATE_PLAY_IN_PROGRESS:
2329 case HEADSET_STATE_ON_CALL:
2331 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2333 BT_HEADSET_INTERFACE, "State",
2334 g_variant_new("s", hs_state));
2336 /*add watch for sco data */
2337 hs->sco_id = g_io_add_watch(hs->sco,
2338 G_IO_ERR | G_IO_NVAL,
2339 (GIOFunc) __bt_ag_sco_cb, hs);
2341 _bt_ag_agent_emit_property_changed(
2342 ag_dbus_conn, hs->path,
2343 BT_HEADSET_INTERFACE, "Playing",
2344 g_variant_new("b", val));
2346 if (slconn->microphone_gain >= 0)
2347 _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
2348 slconn->microphone_gain);
2350 if (slconn->speaker_gain >= 0)
2351 _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
2352 slconn->speaker_gain);
2362 INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
2363 __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
2365 /* LCOV_EXCL_STOP */
2367 static struct event at_event_callbacks[] = {
2368 { "AT+BRSF", _bt_hfp_supported_features },
2369 { "AT+CIND", _bt_hfp_report_indicators },
2370 { "AT+CMER", _bt_hfp_enable_indicators },
2371 { "AT+CHLD", _bt_hfp_call_hold },
2372 { "ATA", _bt_hfp_answer_call },
2373 { "ATD", _bt_hfp_dial_number },
2374 { "AT+VG", _bt_hfp_signal_gain_setting },
2375 { "AT+CHUP", _bt_hfp_terminate_call },
2376 { "AT+CKPD", _bt_hfp_key_press },
2377 { "AT+CLIP", _bt_hfp_cli_notification },
2378 { "AT+BTRH", _bt_hfp_response_and_hold },
2379 { "AT+BLDN", _bt_hfp_last_dialed_number },
2380 { "AT+VTS", _bt_hfp_dtmf_tone },
2381 { "AT+CNUM", _bt_hfp_subscriber_number },
2382 { "AT+CLCC", _bt_hfp_list_current_calls },
2383 { "AT+CMEE", _bt_hfp_extended_errors },
2384 { "AT+CCWA", _bt_hfp_call_waiting_notify },
2385 { "AT+COPS", _bt_hfp_operator_selection },
2386 { "AT+NREC", _bt_hfp_nr_and_ec },
2387 { "AT+BVRA", _bt_hfp_voice_dial },
2388 { "AT+XAPL", _bt_hfp_apl_command },
2389 { "AT+IPHONEACCEV", _bt_hfp_apl_command },
2390 { "AT+BIA", _bt_hfp_indicators_activation },
2391 { "AT+CPBS", _bt_hfp_select_pb_memory },
2392 { "AT+CPBR", _bt_hfp_read_pb_entries},
2393 { "AT+CPBF", _bt_hfp_find_pb_entires },
2394 { "AT+CSCS", _bt_hfp_select_character_set },
2395 { "AT+CSQ", _bt_hfp_get_signal_quality },
2396 { "AT+CBC", _bt_hfp_get_battery_charge_status },
2397 { "AT+CPAS", _bt_hfp_get_activity_status },
2398 { "AT+CGSN", _bt_hfp_get_equipment_identity },
2399 { "AT+CGMM", _bt_hfp_get_model_information },
2400 { "AT+CGMI", _bt_hfp_get_device_manufacturer },
2401 { "AT+CGMR", _bt_hfp_get_revision_information },
2402 { "AT+BAC", __bt_hfp_available_codecs },
2403 { "AT+BCC", __bt_hfp_codec_connection },
2404 { "AT+BCS", __bt_hfp_codec_selection },
2405 { "AT+XSAT", _bt_hfp_vendor_cmd },
2406 { "AT+CIMI", _bt_hfp_get_imsi },
2407 { "AT+CREG", _bt_hfp_get_creg_status },
2411 int num_of_secure_command = 4;
2412 static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
2414 /* LCOV_EXCL_START */
2415 static void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
2419 char s[MAX_BUFFER_SIZE] = {0, };
2420 gboolean hide = FALSE;
2422 gboolean is_security_command = FALSE;
2425 strncpy(s, buf, MAX_BUFFER_SIZE - 1);
2427 for (i = 0; i < num_of_secure_command; i++) {
2428 if (strstr(buf, secure_command[i])) {
2429 is_security_command = TRUE;
2434 /* +XSAT: 11,DISC */
2435 xsat_ptr = strstr(s, "11,DISC,");
2437 xsat_ptr = xsat_ptr + 8;
2439 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2445 /* AT+XSAT=11,Q_CT,X,XXXX */
2446 xsat_ptr = strstr(s, "11,Q_CT,");
2448 xsat_ptr = xsat_ptr + 8;
2450 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2451 if (x > 1) /* ignore 0 and 1 position */
2458 while (s[i] != '\0') {
2459 if (s[i] == '\r' || s[i] == '\n') {
2463 hide = hide ? FALSE : TRUE;
2464 else if (is_security_command && hide) {
2472 INFO("%s Buffer = [%s], Len(%zd)", message, s, strlen(s));
2477 static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
2481 __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
2483 for (ev = at_event_callbacks; ev->cmd; ev++) {
2484 if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
2485 return ev->callback(hs, buf);
2490 /* LCOV_EXCL_STOP */
2492 static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
2495 ssize_t final_written, count;
2496 char rsp_buffer[MAX_BUFFER_SIZE];
2500 count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
2502 ERR("count is %zd", count);
2506 if (!hdset->io_chan) {
2507 ERR("__bt_ag_send_at_valist: headset not connected");
2513 fd = g_io_channel_unix_get_fd(hdset->io_chan);
2516 while (final_written < count) {
2520 written = write(fd, rsp_buffer + final_written,
2521 count - final_written);
2522 } while (written < 0 && errno == EINTR);
2526 ERR("write failed : %s (%d)", strerror(-err), -err);
2530 final_written += written;
2533 /* Synchronize the sending buffer */
2537 ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
2541 __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
2546 int __attribute__((format(printf, 2, 3)))
2547 _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
2552 va_start(ap, format);
2553 ret = __bt_ag_send_at_valist(hs, ap, format);
2559 void __attribute__((format(printf, 3, 4)))
2560 _bt_ag_send_foreach_headset(GSList *devices,
2561 int (*cmp) (bt_ag_info_t *hs),
2567 for (l = devices; l != NULL; l = l->next) {
2568 bt_ag_info_t *hs = l->data;
2571 if (cmp && cmp(hs) != 0)
2574 va_start(ap, format);
2575 ret = __bt_ag_send_at_valist(hs, ap, format);
2577 ERR("Failed to send to headset: %s (%d)",
2578 strerror(-ret), -ret);
2583 int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
2585 if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
2586 return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
2589 case HFP_STATE_MNGR_ERR_NONE:
2590 return _bt_ag_send_at(hs, "\r\nOK\r\n");
2591 case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
2592 return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
2594 return _bt_ag_send_at(hs, "\r\nERROR\r\n");
2598 /* LCOV_EXCL_START */
2599 static gboolean __bt_ag_event_handler(GIOChannel *channel,
2600 GIOCondition cond, void *user_data)
2602 bt_ag_slconn_t *slconn;
2603 unsigned char event_buf[MAX_BUFFER_SIZE];
2605 size_t available_buffer;
2607 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2611 if (cond & G_IO_NVAL)
2614 slconn = bt_ag_info->slc;
2615 if (cond & (G_IO_ERR | G_IO_HUP)) {
2616 if (bt_ag_info->watch_id)
2617 __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
2619 ERR("ERR or HUP on RFCOMM socket");
2620 INFO_C("Disconnected [AG role] [Terminated by remote dev]");
2624 fd = g_io_channel_unix_get_fd(channel);
2625 len = read(fd, event_buf, sizeof(event_buf) - 1);
2629 available_buffer = sizeof(slconn->buffer) - (slconn->start) -
2630 (slconn->length) - 1;
2631 if (available_buffer < (size_t) len) {
2632 ERR("Buffer over flow");
2636 memcpy(&slconn->buffer[slconn->start + slconn->length], event_buf, len);
2637 slconn->length += len;
2639 slconn->buffer[slconn->start + slconn->length] = '\0';
2641 while (slconn->length > 0) {
2646 get_cr = strchr(&slconn->buffer[slconn->start], '\r');
2648 ERR("Broken AT command received, break");
2652 cmd_len = 1 + (off_t)(intptr_t)get_cr -
2653 (off_t)(intptr_t)&slconn->buffer[slconn->start];
2657 DBG("Call AT handler");
2658 err = __bt_ag_at_handler(bt_ag_info,
2659 &slconn->buffer[slconn->start]);
2661 ERR("Failed to call AT handler");
2668 err_return = HFP_STATE_MNGR_ERR_NOT_SUPPORTED;
2671 err_return = HFP_STATE_MNGR_ERR_NOT_ALLOWED;
2674 err_return = HFP_STATE_MNGR_ERR_NOT_SUPPORTED;
2677 ERR("Error handling command %s: %s (%d)",
2678 &slconn->buffer[slconn->start],
2679 strerror(-err), -err);
2680 err = _bt_ag_send_response(bt_ag_info,
2686 slconn->start += cmd_len;
2687 slconn->length -= cmd_len;
2689 if (slconn->length <= 0)
2694 ERR("Failed in event handler - SLC Disconnect");
2695 _bt_ag_set_headset_state(bt_ag_info,
2696 HEADSET_STATE_DISCONNECTED);
2700 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
2701 const gchar *object_path)
2705 bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
2706 struct sockaddr_remote address;
2707 socklen_t address_len;
2709 INFO_C("Connected [AG role]");
2710 bt_ag_info->rfcomm = NULL;
2711 bt_ag_info->slc = NULL;
2712 bt_ag_info->hfp_active = TRUE;
2713 bt_ag_info->vr_blacklisted = FALSE;
2714 bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
2715 bt_ag_info->sco_server_started = FALSE;
2716 __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
2718 bt_ag_info->path = device_path;
2719 DBG("device_path = [%s]", device_path);
2721 address_len = sizeof(address);
2722 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2723 ERR("BD_ADDR is NULL");
2725 DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
2726 bt_ag_info->fd = fd;
2727 bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
2728 flags = g_io_channel_get_flags(bt_ag_info->io_chan);
2730 flags &= ~G_IO_FLAG_NONBLOCK;
2731 flags &= G_IO_FLAG_MASK;
2732 g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
2733 g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
2734 g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
2736 bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
2738 bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2739 __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
2740 address.remote_bdaddr.b);
2742 #if defined(TIZEN_SUPPORT_DUAL_HF)
2743 bt_ag_info->is_companion_device =
2744 __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
2747 DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
2749 if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
2750 DBG("HSP connection completed");
2751 _bt_ag_set_headset_state(bt_ag_info,
2752 HEADSET_STATE_CONNECTED);
2754 DBG("HFP connection connecting");
2755 _bt_ag_set_headset_state(bt_ag_info,
2756 HEADSET_STATE_CONNECTING);
2759 __bt_ag_agent_start_watch(bt_ag_info);
2761 bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
2762 bt_ag_info->slc->speaker_gain = 15;
2763 bt_ag_info->slc->microphone_gain = 15;
2764 bt_ag_info->slc->is_nrec = TRUE;
2769 static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
2778 fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
2781 ERR("Unable to open VR blacklist file");
2785 fseek(fp, 0, SEEK_END);
2788 ERR("size is not a positive number");
2795 buffer = g_malloc0(sizeof(char) * size);
2796 if (buffer == NULL) {
2797 ERR("g_malloc0 is failed");
2801 result = fread((char *)buffer, 1, size, fp);
2803 if (result != size) {
2809 token = strtok_r(buffer, "=", &saveptr);
2810 if (token == NULL) {
2815 while ((token = strtok_r(NULL, ",", &saveptr))) {
2816 if (strlen(token) > 8)
2818 if (0 == g_strcmp0(token, lap_addr)) {
2819 INFO("Voice Recognition blacklisted");
2828 static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
2830 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2831 sco_open_timer_id = 0;
2832 DBG("sco_open_request (%d)", sco_open_request);
2834 if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
2835 bt_ag_slconn_t *slconn = bt_ag_info->slc;
2837 INFO("try to open SCO");
2838 sco_open_request = FALSE;
2840 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2841 (slconn && (slconn->hs_features &
2842 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
2843 switch (bt_ag_info->codec_info.final_codec) {
2844 case BT_CVSD_CODEC_ID:
2845 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
2846 __bt_ag_sco_connect(bt_ag_info);
2848 case BT_MSBC_CODEC_ID:
2849 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
2850 __bt_ag_sco_connect(bt_ag_info);
2853 __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
2857 __bt_ag_sco_connect(bt_ag_info);
2862 /* LCOV_EXCL_STOP */
2865 * Service level connection complete
2866 * indication and state management
2868 void _bt_ag_slconn_complete(bt_ag_info_t *hs)
2870 char lap_address[BT_LOWER_ADDRESS_LENGTH];
2872 DBG("HFP Service Level Connection established\n");
2874 /* Check device Voice Recognition blacklist status */
2875 g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
2876 hs->vr_blacklisted =
2877 __bt_ag_agent_is_device_vr_blacklisted(lap_address);
2879 if (sco_open_timer_id > 0) {
2880 g_source_remove(sco_open_timer_id);
2881 sco_open_timer_id = 0;
2884 sco_open_request = FALSE;
2885 sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
2886 __bt_sco_open_delay_timeout_cb, hs);
2888 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2891 /* LCOV_EXCL_START */
2892 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
2895 g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
2896 g_io_channel_unref(hs->io_chan);
2900 __bt_ag_close_sco(hs);
2901 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2903 __bt_ag_agent_remove_watch(&hs->watch_id);
2905 _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
2909 static GQuark __bt_ag_agent_error_quark(void)
2913 static GQuark quark = 0;
2915 quark = g_quark_from_static_string("ag-agent");
2921 static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
2924 ERR("error[%d]\n", error);
2927 case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
2928 return g_error_new(BT_AG_AGENT_ERROR, error,
2929 BT_ERROR_NOT_AVAILABLE);
2930 case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
2931 return g_error_new(BT_AG_AGENT_ERROR, error,
2932 BT_ERROR_NOT_CONNECTED);
2933 case BT_HFP_AGENT_ERROR_BUSY:
2934 return g_error_new(BT_AG_AGENT_ERROR, error,
2936 case BT_HFP_AGENT_ERROR_INVALID_PARAM:
2937 return g_error_new(BT_AG_AGENT_ERROR, error,
2938 BT_ERROR_INVALID_PARAM);
2939 case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
2940 return g_error_new(BT_AG_AGENT_ERROR, error,
2941 BT_ERROR_ALREADY_EXSIST);
2942 case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
2943 return g_error_new(BT_AG_AGENT_ERROR, error,
2944 BT_ERROR_ALREADY_CONNECTED);
2945 case BT_HFP_AGENT_ERROR_NO_MEMORY:
2946 return g_error_new(BT_AG_AGENT_ERROR, error,
2947 BT_ERROR_NO_MEMORY);
2948 case BT_HFP_AGENT_ERROR_I_O_ERROR:
2949 return g_error_new(BT_AG_AGENT_ERROR, error,
2950 BT_ERROR_I_O_ERROR);
2951 case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
2952 return g_error_new(BT_AG_AGENT_ERROR, error,
2953 BT_ERROR_OPERATION_NOT_AVAILABLE);
2954 case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
2955 return g_error_new(BT_AG_AGENT_ERROR, error,
2957 case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
2958 return g_error_new(BT_AG_AGENT_ERROR, error,
2960 case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
2961 return g_error_new(BT_AG_AGENT_ERROR, error,
2962 BT_ERROR_NO_CALL_LOG);
2963 case BT_HFP_AGENT_ERROR_INTERNAL:
2965 return g_error_new(BT_AG_AGENT_ERROR, error,
2971 static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
2975 for (l = active_devices ; l; l = l->next) {
2976 bt_ag_info_t *data = l->data;
2977 if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
2979 if (g_strcmp0(data->path, device_path) == 0) {
2980 INFO("Active device found");
2985 INFO("Active device not found");
2989 static void __bt_ag_agent_method(GDBusConnection *connection,
2990 const gchar *sender,
2991 const gchar *object_path,
2992 const gchar *interface_name,
2993 const gchar *method_name,
2994 GVariant *parameters,
2995 GDBusMethodInvocation *invocation,
3000 INFO("method %s", method_name);
3001 INFO("object_path %s", object_path);
3002 int ret = BT_HFP_AGENT_ERROR_NONE;
3004 const gchar *device_path = NULL;
3006 if (g_strcmp0(method_name, "NewConnection") == 0) {
3010 GUnixFDList *fd_list;
3011 GVariant *options = NULL;
3012 int device_count = 0;
3014 device_count = g_slist_length(active_devices);
3016 INFO("device_count %d", device_count);
3018 if (device_count >= MAX_CONNECTED_DEVICES) {
3019 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3023 g_variant_get(parameters, "(oha{sv})",
3024 &device_path, &index, &options);
3026 #if defined(TIZEN_SUPPORT_DUAL_HF) && defined(TIZEN_PROFILE_WEARABLE)
3028 * Below code is not required for dual HF support for
3032 __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
3033 INFO("not allow to connect 2nd HF connection");
3034 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3038 msg = g_dbus_method_invocation_get_message(invocation);
3039 fd_list = g_dbus_message_get_unix_fd_list(msg);
3040 if (fd_list == NULL) {
3041 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3045 fd = g_unix_fd_list_get(fd_list, index, NULL);
3047 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3051 DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
3053 if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
3054 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3058 g_dbus_method_invocation_return_value(invocation, NULL);
3059 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
3062 g_variant_get(parameters, "(o)", &device_path);
3063 INFO("device_path %s", device_path);
3065 for (l = active_devices; l; l = l->next) {
3066 bt_ag_info_t *data = l->data;
3068 INFO("data->path %s", data->path);
3069 if (g_strcmp0(data->path, device_path) == 0) {
3070 if (!__bt_ag_agent_connection_release(data)) {
3071 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3074 INFO_C("Disconnected [AG role] [Terminated by local host]");
3075 g_dbus_method_invocation_return_value(invocation, NULL);
3078 } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
3080 gchar *address = NULL;
3081 g_variant_get(parameters, "(&s&s)", &path, &address);
3082 /*local_addr = malloc(strlen(address));
3083 memcpy(local_addr, address, strlen(address));*/
3085 DBG("Sender = %s, Application path = %s\n", sender, path);
3086 ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
3091 local_addr = g_strdup(address);
3092 DBG("Address = %s\n", local_addr);
3093 g_dbus_method_invocation_return_value(invocation, NULL);
3094 } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
3096 g_variant_get(parameters, "(&s)", &path);
3098 DBG("Application path = %s\n", path);
3099 DBG("Sender = %s\n", sender);
3101 ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
3105 g_dbus_method_invocation_return_value(invocation, NULL);
3106 } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
3108 gchar *number = NULL;
3111 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3113 DBG("Application path = %s", path);
3114 DBG_SECURE("Phone number = %s", number);
3115 DBG("Call id = %d", call_id);
3117 DBG("Sender = %s", sender);
3119 ret = _bt_hfp_incoming_call(path, number, call_id, sender);
3122 g_dbus_method_invocation_return_value(invocation, NULL);
3123 } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
3125 gchar *number = NULL;
3128 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3130 DBG("Application path = %s", path);
3131 DBG_SECURE("Phone number = %s", number);
3132 DBG("Call id = %d", call_id);
3134 DBG("Sender = %s", sender);
3136 ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
3139 g_dbus_method_invocation_return_value(invocation, NULL);
3140 } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
3142 gchar *number = NULL;
3147 g_variant_get(parameters, "(&s&sii)",
3148 &path, &number, &status, &call_id);
3149 DBG("Application path = %s\n", path);
3150 DBG_SECURE("Number = %s\n", number);
3151 DBG("Status = %d\n", status);
3152 DBG("Call id = %d\n", call_id);
3153 DBG("Sender = %s\n", sender);
3155 ret = _bt_hfp_change_call_status(path,
3156 number, status, call_id, sender);
3158 if (_bt_hfp_is_call_exist() == FALSE) {
3159 for (l = active_devices; l; l = l->next) {
3160 bt_ag_info_t *data = l->data;
3162 if (data->state == HEADSET_STATE_ON_CALL) {
3163 __bt_ag_close_sco(data);
3164 _bt_ag_set_headset_state(data,
3165 HEADSET_STATE_CONNECTED);
3172 g_dbus_method_invocation_return_value(invocation, NULL);
3173 } else if (g_strcmp0(method_name, "GetProperties") == 0) {
3174 GVariantBuilder *builder;
3176 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3179 gchar *codec = g_strdup("codec");
3180 gchar *nrec = g_strdup("nrec");
3182 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3184 g_variant_builder_add(builder, "{sv}",
3185 codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
3186 g_variant_builder_add(builder, "{sv}",
3187 nrec, g_variant_new("b", bt_ag_info->nrec_status));
3189 var_data = g_variant_new("(a{sv})", builder);
3190 g_variant_builder_unref(builder);
3191 g_dbus_method_invocation_return_value(invocation, var_data);
3196 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3199 } else if (g_strcmp0(method_name, "Disconnect") == 0) {
3200 char hdset_address[18] = { 0, };
3203 for (l = active_devices; l; l = l->next) {
3204 bt_ag_info_t *data = l->data;
3206 __bt_convert_addr_type_to_rev_string(hdset_address,
3207 (unsigned char *)data->remote_addr);
3209 DBG("Disconnect Headset %s, %s\n",
3210 hdset_address, data->path);
3211 _bt_ag_set_headset_state(data,
3212 HEADSET_STATE_DISCONNECTED);
3214 g_dbus_method_invocation_return_value(invocation, NULL);
3215 } else if (g_strcmp0(method_name, "IsConnected") == 0) {
3216 gboolean is_connected = FALSE;
3219 for (l = active_devices; l; l = l->next) {
3220 bt_ag_info_t *data = l->data;
3222 if (data->state == HEADSET_STATE_CONNECTED)
3223 is_connected = TRUE;
3225 DBG("is_connected : %s",
3226 is_connected ? "Connected" : "Disconnected");
3228 g_dbus_method_invocation_return_value(invocation,
3229 g_variant_new("(b)", is_connected));
3230 } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
3233 if (0 == g_slist_length(active_devices)) {
3234 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3238 if (ag.ring_timer) {
3239 DBG("IndicateCall received when already indicating");
3240 g_dbus_method_invocation_return_value(invocation, NULL);
3243 for (l = active_devices; l; l = l->next) {
3244 bt_ag_info_t *data = l->data;
3246 if (data->state >= HEADSET_STATE_CONNECTED)
3247 _bt_ag_send_at(data, "\r\nRING\r\n");
3250 __bt_ring_timer_cb(NULL);
3251 ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
3252 __bt_ring_timer_cb, NULL);
3253 g_dbus_method_invocation_return_value(invocation, NULL);
3254 } else if (g_strcmp0(method_name, "CancelCall") == 0) {
3255 if (0 == g_slist_length(active_devices)) {
3256 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3260 if (ag.ring_timer) {
3261 g_source_remove(ag.ring_timer);
3264 DBG("Got CancelCall method call but no call is active");
3266 g_dbus_method_invocation_return_value(invocation, NULL);
3267 } else if (g_strcmp0(method_name, "Play") == 0) {
3268 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3269 bt_ag_slconn_t *slconn = NULL;
3272 slconn = bt_ag_info->slc;
3274 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3278 #ifndef __TIZEN_OPEN__
3281 if (slconn && FALSE == slconn->is_voice_recognition_running &&
3282 mdm_get_service() == MDM_RESULT_SUCCESS) {
3283 mode = mdm_get_allow_bluetooth_outgoing_call();
3284 mdm_release_service();
3286 if (mode == MDM_RESTRICTED) {
3287 ERR("[MDM] Not allow the outgoing call");
3288 ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
3295 switch (bt_ag_info->state) {
3296 case HEADSET_STATE_CONNECTING:
3297 case HEADSET_STATE_DISCONNECTED:
3298 ERR("HEADSET_STATE ERROR");
3299 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3301 case HEADSET_STATE_CONNECTED:
3303 case HEADSET_STATE_PLAY_IN_PROGRESS:
3304 ERR("Play In Progress");
3305 ret = BT_HFP_AGENT_ERROR_BUSY;
3313 if (sco_open_timer_id > 0) {
3314 INFO("SCO open delay");
3315 sco_open_request = TRUE;
3316 g_dbus_method_invocation_return_value(invocation, NULL);
3320 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
3321 (slconn && (slconn->hs_features &
3322 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
3323 switch (bt_ag_info->codec_info.final_codec) {
3324 case BT_CVSD_CODEC_ID:
3325 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
3326 ret = __bt_ag_sco_connect(bt_ag_info);
3328 case BT_MSBC_CODEC_ID:
3329 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
3330 ret = __bt_ag_sco_connect(bt_ag_info);
3333 ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
3337 ret = __bt_ag_sco_connect(bt_ag_info);
3343 sco_owner = g_strdup(sender);
3345 g_dbus_method_invocation_return_value(invocation, NULL);
3347 name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
3348 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
3349 __bt_ag_name_owner_changed_cb, NULL, NULL);
3350 } else if (g_strcmp0(method_name, "Stop") == 0) {
3353 for (l = active_devices; l; l = l->next) {
3354 bt_ag_info_t *data = l->data;
3356 if (data->state > HEADSET_STATE_CONNECTED) {
3357 __bt_ag_close_sco(data);
3358 _bt_ag_set_headset_state(data,
3359 HEADSET_STATE_CONNECTED);
3363 g_dbus_method_invocation_return_value(invocation, NULL);
3364 } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
3365 gboolean is_playing = FALSE;
3368 for (l = active_devices; l; l = l->next) {
3369 bt_ag_info_t *data = l->data;
3371 if (data->state == HEADSET_STATE_ON_CALL)
3374 DBG("is_playing : %s", is_playing ? "Playing" : "Not Playing");
3376 g_dbus_method_invocation_return_value(invocation,
3377 g_variant_new("(b)", is_playing));
3378 } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
3379 bt_ag_slconn_t *slconn = NULL;
3380 guint16 gain_value = 0;
3381 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3383 if (bt_ag_info == NULL) {
3384 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3388 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3389 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3393 slconn = bt_ag_info->slc;
3395 gain_value = (guint16) slconn->speaker_gain;
3397 g_dbus_method_invocation_return_value(invocation,
3398 g_variant_new("(q)", gain_value));
3399 } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
3401 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3403 g_variant_get(parameters, "(q)", &gain);
3404 DBG("Speaker gain = %d\n", gain);
3406 if (bt_ag_info == NULL) {
3407 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3411 ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
3414 g_dbus_method_invocation_return_value(invocation, NULL);
3415 } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
3416 bt_ag_slconn_t *slconn = NULL;
3417 guint16 gain_value = 0;
3418 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3420 if (bt_ag_info == NULL) {
3421 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3425 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3426 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3430 slconn = bt_ag_info->slc;
3432 gain_value = (guint16) slconn->microphone_gain;
3434 g_dbus_method_invocation_return_value(invocation,
3435 g_variant_new("(q)", gain_value));
3436 } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
3438 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3440 g_variant_get(parameters, "(q)", &gain);
3441 DBG("Microphone gain = %d\n", gain);
3443 if (bt_ag_info == NULL) {
3444 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3448 ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
3451 g_dbus_method_invocation_return_value(invocation, NULL);
3452 } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
3453 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3454 if (bt_ag_info == NULL) {
3455 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3459 bt_ag_slconn_t *slconn = bt_ag_info->slc;
3462 g_variant_get(parameters, "(b)", &enable);
3463 DBG("VoiceDail enable = %d\n", enable);
3465 if ((slconn && !(slconn->hs_features &
3466 BT_HF_FEATURE_VOICE_RECOGNITION)))
3467 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3468 else if (bt_ag_info->vr_blacklisted)
3469 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3471 ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
3474 slconn->is_voice_recognition_running = enable;
3478 g_dbus_method_invocation_return_value(invocation, NULL);
3479 } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
3481 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3482 if (bt_ag_info == NULL) {
3483 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3487 g_variant_get(parameters, "(&s)", &cmd);
3489 ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
3493 DBG("vendor cmd = %s", cmd);
3495 ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
3498 g_dbus_method_invocation_return_value(invocation, NULL);
3499 } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
3500 DBG("Already pass dbus SMACK for bt-service::platform");
3501 /* Return success */
3502 g_dbus_method_invocation_return_value(invocation, NULL);
3503 } else if (g_strcmp0(method_name, "SwapHeadset") == 0) {
3506 char address[BT_ADDRESS_STRING_SIZE];
3507 char remote_addr[BT_ADDRESS_STRING_SIZE];
3508 gboolean device_found = FALSE;
3510 g_variant_get(parameters, "(s)", &addr);
3511 g_strlcpy(address, addr, sizeof(address));
3512 DBG("Sender = %s", sender);
3514 /* Loop through connected headset list
3515 * If found, update the remote_dev_path.
3517 for (l = active_devices ; l; l = l->next) {
3518 bt_ag_info_t *data = l->data;
3519 g_strlcpy(remote_addr, data->remote_addr, sizeof(remote_addr));
3520 if (g_strcmp0(remote_addr, address) == 0) {
3521 DBG("Active device found");
3522 if (data->path == NULL) {
3523 DBG("device path is null");
3524 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3527 remote_dev_path = g_strdup(data->path);
3528 DBG("Setting device path %s as active device path", remote_dev_path);
3529 device_found = TRUE;
3534 if (!device_found) {
3535 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3539 g_dbus_method_invocation_return_value(invocation, NULL);
3546 err = __bt_ag_agent_set_error(ret);
3547 g_dbus_method_invocation_return_gerror(invocation, err);
3552 static const GDBusInterfaceVTable method_table = {
3553 __bt_ag_agent_method,
3558 static GDBusNodeInfo *__bt_ag_create_method_node_info
3559 (const gchar *introspection_data)
3562 GDBusNodeInfo *node_info = NULL;
3564 if (introspection_data == NULL)
3567 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
3570 ERR("Unable to create node: %s", err->message);
3571 g_clear_error(&err);
3576 static GDBusConnection *__bt_ag_get_gdbus_connection(void)
3582 if (ag_dbus_conn == NULL)
3583 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
3585 if (!ag_dbus_conn) {
3587 ERR("Unable to connect to dbus: %s", err->message);
3588 g_clear_error(&err);
3594 return ag_dbus_conn;
3597 static gboolean __bt_ag_register_profile_methods(void)
3600 GError *error = NULL;
3602 GDBusNodeInfo *node_info = NULL;
3605 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
3607 G_BUS_NAME_OWNER_FLAGS_NONE,
3611 DBG("owner_id is [%d]", owner_id);
3613 node_info = __bt_ag_create_method_node_info(
3614 ag_agent_bluez_introspection_xml);
3615 if (node_info == NULL)
3618 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3619 DBG("path is [%s]", path);
3621 hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3622 node_info->interfaces[0],
3624 NULL, NULL, &error);
3625 if (hf_bluez_id == 0) {
3626 ERR("Failed to register: %s", error->message);
3627 g_error_free(error);
3629 g_dbus_node_info_unref(node_info);
3634 /* Ag register profile methods for HSP*/
3636 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
3637 DBG("path is [%s]", path);
3639 hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3640 node_info->interfaces[0],
3642 NULL, NULL, &error);
3643 if (hs_bluez_id == 0) {
3644 ERR("Failed to register: %s", error->message);
3645 g_error_free(error);
3647 g_dbus_node_info_unref(node_info);
3651 g_dbus_node_info_unref(node_info);
3653 node_info = __bt_ag_create_method_node_info
3654 (ag_agent_app_introspection_xml);
3655 if (node_info == NULL)
3658 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3659 DBG("path is [%s]", path);
3661 app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3662 node_info->interfaces[0],
3664 NULL, NULL, &error);
3666 ERR("Failed to register: %s", error->message);
3667 g_error_free(error);
3669 g_dbus_node_info_unref(node_info);
3673 g_dbus_node_info_unref(node_info);
3679 static void __bt_ag_unregister_profile_methods(void)
3683 if (hf_bluez_id > 0) {
3684 g_dbus_connection_unregister_object(ag_dbus_conn,
3689 if (hs_bluez_id > 0) {
3690 g_dbus_connection_unregister_object(ag_dbus_conn,
3696 g_dbus_connection_unregister_object(ag_dbus_conn,
3702 static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
3703 const gchar *path, const gchar *interface)
3705 return (service_gproxy) ? service_gproxy :
3706 __bt_ag_gdbus_init_service_proxy(service,
3710 static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
3711 char *profile_uuid, const char* profile_name)
3716 GError *error = NULL;
3717 GVariantBuilder *builder;
3719 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3720 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3725 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3727 g_variant_builder_add(builder, "{sv}",
3728 "Name", g_variant_new("s",
3730 g_variant_builder_add(builder, "{sv}",
3731 "Version", g_variant_new("q", profile_version));
3732 /*g_variant_builder_add(builder, "{sv}",
3733 "Role", g_variant_new("s","client"));*/
3734 if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
3735 g_variant_builder_add(builder, "{sv}",
3736 "features", g_variant_new("q", ag.sdp_features));
3739 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3740 g_variant_new("(osa{sv})", path,
3741 profile_uuid, builder),
3742 G_DBUS_CALL_FLAGS_NONE, -1,
3744 g_variant_builder_unref(builder);
3745 /* set the name and role for the profile*/
3747 /* dBUS-RPC is failed */
3748 ERR("dBUS-RPC is failed");
3750 if (error != NULL) {
3751 /* dBUS gives error cause */
3752 ERR("D-Bus API failure: errCode[%x], message[%s]",
3753 error->code, error->message);
3755 g_clear_error(&error);
3760 g_variant_unref(ret);
3767 static void __bt_ag_agent_unregister(gchar *path)
3772 GError *error = NULL;
3774 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3775 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3780 ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
3781 g_variant_new("(o)", path),
3782 G_DBUS_CALL_FLAGS_NONE, -1,
3785 /* set the name and role for the profile*/
3787 /* dBUS-RPC is failed */
3788 ERR("dBUS-RPC is failed");
3790 if (error != NULL) {
3791 /* dBUS gives error cause */
3792 ERR("D-Bus API failure: errCode[%x], message[%s]",
3793 error->code, error->message);
3795 g_clear_error(&error);
3799 g_variant_unref(ret);
3809 static void __bt_ag_agent_battery_status_cb(keynode_t *node)
3811 int batt = vconf_keynode_get_int(node);
3813 _bt_hfp_set_property_value("BatteryBarsChanged", batt);
3816 static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
3818 int signal_bar = vconf_keynode_get_int(node);
3820 BT_CHECK_SIGNAL_STRENGTH(signal_bar);
3821 _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
3824 static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
3826 gboolean status = vconf_keynode_get_bool(node);
3828 DBG("status = %d", status);
3830 if (status == TRUE) {
3831 for (l = active_devices; l; l = l->next) {
3832 bt_ag_info_t *data = l->data;
3833 _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
3838 static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
3840 int service = vconf_keynode_get_int(node);
3841 bt_hfp_agent_network_registration_status_t network_service;
3845 DBG("Current Signal Level = [%d] \n", service);
3848 case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
3849 case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
3850 case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
3858 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
3860 ERR("Get roaming status failed err = %d\n", ret);
3864 if (roam_status == 0 && service == 1)
3865 network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
3866 else if (roam_status == 1 && service == 1)
3867 network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
3869 network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
3871 _bt_hfp_set_property_value("RegistrationChanged", network_service);
3874 static void __bt_ag_agent_subscribe_vconf_updates(void)
3880 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3881 (void *)__bt_ag_agent_battery_status_cb, NULL);
3883 ERR("Subsrciption to battery status failed err = [%d]\n", ret);
3885 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
3886 (void *)__bt_ag_agent_network_signal_status_cb, NULL);
3888 ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
3890 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3891 (void *)__bt_ag_agent_network_register_status_cb, NULL);
3893 ERR("Subsrciption to network failed err = [%d]\n", ret);
3895 if (TIZEN_PROFILE_WEARABLE) {
3896 ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
3897 (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
3899 ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
3903 static void __bt_ag_agent_release_vconf_updates(void)
3909 ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3910 (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
3912 ERR("vconf_ignore_key_changed failed\n");
3914 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
3915 (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
3917 ERR("vconf_ignore_key_changed failed\n");
3919 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3920 (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
3922 ERR("vconf_ignore_key_changed failed\n");
3925 static gboolean __bt_ag_agent_send_subscriber_number_changed(
3928 const char *property = g_strdup("SubscriberNumberChanged");
3932 DBG("Number is %s", number);
3934 if (!_bt_hfp_set_property_name(property, number)) {
3935 DBG("Error- set property for subscriber no change - ERROR\n");
3936 g_free((void *)property);
3939 g_free((void *)property);
3943 static void __bt_ag_agent_sigterm_handler(int signo)
3948 ERR_C("***** Signal handler came with signal %d *****", signo);
3950 for (l = active_devices ; l; l = l->next) {
3951 bt_ag_info_t *data = l->data;
3952 if (!__bt_ag_agent_connection_release(data))
3953 ERR("__bt_ag_agent_connection_release failed");
3956 g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
3959 g_main_loop_quit(gmain_loop);
3963 INFO("Terminating AG agent");
3967 if (signo == SIGTERM)
3970 for (i = 0; i < BT_AG_SIG_NUM; i++)
3971 sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
3976 static void __bt_ag_agent_tel_cb(TapiHandle *handle,
3981 TelSimMsisdnList_t *number;
3982 gchar *subscriber_number;
3984 ERR("*********** result = %d", result);
3986 if (result == TAPI_API_SIM_LOCKED ||
3987 result == TAPI_API_SIM_NOT_INITIALIZED ||
3988 result == TAPI_API_SERVICE_NOT_READY) {
3989 DBG("initializing the tapi event for SIM status");
3990 __bt_ag_agent_reg_sim_event(handle, user_data);
3997 number = (TelSimMsisdnList_t *)data;
3998 subscriber_number = g_strdup(number->list[0].num);
3999 __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
4000 g_free(subscriber_number);
4003 static void __bt_ag_agent_on_noti_sim_status(TapiHandle *handle,
4004 const char *noti_id, void *data, void *user_data)
4006 TelSimCardStatus_t *status = data;
4009 DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
4011 if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
4012 __bt_ag_agent_dereg_sim_event(handle);
4013 tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
4015 if (tapi_result != TAPI_API_SUCCESS)
4016 ERR("Fail to get sim info: %d", tapi_result);
4020 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data)
4023 ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
4024 __bt_ag_agent_on_noti_sim_status, user_data);
4026 if (ret != TAPI_API_SUCCESS)
4027 ERR("event register failed(%d)", ret);
4030 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle)
4033 ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
4035 if (ret != TAPI_API_SUCCESS)
4036 ERR("event deregister failed(%d)", ret);
4039 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
4040 const gchar *sender_name,
4041 const gchar *object_path,
4042 const gchar *interface_name,
4043 const gchar *signal_name,
4044 GVariant *parameters,
4048 char *name_owner = NULL;
4049 char *old_owner = NULL;
4050 char *new_owner = NULL;
4052 if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
4055 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
4057 _bt_hfp_release_all_calls_by_sender(name_owner);
4059 if (sco_owner == NULL)
4062 if (strcasecmp(name_owner, sco_owner) == 0) {
4063 if (name_owner_sig_id != -1)
4064 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4066 name_owner_sig_id = -1;
4070 for (l = active_devices ; l; l = l->next) {
4071 bt_ag_info_t *data = l->data;
4074 __bt_ag_close_sco(data);
4075 _bt_ag_set_headset_state(data,
4076 HEADSET_STATE_CONNECTED);
4083 static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
4084 const gchar *sender_name,
4085 const gchar *object_path,
4086 const gchar *interface_name,
4087 const gchar *signal_name,
4088 GVariant *parameters,
4093 GVariant *optional_param = NULL;
4095 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
4096 g_variant_get(parameters, "(&o@a{sa{sv}})", &path, &optional_param);
4099 g_variant_unref(optional_param);
4100 ERR("Invalid adapter path");
4104 INFO("Adapter Path = [%s]", path);
4105 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4106 gchar *obj_path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4107 __bt_ag_agent_register(obj_path, hfp_ver,
4108 HFP_AG_UUID, "Hands-Free Audio Gateway");
4110 obj_path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4111 __bt_ag_agent_register(obj_path, hsp_ver,
4112 HSP_AG_UUID, "Headset Audio Gateway");
4114 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
4115 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
4118 g_variant_unref(optional_param);
4119 ERR("Invalid adapter path");
4123 INFO("Adapter Path = [%s]", path);
4124 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4125 gchar *obj_path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4126 __bt_ag_agent_unregister(obj_path);
4128 obj_path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4129 __bt_ag_agent_unregister(obj_path);
4134 g_variant_unref(optional_param);
4139 static void __bt_ag_agent_dbus_deinit(void)
4142 if (service_gproxy) {
4143 g_object_unref(service_gproxy);
4144 service_gproxy = NULL;
4148 g_object_unref(app_gproxy);
4153 __bt_ag_unregister_profile_methods();
4155 if (interface_added_sig_id)
4156 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4157 interface_added_sig_id);
4159 if (interface_removed_sig_id)
4160 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4161 interface_removed_sig_id);
4163 if (name_owner_sig_id)
4164 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4166 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4168 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4172 if (media_state_sig_id)
4173 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4174 media_state_sig_id);
4175 media_state_sig_id = 0;
4178 interface_added_sig_id = 0;
4179 interface_removed_sig_id = 0;
4180 name_owner_sig_id = 0;
4184 g_object_unref(ag_dbus_conn);
4185 ag_dbus_conn = NULL;
4190 static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
4193 GDBusProxy *manager_proxy = NULL;
4194 GVariant *result = NULL;
4195 char *adapter_path = NULL;
4198 return BT_HFP_AGENT_ERROR_INTERNAL;
4200 manager_proxy = g_dbus_proxy_new_sync(conn,
4201 G_DBUS_PROXY_FLAGS_NONE, NULL,
4204 BT_MANAGER_INTERFACE,
4207 if (!manager_proxy) {
4208 ERR("Unable to create proxy: %s", err->message);
4212 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
4213 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
4216 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
4218 ERR("Fail to get DefaultAdapter");
4223 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
4224 ERR("Incorrect result\n");
4228 g_variant_get(result, "(&o)", &adapter_path);
4230 if (adapter_path == NULL ||
4231 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
4232 ERR("Adapter path is inproper\n");
4237 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
4239 g_variant_unref(result);
4240 g_object_unref(manager_proxy);
4245 g_clear_error(&err);
4248 g_variant_unref(result);
4251 g_object_unref(manager_proxy);
4253 return BT_HFP_AGENT_ERROR_INTERNAL;
4256 /* LCOV_EXCL_STOP */
4258 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4259 void _bt_ag_agent_check_transport_state(void)
4263 if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
4267 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
4268 G_DBUS_PROXY_FLAGS_NONE, NULL,
4269 "org.pulseaudio.Server", A2DP_SOURCE_ENDPOINT,
4270 BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
4274 ERR("Unable to create proxy: %s", err->message);
4275 g_clear_error(&err);
4279 INFO_C("SuspendMedia initiated");
4281 g_dbus_proxy_call(proxy,
4282 "SuspendMedia", NULL,
4283 G_DBUS_CALL_FLAGS_NONE, 2000,
4285 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4291 static void __bt_ag_agent_transport_state_update(const char *value)
4294 if (!g_strcmp0(value, "idle"))
4295 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4296 else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
4297 transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
4299 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4301 INFO_C("transport_state %d", transport_state);
4304 static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
4305 const gchar *sender_name,
4306 const gchar *object_path,
4307 const gchar *interface_name,
4308 const gchar *signal_name,
4309 GVariant *parameters,
4314 GVariant *dict_param = NULL;
4315 GVariant *optional_param = NULL;
4317 if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
4318 if (g_strcmp0(g_variant_get_type_string(parameters),
4320 ERR("Incorrect parameters\n");
4324 g_variant_get(parameters, "(&s@a{sv}@as)",
4325 &inter, &dict_param, &optional_param);
4326 if (dict_param && (!g_strcmp0(inter,
4327 BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
4328 GVariantIter *iter = NULL;
4329 const gchar *key = NULL;
4330 GVariant *value_var = NULL;
4331 gchar *value = NULL;
4332 g_variant_get(dict_param, "a{sv}", &iter);
4333 while (g_variant_iter_loop(
4334 iter, "{sv}", &key, &value_var)) {
4336 if (g_strcmp0(key, "State") == 0) {
4337 value = (gchar *)g_variant_get_string(
4340 DBG("value %s", value);
4341 __bt_ag_agent_transport_state_update(value);
4345 g_variant_iter_free(iter);
4347 } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
4348 char *profile_uuid = NULL;
4351 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
4352 if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
4353 (state == BT_PROFILE_STATE_DISCONNECTED)) {
4354 DBG("Updating the transport state");
4355 __bt_ag_agent_transport_state_update("Disconnect");
4360 g_variant_unref(dict_param);
4363 g_variant_unref(optional_param);
4369 /* LCOV_EXCL_START */
4370 static void __bt_ag_agent_dbus_init(void)
4374 if (__bt_ag_get_gdbus_connection() == NULL) {
4375 ERR("Error in creating the gdbus connection\n");
4378 if (!__bt_ag_register_profile_methods()) {
4379 ERR("Error in HFP / HSP register_profile_methods\n");
4383 if (!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
4385 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4386 __bt_ag_agent_register(path, hfp_ver,
4387 HFP_AG_UUID, "Hands-Free Audio Gateway");
4389 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4390 __bt_ag_agent_register(path, hsp_ver,
4391 HSP_AG_UUID, "Headset Audio Gateway");
4394 interface_added_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4395 NULL, BT_MANAGER_INTERFACE,
4396 BT_INTERFACES_ADDED, NULL, NULL, 0,
4397 __bt_ag_agent_filter_cb, NULL, NULL);
4399 interface_removed_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4400 NULL, BT_MANAGER_INTERFACE,
4401 BT_INTERFACES_REMOVED, NULL, NULL, 0,
4402 __bt_ag_agent_filter_cb, NULL, NULL);
4404 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4405 media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4406 NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
4407 NULL, 0, __bt_ag_agent_media_filter_cb,
4410 media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4411 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
4412 NULL, 0, __bt_ag_agent_media_filter_cb,
4415 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4420 /* LCOV_EXCL_STOP */
4422 static uint32_t __bt_ag_agent_get_ag_features(void)
4425 uint32_t ag_features;
4427 if (TIZEN_MODEL_NAME_TM1) {
4428 ag_features = BT_AG_FEATURE_EC_AND_NR |
4429 BT_AG_FEATURE_REJECT_CALL |
4430 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4431 BT_AG_FEATURE_THREE_WAY_CALL |
4432 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4434 ag_features = BT_AG_FEATURE_EC_AND_NR |
4435 BT_AG_FEATURE_REJECT_CALL |
4436 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4437 BT_AG_FEATURE_THREE_WAY_CALL |
4438 BT_AG_FEATURE_VOICE_RECOGNITION |
4439 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4443 #if defined(TIZEN_FEATURE_BT_HFP_AG)
4444 hfp_ver = HFP_VERSION_1_7;
4446 hfp_ver = HFP_VERSION_1_5;
4448 hsp_ver = HSP_VERSION_1_2;
4450 if (hfp_ver > HFP_VERSION_1_5)
4451 ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
4452 if (hfp_ver == HFP_VERSION_1_7)
4453 ag_features |= BT_AG_FEATURE_ESCO_S4_T2_SUPPORT;
4458 /* LCOV_EXCL_START */
4459 void *__bt_ag_agent_telephony_init(void *arg)
4463 uint32_t ag_features = *((uint32_t *)arg);
4465 INFO_C("Initializing the telephony info");
4467 _bt_hfp_initialize_telephony_manager(ag_features);
4468 __bt_ag_agent_subscribe_vconf_updates();
4470 tapi_handle = tel_init(NULL);
4471 tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
4473 if (tapi_result != TAPI_API_SUCCESS)
4474 ERR("Fail to get sim info: %d", tapi_result);
4481 uint32_t ag_features;
4482 struct sigaction sa;
4483 pthread_t thread_id = 0;
4485 INFO_C("### Starting Bluetooth AG agent");
4487 ag_features = __bt_ag_agent_get_ag_features();
4489 ag.sdp_features = (uint16_t) ag_features & 0x1F;
4491 if (hfp_ver >= HFP_VERSION_1_6 && wbs_en == TRUE)
4492 ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
4494 memset(&sa, 0, sizeof(sa));
4495 sa.sa_flags = SA_NOCLDSTOP;
4496 sa.sa_handler = __bt_ag_agent_sigterm_handler;
4498 for (i = 0; i < BT_AG_SIG_NUM; i++)
4499 sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
4501 gmain_loop = g_main_loop_new(NULL, FALSE);
4503 if (gmain_loop == NULL) {
4504 ERR("GMainLoop create failed");
4505 return EXIT_FAILURE;
4508 __bt_ag_agent_dbus_init();
4509 if (pthread_create(&thread_id, NULL,
4510 (void *)&__bt_ag_agent_telephony_init,
4511 &ag_features) < 0) {
4512 ERR("pthread_create() is failed");
4513 return EXIT_FAILURE;
4516 if (pthread_detach(thread_id) < 0)
4517 ERR("pthread_detach() is failed");
4519 g_main_loop_run(gmain_loop);
4523 tel_deinit(tapi_handle);
4525 __bt_ag_agent_dbus_deinit();
4526 _bt_hfp_deinitialize_telephony_manager();
4527 __bt_ag_agent_release_vconf_updates();
4529 if (remote_dev_path)
4530 g_free(remote_dev_path);
4533 g_main_loop_unref(gmain_loop);
4535 INFO_C("### Terminating Bluetooth AG agent");
4538 /* LCOV_EXCL_STOP */