4 * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Chethan T N <chethan.tn@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
9 * Rakesh MK <rakesh.mk@samsung.com>
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
28 #include <gio/gunixfdlist.h>
29 #include <bundle_internal.h>
30 #include "bluetooth-ag-agent.h"
31 #include "bluetooth-ag-handler.h"
33 #include <TapiUtility.h>
35 #include <ITapiModem.h>
36 #include <TelNetwork.h>
39 #include <system_info.h>
44 static GMainLoop *gmain_loop = NULL;
45 static GDBusProxy *service_gproxy;
46 static int owner_sig_id = -1;
47 static int name_owner_sig_id = -1;
48 GDBusConnection *ag_dbus_conn = NULL;
49 gchar *remote_dev_path = NULL;
53 static TapiHandle *tapi_handle;
54 extern wbs_options wbs_opts;
55 GSList *active_devices = NULL;
56 static gchar *local_addr = NULL;
57 static GDBusProxy *app_gproxy;
58 static gboolean call_launch_requested = FALSE;
59 static gchar* sco_owner = NULL;
60 static guint sco_open_timer_id = 0;
61 static gboolean sco_open_request = FALSE;
62 static guint hf_bluez_id;
63 static guint hs_bluez_id;
65 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
66 static int media_sig_id = -1;
67 static int media_state_sig_id = -1;
68 static bt_ag_media_transport_state_t transport_state;
71 #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
72 #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
73 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
74 #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
76 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
78 #ifdef TIZEN_FEATURE_BT_LUNAR_DEVICE
79 #define VCONF_KEY_BT_LUNAR_ENABLED "db/wms/bt_loop_device_hfp_connected"
82 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
83 #define CALL_APP_ID "org.tizen.call-ui"
86 #if defined(TIZEN_SUPPORT_DUAL_HF)
87 #define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac"
88 #define MAX_CONNECTED_DEVICES 2
90 #define MAX_CONNECTED_DEVICES 1
93 #define BT_AG_SIG_NUM 3
94 static struct sigaction bt_ag_sigoldact[BT_AG_SIG_NUM];
95 static int bt_ag_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
97 /*Below Inrospection data is exposed to bluez from agent*/
98 static const gchar ag_agent_bluez_introspection_xml[] =
100 " <interface name='org.bluez.Profile1'>"
101 " <method name='NewConnection'>"
102 " <arg type='o' name='device' direction='in'/>"
103 " <arg type='h' name='fd' direction='in'/>"
104 " <arg type='a{sv}' name='options' direction='in'/>"
106 " <method name='RequestDisconnection'>"
107 " <arg type='o' name='device' direction='in'/>"
112 /*Below Introspection data is exposed to application from agent*/
113 static const gchar ag_agent_app_introspection_xml[] =
115 " <interface name='Org.Hfp.App.Interface'>"
116 " <method name='RegisterApplication'>"
117 " <arg type='s' name='path' direction='in'/>"
118 " <arg type='s' name='address' direction='in'/>"
120 " <method name='UnregisterApplication'>"
121 " <arg type='s' name='path' direction='in'/>"
123 " <method name='IncomingCall'>"
124 " <arg type='s' name='path' direction='in'/>"
125 " <arg type='s' name='number' direction='in'/>"
126 " <arg type='i' name='id' direction='in'/>"
128 " <method name='OutgoingCall'>"
129 " <arg type='s' name='path' direction='in'/>"
130 " <arg type='s' name='number' direction='in'/>"
131 " <arg type='i' name='id' direction='in'/>"
133 " <method name='ChangeCallStatus'>"
134 " <arg type='s' name='path' direction='in'/>"
135 " <arg type='s' name='number' direction='in'/>"
136 " <arg type='i' name='status' direction='in'/>"
137 " <arg type='i' name='id' direction='in'/>"
139 " <method name='GetProperties'>"
140 " <arg type='a{sv}' name='properties' direction='out'/>"
142 " <method name='Disconnect'>"
144 " <method name='IsConnected'>"
145 " <arg type='b' name='connected' direction='out'/>"
147 " <method name='IndicateCall'>"
149 " <method name='CancelCall'>"
151 " <method name='Play'>"
153 " <method name='Stop'>"
155 " <method name='IsPlaying'>"
156 " <arg type='b' name='playing' direction='out'/>"
158 " <method name='GetSpeakerGain'>"
159 " <arg type='q' name='gain' direction='out'/>"
161 " <method name='GetMicrophoneGain'>"
162 " <arg type='q' name='gain' direction='out'/>"
164 " <method name='SetSpeakerGain'>"
165 " <arg type='q' name='gain' direction='in'/>"
167 " <method name='SetMicrophoneGain'>"
168 " <arg type='q' name='gain' direction='in'/>"
170 " <method name='SetVoiceDial'>"
171 " <arg type='b' name='enable' direction='in'/>"
173 " <method name='CheckPrivilege'>"
180 int (*callback)(bt_ag_info_t *hs, const char *buf);
183 struct sco_socket_addr {
184 sa_family_t sco_family;
193 bt_ag_info_t *bt_ag_info;
197 bt_ag_status_t ag = {
198 .telephony_ready = FALSE,
202 .rh = BT_RSP_HOLD_NOT_SUPPORTED,
208 static void __bt_ag_agent_sigterm_handler(int signo);
209 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
210 const gchar *object_path);
211 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs);
212 static gboolean __bt_ag_event_handler(GIOChannel *channel, GIOCondition cond,
214 static int __bt_ag_sco_connect(bt_ag_info_t *hs);
215 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state);
216 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data);
217 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle);
218 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
219 const gchar *sender_name,
220 const gchar *object_path,
221 const gchar *interface_name,
222 const gchar *signal_name,
223 GVariant *parameters,
226 static void __bt_convert_addr_type_to_rev_string(char *address,
229 ret_if(address == NULL);
230 ret_if(addr == NULL);
232 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
233 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
234 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
237 static GDBusProxy *__bt_ag_gdbus_init_service_proxy(const gchar *service,
238 const gchar *path, const gchar *interface)
245 if (ag_dbus_conn == NULL)
246 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
250 ERR("Unable to connect to gdbus: %s", err->message);
256 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
257 G_DBUS_PROXY_FLAGS_NONE, NULL,
259 interface, NULL, &err);
263 ERR("Unable to create proxy: %s", err->message);
273 static GDBusProxy *__bt_ag_gdbus_get_app_proxy(const gchar *service,
274 const gchar *path, const gchar *interface)
276 return (app_gproxy) ? app_gproxy :
277 __bt_ag_gdbus_init_service_proxy(service,
281 static int __bt_ag_agent_gdbus_method_send(const char *service,
282 const gchar *path, const char *interface,
283 const char *method, gboolean response,
284 GVariant *parameters)
290 GError *error = NULL;
292 proxy = __bt_ag_gdbus_get_app_proxy(service, path, interface);
294 return BT_HFP_AGENT_ERROR_INTERNAL;
297 ret = g_dbus_proxy_call_sync(proxy,
299 G_DBUS_CALL_FLAGS_NONE, -1,
302 /* dBUS-RPC is failed */
303 ERR("dBUS-RPC is failed");
305 /* dBUS gives error cause */
306 ERR("D-Bus API failure: errCode[%x], message[%s]",
307 error->code, error->message);
309 g_clear_error(&error);
311 return BT_HFP_AGENT_ERROR_INTERNAL;
314 g_variant_unref(ret);
316 g_dbus_proxy_call(proxy,
318 G_DBUS_CALL_FLAGS_NONE, 2000,
321 return BT_HFP_AGENT_ERROR_NONE;
324 gboolean _bt_ag_agent_emit_signal(
325 GDBusConnection *connection,
327 const char *interface,
333 GError *error = NULL;
335 ret = g_dbus_connection_emit_signal(connection,
336 NULL, path, interface,
341 /* dBUS gives error cause */
342 ERR("D-Bus API failure: errCode[%x], message[%s]",
343 error->code, error->message);
344 g_clear_error(&error);
347 INFO_C("Emit Signal done = [%s]", name);
353 gboolean _bt_ag_agent_emit_property_changed(
354 GDBusConnection *connection,
356 const char *interface,
365 var_data = g_variant_new("(sv)", name, property);
367 ret = _bt_ag_agent_emit_signal(connection,
369 "PropertyChanged", var_data);
374 static void __bt_ag_agent_start_watch(bt_ag_info_t *bt_ag_info)
376 bt_ag_info->watch_id = g_io_add_watch(bt_ag_info->io_chan,
377 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
378 (GIOFunc) __bt_ag_event_handler, bt_ag_info);
381 static void __bt_ag_agent_remove_watch(guint *watch_id)
383 DBG("Remove IO watch ID %d", *watch_id);
385 g_source_remove(*watch_id);
390 #if defined(TIZEN_SUPPORT_DUAL_HF)
391 gboolean __bt_ag_agent_is_companion_device(const char *addr)
393 #if defined(TIZEN_PROFILE_WEARABLE)
394 char *host_device_address = NULL;
395 host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR);
397 if (!host_device_address) {
398 INFO("Failed to get a companion device address");
402 if (g_strcmp0(host_device_address, addr) == 0) {
403 INFO("addr[%s] is companion device", addr);
409 /* TODO : Need to add companion device check condition for Phone models */
414 void __bt_convert_device_path_to_address(const gchar *device_path,
415 char *device_address)
417 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
420 ret_if(device_path == NULL);
421 ret_if(device_address == NULL);
423 dev_addr = strstr(device_path, "dev_");
424 if (dev_addr != NULL) {
427 g_strlcpy(address, dev_addr, sizeof(address));
429 while ((pos = strchr(address, '_')) != NULL)
432 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
436 static gboolean __bt_ag_agent_is_companion_device_connected(void)
440 for (l = active_devices ; l; l = l->next) {
441 bt_ag_info_t *data = l->data;
443 if (data->is_companion_device) {
444 DBG("Companion device found");
452 gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
454 char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
455 gboolean is_companion_device;
457 __bt_convert_device_path_to_address(device_path, device_address);
458 is_companion_device = __bt_ag_agent_is_companion_device(device_address);
460 DBG(" device_address[%s]", device_address);
461 DBG(" is_companion_device[%d]", is_companion_device);
463 if (__bt_ag_agent_is_companion_device_connected()) {
464 if (is_companion_device)
467 if (!is_companion_device)
473 #endif /* TIZEN_SUPPORT_DUAL_HF */
475 static gboolean __bt_is_phone_locked(int *phone_lock_state)
480 if (NULL == phone_lock_state)
483 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, phone_lock_state);
485 ERR("Failed to read [%s]\n", VCONFKEY_IDLE_LOCK_STATE);
493 static gboolean __bt_get_outgoing_callapp_type(int *callapp_type)
497 if (NULL == callapp_type)
500 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
501 *callapp_type = BT_VOICE_CALL;
508 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT,
511 ERR("Failed to read [%s]\n",
512 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT);
516 INFO(" [%s] = [%d]\n",
517 VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT, *callapp_type);
519 /* The vconf value does not include in platform. */
520 *callapp_type = BT_VOICE_CALL;
526 static gboolean __bt_get_outgoing_call_condition(int *condition)
530 if (NULL == condition)
533 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
534 *condition = BT_MO_ONLY_UNLOCKED;
541 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT,
544 ERR("Failed to read [%s]\n",
545 VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT);
549 /* The vconf value does not include in platform. */
550 *condition = BT_MO_ONLY_UNLOCKED;
556 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_TELEPHONY_ENABLED)
557 static gboolean __bt_ag_agent_launch_call_app(const char *number)
562 DBG_SECURE("number(%s)", number);
566 ERR("bundle_create() Failed");
570 bundle_add(b, "launch-type", "MO");
571 bundle_add(b, "dial-type", "HEADSET");
573 if (strlen(number) != 0)
574 bundle_add(b, "number", number);
576 aul_launch_app_async(CALL_APP_ID, b);
584 static void *__bt_ag_agent_launch_call_req(void *arg)
587 bundle *b = (bundle *)arg;
588 if (appsvc_run_service(b, 0, NULL, NULL) < 0)
589 ERR("Unable to run app svc");
591 call_launch_requested = FALSE;
596 static gboolean __bt_ag_agent_make_call(const char *number)
600 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
602 return __bt_ag_agent_launch_call_app(number);
604 char telnum[BT_MAX_TEL_NUM_STRING];
608 if (call_launch_requested == TRUE) {
609 DBG("Launch request is in progress");
617 appsvc_set_operation(b, APPSVC_OPERATION_CALL);
618 snprintf(telnum, sizeof(telnum), "tel:%s", number);
619 appsvc_set_uri(b, telnum);
620 appsvc_add_data(b, "ctindex", "-1");
622 call_launch_requested = TRUE;
623 if (pthread_create(&thread_id, NULL,
624 (void *)&__bt_ag_agent_launch_call_req,
626 ERR("pthread_create() is failed");
627 call_launch_requested = FALSE;
630 if (pthread_detach(thread_id) < 0)
631 ERR("pthread_detach() is failed");
638 static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
643 kb = bundle_create();
647 bundle_add(kb, "KEY_CALL_TYPE", "MO");
648 bundle_add(kb, "number", mo_number);
649 aul_launch_app("org.tizen.vtmain", kb);
656 gboolean _bt_ag_agent_answer_call(unsigned int call_id,
657 const gchar *path, const gchar *sender)
661 if (path == NULL || sender == NULL) {
662 DBG("Invalid Arguments");
666 DBG("Application path = %s", path);
667 DBG("Call Id = %d", call_id);
668 DBG("Sender = %s", sender);
670 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
671 BT_AG_SERVICE_NAME, "Answer",
672 g_variant_new("(u)", call_id));
677 gboolean _bt_ag_agent_reject_call(unsigned int call_id,
678 const gchar *path, const gchar *sender)
682 if (path == NULL || sender == NULL) {
683 DBG("Invalid Arguments");
687 DBG("Application path = %s", path);
688 DBG("Call Id = %d", call_id);
689 DBG("Sender = %s", sender);
691 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
692 BT_AG_SERVICE_NAME, "Reject",
693 g_variant_new("(u)", call_id));
698 gboolean _bt_ag_agent_release_call(unsigned int call_id,
699 const gchar *path, const gchar *sender)
703 if (path == NULL || sender == NULL) {
704 DBG("Invalid Arguments");
708 DBG("Application path = %s", path);
709 DBG("Call Id = %d", call_id);
710 DBG("Sender = %s", sender);
712 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
713 BT_AG_SERVICE_NAME, "Release",
714 g_variant_new("(u)", call_id));
720 bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
722 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
724 int phone_lock_state;
729 if (number == NULL) {
730 ERR("Invalid Argument");
731 error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
735 DBG("Number = %s", number);
736 DBG("flags = %d", flags);
738 if (!__bt_is_phone_locked(&phone_lock_state)) {
739 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
743 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
744 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
748 if (!__bt_get_outgoing_call_condition(&condition)) {
749 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
753 if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
754 VCONFKEY_IDLE_LOCK) {
755 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
759 if (callapp_type == BT_VIDEO_CALL) {
760 if (!__bt_ag_agent_make_video_call(number)) {
761 ERR("Problem launching application");
762 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
766 if (!__bt_ag_agent_make_call(number)) {
767 ERR("Problem launching application");
768 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
778 bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
780 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
782 contacts_filter_h filter = NULL;
783 contacts_query_h query = NULL;
784 contacts_list_h list = NULL;
785 contacts_record_h record = NULL;
786 unsigned int projections[] = {
787 _contacts_speeddial.number,
792 DBG("location = %d", location);
794 /*Get number from contacts location*/
795 if (contacts_connect() != CONTACTS_ERROR_NONE) {
796 ERR(" contacts_connect failed");
797 return BT_HFP_AGENT_ERROR_INTERNAL;
800 contacts_filter_create(_contacts_speeddial._uri, &filter);
805 if (contacts_filter_add_int(filter,
806 _contacts_speeddial.speeddial_number,
807 CONTACTS_MATCH_EQUAL, location) !=
808 CONTACTS_ERROR_NONE) {
809 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
813 contacts_query_create(_contacts_speeddial._uri, &query);
818 contacts_query_set_filter(query, filter);
820 if (contacts_query_set_projection(query, projections,
821 sizeof(projections)/sizeof(unsigned int)) !=
822 CONTACTS_ERROR_NONE) {
823 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
827 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
828 CONTACTS_ERROR_NONE) {
829 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
833 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
834 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
838 if (contacts_list_get_current_record_p(list, &record) !=
839 CONTACTS_ERROR_NONE) {
840 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
847 if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
848 != CONTACTS_ERROR_NONE) {
849 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
853 if (number == NULL) {
854 ERR("No number at the location");
855 error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
859 DBG("number %s", number);
862 if (!__bt_ag_agent_make_call(number)) {
863 ERR("Problem launching application");
864 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
870 contacts_list_destroy(list, TRUE);
873 contacts_filter_destroy(filter);
876 contacts_query_destroy(query);
878 contacts_disconnect();
885 bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
886 const gchar *path, const gchar *sender)
888 bt_hfp_agent_error_t ret;
892 if (dtmf == NULL || path == NULL || sender == NULL) {
893 ERR("Invalid Argument");
897 DBG("Dtmf = %s", dtmf);
898 DBG("Application path = %s", path);
899 DBG("Sender = %s", sender);
901 ret = __bt_ag_agent_gdbus_method_send(sender,
902 path, TELEPHONY_APP_INTERFACE,
904 g_variant_new("(s)", dtmf));
909 gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
910 const gchar *path, const gchar *sender)
914 if (path == NULL || sender == NULL) {
915 DBG("Invalid Arguments");
919 DBG("Application path = %s", path);
920 DBG("Value = %d", chld_value);
921 DBG("Sender = %s", sender);
923 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
924 /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
925 if not return FALSE */
926 if (chld_value != 0 && chld_value != 1 && chld_value != 2)
929 if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
933 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
934 BT_AG_SERVICE_NAME, "Threeway",
935 g_variant_new("(u)", chld_value));
940 bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
942 bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
943 char *last_num = NULL;
946 int phone_lock_state;
948 contacts_list_h list = NULL;
949 contacts_query_h query = NULL;
950 contacts_filter_h filter = NULL;
951 contacts_record_h record = NULL;
952 unsigned int projections[] = {
953 _contacts_phone_log.address,
954 _contacts_phone_log.log_type,
959 if (contacts_connect() != CONTACTS_ERROR_NONE) {
960 ERR(" contacts_connect failed");
961 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
965 contacts_filter_create(_contacts_phone_log._uri, &filter);
970 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
971 CONTACTS_MATCH_EQUAL,
972 CONTACTS_PLOG_TYPE_VOICE_OUTGOING) !=
973 CONTACTS_ERROR_NONE) {
974 ERR(" contacts_filter_add_int failed");
975 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
979 if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) !=
980 CONTACTS_ERROR_NONE) {
981 ERR(" contacts_filter_add_operator failed");
982 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
986 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
987 CONTACTS_MATCH_EQUAL,
988 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) !=
989 CONTACTS_ERROR_NONE) {
990 ERR(" contacts_filter_add_int failed");
991 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
995 contacts_query_create(_contacts_phone_log._uri, &query);
1000 contacts_query_set_filter(query, filter);
1002 if (contacts_query_set_projection(query, projections,
1003 sizeof(projections)/sizeof(unsigned int)) !=
1004 CONTACTS_ERROR_NONE) {
1005 ERR(" contacts_query_set_projection failed");
1006 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1010 if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false)
1011 != CONTACTS_ERROR_NONE) {
1012 ERR(" contacts_query_set_sort failed");
1013 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1017 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
1018 CONTACTS_ERROR_NONE) {
1019 ERR(" contacts_db_get_records_with_query failed");
1020 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1024 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
1025 ERR(" contacts_list_first failed");
1026 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1030 if (contacts_list_get_current_record_p(list, &record) !=
1031 CONTACTS_ERROR_NONE) {
1032 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1039 if (contacts_record_get_str(record, _contacts_phone_log.address,
1040 &last_num) != CONTACTS_ERROR_NONE) {
1041 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1045 if (last_num == NULL) {
1046 ERR("No last number");
1047 err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
1051 if (!__bt_is_phone_locked(&phone_lock_state)) {
1052 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1056 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
1057 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1061 if (!__bt_get_outgoing_call_condition(&condition)) {
1062 ERR(" Failed to get the call condition");
1063 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1067 if (condition == BT_MO_ONLY_UNLOCKED &&
1068 phone_lock_state == VCONFKEY_IDLE_LOCK) {
1069 ERR(" call condition and phone lock state check fail");
1070 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1074 switch (callapp_type) {
1076 if (!__bt_ag_agent_make_call(last_num)) {
1077 ERR("Problem launching application");
1078 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1082 if (!__bt_ag_agent_make_video_call(last_num)) {
1083 ERR("Problem launching application");
1084 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1087 case BT_FOLLOW_CALL_LOG:
1088 if (contacts_record_get_int(record,
1089 _contacts_phone_log.log_type,
1090 &type) != CONTACTS_ERROR_NONE) {
1091 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1094 if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
1095 if (!__bt_ag_agent_make_call(last_num)) {
1096 ERR("Problem launching application");
1097 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1099 } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
1100 if (!__bt_ag_agent_make_video_call(last_num)) {
1101 ERR("Problem launching application");
1102 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1105 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1109 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1116 contacts_list_destroy(list, TRUE);
1119 contacts_filter_destroy(filter);
1122 contacts_query_destroy(query);
1124 contacts_disconnect();
1126 if (last_num != NULL)
1134 bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
1135 const gchar *path, const gchar *sender)
1137 bt_hfp_agent_error_t ret;
1141 if (cmd == NULL || path == NULL || sender == NULL) {
1142 ERR("Invalid Argument");
1143 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
1146 DBG("cmd = %s", cmd);
1147 DBG("Application path = %s", path);
1148 DBG("Sender = %s", sender);
1150 ret = __bt_ag_agent_gdbus_method_send(sender,
1151 path, TELEPHONY_APP_INTERFACE,
1153 g_variant_new("(s)", cmd));
1158 gboolean _bt_ag_agent_get_signal_quality(void *device)
1164 if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
1165 DBG("VCONFKEY_TELEPHONY_RSSI failed\n");
1169 DBG("RSSI : %d", rssi);
1171 _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
1178 _bt_hfp_signal_quality_reply(-1, -1, device);
1182 gboolean _bt_ag_agent_get_battery_status(void *device)
1184 gint battery_chrg_status;
1185 gint battery_capacity;
1189 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
1190 &battery_chrg_status)) {
1191 DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n");
1195 DBG("Status : %d\n", battery_chrg_status);
1197 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
1198 &battery_capacity)) {
1199 DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n");
1203 DBG("Capacity : %d\n", battery_capacity);
1205 _bt_hfp_battery_property_reply(device,
1206 battery_chrg_status, battery_capacity);
1211 _bt_hfp_battery_property_reply(device, -1, -1);
1216 gboolean _bt_ag_agent_get_operator_name(void *device)
1218 char *operator_name;
1221 operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
1222 if (NULL == operator_name) {
1223 DBG("vconf_get_str failed");
1224 _bt_hfp_operator_reply(NULL, device);
1228 DBG("operator_name = [%s]", operator_name);
1230 _bt_hfp_operator_reply(operator_name, device);
1232 free(operator_name);
1238 gboolean _bt_hfp_agent_nrec_status(gboolean status,
1242 bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
1244 DBG("NREC status = %d", status);
1246 hs->nrec_status = FALSE;
1248 hs->nrec_status = TRUE;
1250 _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
1251 BT_AG_SERVICE_NAME, "NrecStatusChanged",
1252 g_variant_new("(b)", status));
1257 gboolean _bt_ag_agent_get_imei_number(void *device)
1262 imei_number = tel_get_misc_me_imei_sync(tapi_handle);
1263 if (NULL == imei_number) {
1264 ERR("tel_get_misc_me_imei_sync for imei_number failed");
1268 if (!g_utf8_validate(imei_number, -1, NULL)) {
1270 ERR("get_imei_number : invalid UTF8");
1274 DBG_SECURE("imei_number = [%s]", imei_number);
1275 _bt_hfp_get_imei_number_reply(imei_number, device);
1281 _bt_hfp_get_imei_number_reply(NULL, device);
1286 void _bt_ag_agent_get_manufacturer_name(void *device)
1289 char *manufacturer_name;
1292 ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
1293 &manufacturer_name);
1294 if (SYSTEM_INFO_ERROR_NONE != ret) {
1295 ERR("Get manufacturer_name failed : %d", ret);
1296 if (NULL != manufacturer_name)
1297 free(manufacturer_name);
1299 manufacturer_name = g_strdup("Unknown");
1300 } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
1301 free(manufacturer_name);
1302 manufacturer_name = g_strdup("Unknown");
1303 ERR("get_manufacturer_name : invalid UTF8");
1306 DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
1307 _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
1308 free(manufacturer_name);
1312 void _bt_ag_agent_get_imsi(void *device)
1315 TelSimImsiInfo_t imsi;
1316 memset(&imsi, 0, sizeof(TelSimImsiInfo_t));
1317 if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
1318 ERR("tel_get_sim_imsi failed");
1321 DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
1323 _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
1327 _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
1331 int _bt_ag_agent_registration_status_convert(int result)
1334 case TAPI_NETWORK_SERVICE_LEVEL_NO:
1335 return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
1336 case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
1337 return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
1338 case TAPI_NETWORK_SERVICE_LEVEL_FULL:
1339 return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
1340 case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
1341 return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
1343 return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
1348 void _bt_ag_agent_get_creg_status(void *device)
1354 int registration_status = 0;
1355 int roam_status = 0;
1357 ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
1359 if (ret != TAPI_API_SUCCESS) {
1360 ERR("tel_get_property_int failed");
1363 registration_status =
1364 _bt_ag_agent_registration_status_convert(result);
1366 DBG_SECURE("Registration status %d", result);
1367 DBG_SECURE("Mapped Status %d", registration_status);
1368 if (registration_status ==
1369 BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
1370 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
1372 ERR("Get roaming status failed err = %d\n", ret);
1375 DBG_SECURE("Roam status %d", roam_status);
1376 if (roam_status == 1) {
1377 registration_status =
1378 BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
1382 _bt_hfp_get_creg_status_reply(n, registration_status, device);
1388 void _bt_ag_agent_get_model_name(void *device)
1394 ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
1395 if (SYSTEM_INFO_ERROR_NONE != ret) {
1396 ERR("Get model_name failed: %d", ret);
1397 if (NULL != model_name)
1400 model_name = g_strdup("Unknown");
1401 } else if (!g_utf8_validate(model_name, -1, NULL)) {
1403 model_name = g_strdup("Unknown");
1404 ERR("get_model_name : invalid UTF8");
1407 DBG_SECURE("model_name = [%s]", model_name);
1408 _bt_hfp_get_model_info_reply(model_name, device);
1413 void _bt_ag_agent_get_revision_information(void *device)
1416 char *revision_info;
1419 ret = system_info_get_platform_string("http://tizen.org/system/build.string",
1421 if (SYSTEM_INFO_ERROR_NONE != ret) {
1422 ERR("Get revision_info failed: %d", ret);
1423 if (NULL != revision_info)
1424 free(revision_info);
1426 revision_info = g_strdup("Unknown");
1427 } else if (!g_utf8_validate(revision_info, -1, NULL)) {
1428 free(revision_info);
1429 revision_info = g_strdup("Unknown");
1430 ERR("get_revision_info: invalid UTF8");
1433 DBG_SECURE("revision_info = [%s]", revision_info);
1434 _bt_hfp_get_revision_info_reply(revision_info, device);
1435 free(revision_info);
1439 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
1440 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1445 b = bundle_create();
1447 ERR("bundle_create() Failed");
1451 bundle_add(b, "domain", "bt_headset");
1453 bundle_add(b, "action_type", "deactivate");
1455 aul_launch_app_async("org.tizen.svoice", b);
1461 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1464 app_control_h service = NULL;
1466 app_control_create(&service);
1468 if (service == NULL) {
1469 ERR("Service create failed");
1473 app_control_set_app_id(service, "org.tizen.svoice");
1474 app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
1475 if (app_control_add_extra_data(service, "domain", "bt_headset")
1476 != APP_CONTROL_ERROR_NONE) {
1477 ERR("app_control_add_extra_data failed");
1478 app_control_destroy(service);
1483 if (app_control_add_extra_data(service, "action_type", "deactivate")
1484 != APP_CONTROL_ERROR_NONE) {
1485 ERR("app_control_add_extra_data failed");
1486 app_control_destroy(service);
1490 if (app_control_send_launch_request(service, NULL, NULL) !=
1491 APP_CONTROL_ERROR_NONE) {
1492 ERR("launch failed");
1493 app_control_destroy(service);
1497 app_control_destroy(service);
1503 gboolean _bt_ag_agent_voice_dial(gboolean activate)
1505 DBG("Activate = %d", activate);
1507 return __bt_ag_agent_launch_voice_dial(activate);
1510 static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
1513 hs->codec_info.is_negotiating = FALSE;
1514 hs->codec_info.requested_by_hf = FALSE;
1515 hs->codec_info.sending_codec = 0;
1517 hs->codec_info.remote_codecs = 0;
1518 hs->codec_info.final_codec = 0;
1519 hs->nrec_status = FALSE;
1522 if (hs->codec_info.nego_timer) {
1523 g_source_remove(hs->codec_info.nego_timer);
1524 hs->codec_info.nego_timer = 0;
1526 wbs_opts.wbs_enable = wbs_en;
1529 static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
1531 struct ag_codec *data = (struct ag_codec *)user_data;
1533 if (g_strcmp0(data->codec_status, "finish") == 0) {
1534 DBG("Codec negotiation finished");
1535 __bt_ag_sco_connect(data->bt_ag_info);
1536 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1537 g_free(data->codec_status);
1540 } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
1541 DBG("Timeout is occured in codec negotiation");
1544 if (data->bt_ag_info->codec_info.requested_by_hf) {
1545 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1547 __bt_ag_sco_connect(data->bt_ag_info);
1548 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1550 g_free(data->codec_status);
1556 static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
1561 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
1563 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
1564 G_DBUS_PROXY_FLAGS_NONE, NULL,
1565 BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
1566 BT_ADAPTER_INTERFACE, NULL, &err);
1570 ERR("Unable to create proxy: %s", err->message);
1571 g_clear_error(&err);
1573 return BT_HFP_AGENT_ERROR_INTERNAL;
1576 ret = g_dbus_proxy_call_sync(proxy, method,
1577 g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
1578 G_DBUS_CALL_FLAGS_NONE, -1,
1581 /* dBUS-RPC is failed */
1582 ERR("dBUS-RPC is failed");
1584 /* dBUS gives error cause */
1585 ERR("D-Bus API failure: errCode[%x], message[%s]",
1586 err->code, err->message);
1588 g_clear_error(&err);
1590 return BT_HFP_AGENT_ERROR_INTERNAL;
1592 g_variant_unref(ret);
1594 return BT_HFP_AGENT_ERROR_NONE;
1597 static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
1600 bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
1602 DBG("Codec setup [%x]", codec);
1604 /* 1. Compare sending codec & recieved code */
1605 if (hs->codec_info.sending_codec != codec)
1606 err = BT_HFP_AGENT_ERROR_INTERNAL;
1608 /* 2. Send WB or NB command */
1610 case BT_CVSD_CODEC_ID:
1611 err = __bt_ag_set_codec(hs, "SetNbParameters");
1613 case BT_MSBC_CODEC_ID:
1614 err = __bt_ag_set_codec(hs, "SetWbsParameters");
1617 err = BT_HFP_AGENT_ERROR_INTERNAL;
1621 /* If the vendor specific calling returns error or codec is not correct,
1622 * we send CVSD Codec parameter to MM module. and also returns
1623 * normal value to HF
1625 if (err != BT_HFP_AGENT_ERROR_NONE)
1626 codec = BT_CVSD_CODEC_ID;
1628 hs->codec_info.final_codec = codec;
1633 static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
1634 gboolean init_by_hf)
1637 struct ag_codec *data = g_new0(struct ag_codec, 1);
1639 #ifdef TIZEN_FEATURE_BT_KIRAN_DEVICE
1640 codec = BT_CVSD_CODEC_ID;
1642 if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
1643 codec = BT_MSBC_CODEC_ID;
1645 codec = BT_CVSD_CODEC_ID;
1648 if (wbs_opts.wbs_enable == FALSE)
1649 codec = BT_CVSD_CODEC_ID;
1653 if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
1654 return BT_HFP_AGENT_ERROR_INTERNAL;
1656 DBG("Send +BCS:%d\n", codec);
1658 /* Send +BCS command to HF, and wait some times */
1659 hs->codec_info.is_negotiating = TRUE;
1660 hs->codec_info.sending_codec = codec;
1661 hs->codec_info.requested_by_hf = init_by_hf;
1662 hs->codec_info.final_codec = codec;
1664 data->bt_ag_info = hs;
1665 data->codec_status = g_strdup("timeout");
1667 hs->codec_info.nego_timer = g_timeout_add_seconds(
1668 HFP_CODEC_NEGOTIATION_TIMEOUT,
1669 (GSourceFunc)__bt_ag_codec_negotiation_finished,
1672 return BT_HFP_AGENT_ERROR_NONE;
1676 static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
1677 bt_ag_info_t *hs, gboolean init_by_hf)
1679 DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
1681 if (hs->state < HEADSET_STATE_CONNECTED)
1682 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1684 if (hs->codec_info.is_negotiating == TRUE) {
1685 /* In codec negotiation, return and wait */
1686 ERR("Codec nogotiation is in progress");
1687 return BT_HFP_AGENT_ERROR_BUSY;
1690 /* Not support Codec Negotiation or Not recieved BAC command */
1691 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
1692 hs->codec_info.remote_codecs == 0) {
1693 ERR("No support for Codec Negotiation or receive BAC command");
1695 return BT_HFP_AGENT_ERROR_INTERNAL;
1697 __bt_ag_sco_connect(hs);
1698 return BT_HFP_AGENT_ERROR_INTERNAL;
1702 /* If HF initiated codec connection setup, it should send OK command
1703 * before +BCS command transmission.
1706 return HFP_STATE_MNGR_ERR_NONE;
1708 return __bt_hfp_send_bcs_command(hs, init_by_hf);
1712 static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
1715 *codecs = 0x00000000;
1717 str = strchr(cmd, '=');
1721 while (str != NULL) {
1724 if (atoi(str) == BT_CVSD_CODEC_ID)
1725 *codecs |= BT_CVSD_CODEC_MASK;
1726 else if (atoi(str) == BT_MSBC_CODEC_ID)
1727 *codecs |= BT_MSBC_CODEC_MASK;
1729 str = strchr(str, ',');
1732 if (*codecs == 0x00000000)
1738 /* AT+BAC (Bluetooth Available Codecs) */
1739 static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
1741 uint32_t codecs = 0x00000000;
1742 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1744 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
1745 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1746 } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
1747 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1749 DBG("Update remote available codecs [%x]", codecs);
1750 hs->codec_info.remote_codecs = codecs;
1753 _bt_ag_send_response(hs, err);
1755 /* Reset codec information and
1756 * restart codec connection setup by AG
1758 hs->codec_info.final_codec = 0;
1759 if (hs->codec_info.nego_timer) {
1760 hs->codec_info.is_negotiating = FALSE;
1761 hs->codec_info.requested_by_hf = FALSE;
1762 hs->codec_info.sending_codec = 0;
1763 g_source_remove(hs->codec_info.nego_timer);
1764 __bt_hfp_codec_connection_setup(hs, FALSE);
1770 /* AT+BCC (Bluetooth Codec Connection) */
1771 static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
1773 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1775 err = __bt_hfp_codec_connection_setup(hs, TRUE);
1777 _bt_ag_send_response(hs, err);
1779 if (err == HFP_STATE_MNGR_ERR_NONE)
1780 err = __bt_hfp_send_bcs_command(hs, TRUE);
1782 if (err != HFP_STATE_MNGR_ERR_NONE)
1783 ERR("Fail to request codec connection setup");
1788 /* AT+BCS (Bluetooth Codec Selection) */
1789 static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
1791 uint32_t codec = 0x00000000;
1792 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1793 struct ag_codec *data = g_new0(struct ag_codec, 1);
1796 if (hs->codec_info.nego_timer) {
1797 g_source_remove(hs->codec_info.nego_timer);
1798 hs->codec_info.nego_timer = 0;
1801 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
1802 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1803 else if (__hfp_parse_available_codecs(buf, &codec) < 0)
1804 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1805 else if (__bt_ag_codec_selection_setup(hs, codec) !=
1806 BT_HFP_AGENT_ERROR_NONE)
1807 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1809 data->bt_ag_info = hs;
1810 data->codec_status = g_strdup("finish");
1811 _bt_ag_send_response(hs, err);
1812 __bt_ag_codec_negotiation_finished(data);
1817 static void __bt_ag_str2ba(const char *str, bt_addr *ba)
1820 for (i = 5; i >= 0; i--, str += 3)
1821 ba->b[i] = strtol(str, NULL, 16);
1824 static const char *__bt_ag_state2str(hs_state_t state)
1827 case HEADSET_STATE_DISCONNECTED:
1828 return "disconnected";
1829 case HEADSET_STATE_CONNECTING:
1830 return "connecting";
1831 case HEADSET_STATE_CONNECTED:
1833 case HEADSET_STATE_PLAY_IN_PROGRESS:
1834 return "Play In Progress";
1835 case HEADSET_STATE_ON_CALL:
1842 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
1843 const char *address)
1848 ret_if(address == NULL);
1849 ret_if(addr == NULL);
1851 for (i = 0; i < 6; i++) {
1852 addr[5 - i] = strtol(address, &ptr, 16);
1853 if (ptr[0] != '\0') {
1862 static gboolean __bt_ag_check_nval(GIOChannel *chan)
1864 struct pollfd file_desc;
1866 memset(&file_desc, 0, sizeof(file_desc));
1867 file_desc.fd = g_io_channel_unix_get_fd(chan);
1868 file_desc.events = POLLNVAL;
1870 if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
1876 static int __bt_ag_sco_connect(bt_ag_info_t *hs)
1878 struct sco_socket_addr sco_addr;
1883 bt_ag_slconn_t *slconn = hs->slc;
1886 if (hs->state == HEADSET_STATE_ON_CALL)
1887 return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED;
1889 if (hs->state != HEADSET_STATE_CONNECTED)
1890 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1891 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
1892 _bt_ag_agent_check_transport_state();
1895 /* Create Sco socket */
1896 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
1898 ERR("ERROR: Create socket failed.\n");
1899 return BT_HFP_AGENT_ERROR_INTERNAL;
1902 /* Bind Sco Socket to Local BD addr */
1903 memset(&sco_addr, 0, sizeof(sco_addr));
1904 sco_addr.sco_family = AF_BLUETOOTH;
1906 __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
1907 DBG("Local BD address: %s", local_addr);
1909 err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1911 ERR("ERROR: sco socket binding failed");
1912 ERR("Close SCO skt");
1914 return BT_HFP_AGENT_ERROR_INTERNAL;
1917 DBG("Socket FD : %d", sco_skt);
1919 io = g_io_channel_unix_new(sco_skt);
1920 g_io_channel_set_close_on_unref(io, TRUE);
1921 /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
1922 g_io_channel_set_buffered(io, FALSE);
1923 g_io_channel_set_encoding(io, NULL, NULL);*/
1925 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
1926 (slconn && (slconn->hs_features &
1927 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
1928 wbs_opts.wbs_enable == TRUE) {
1929 bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
1930 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
1932 DBG("set Bluetooth voice: %d", bt_vo.setting);
1933 err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
1934 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
1936 ERR("ERROR: sco socket set socket option failed");
1937 ERR("Close SCO skt");
1938 g_io_channel_unref(io);
1940 return BT_HFP_AGENT_ERROR_INTERNAL;
1943 DBG("Set NB codec parameter");
1944 __bt_ag_set_codec(hs, "SetNbParameters");
1947 memset(&sco_addr, 0, sizeof(sco_addr));
1948 sco_addr.sco_family = AF_BLUETOOTH;
1949 __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
1950 DBG("remotel BD address: %s", hs->remote_addr);
1952 err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1953 if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
1954 ERR("ERROR: sco socket connect failed : %d", err);
1955 ERR("Close SCO skt");
1956 g_io_channel_unref(io);
1958 return BT_HFP_AGENT_ERROR_INTERNAL;
1961 /* Disabling the watch since SCO is connected */
1962 /*watch_id = __bt_ag_set_watch(io,
1963 (GIOFunc) __bt_ag_sco_connect_cb, hs);
1965 DBG("SCO watch set Success");*/
1969 _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
1970 return BT_HFP_AGENT_ERROR_NONE;
1973 static void __bt_ag_close_sco(bt_ag_info_t *hs)
1977 int sock = g_io_channel_unix_get_fd(hs->sco);
1978 shutdown(sock, SHUT_RDWR);
1979 g_io_channel_unref(hs->sco);
1984 __bt_ag_agent_remove_watch(&hs->sco_id);
1987 static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
1988 GIOCondition cond, gpointer user_data)
1990 bt_ag_info_t *ag_info = user_data;
1993 if (cond & G_IO_NVAL)
1996 if (cond & (G_IO_HUP | G_IO_ERR)) {
1997 ag_info->sco = NULL;
1998 if (ag_info->sco_id)
1999 __bt_ag_agent_remove_watch(&ag_info->sco_id);
2001 if (ag_info->watch_id)
2002 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
2008 static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
2009 GIOCondition cond, gpointer user_data)
2011 bt_ag_info_t *ag_info = user_data;
2015 bt_ag_slconn_t *slconn = ag_info->slc;
2019 if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
2020 __bt_ag_check_nval(chan)) {
2021 ERR("cond or chan is not valid");
2025 INFO_C("Incoming SCO....");
2027 if (ag_info->state < HEADSET_STATE_CONNECTED)
2028 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
2030 sco_skt = g_io_channel_unix_get_fd(chan);
2032 cli_sco_sock = accept(sco_skt, NULL, NULL);
2033 if (cli_sco_sock < 0) {
2034 ERR("accept is failed");
2038 sco_io = g_io_channel_unix_new(cli_sco_sock);
2039 g_io_channel_set_close_on_unref(sco_io, TRUE);
2040 g_io_channel_set_encoding(sco_io, NULL, NULL);
2041 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2042 g_io_channel_set_buffered(sco_io, FALSE);
2044 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2045 (slconn && (slconn->hs_features &
2046 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
2047 wbs_opts.wbs_enable == TRUE) {
2048 bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
2049 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
2051 DBG("set Bluetooth voice: %d", bt_vo.setting);
2052 err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
2053 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
2055 ERR("Sco socket set socket option failed");
2056 close(cli_sco_sock);
2061 ag_info->sco = sco_io;
2062 ag_info->sco_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2063 __bt_ag_sco_server_conn_cb, ag_info);
2065 if (remote_dev_path)
2066 g_free(remote_dev_path);
2068 remote_dev_path = g_strdup(ag_info->path);
2070 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
2075 static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
2077 DBG("Start SCO server");
2078 struct sco_socket_addr addr;
2081 bdaddr_t bd_addr = {{0},};
2083 if (hs->sco_server_started) {
2084 DBG("Already exsist");
2085 return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
2089 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
2091 ERR("Can't create socket:\n");
2092 return BT_HFP_AGENT_ERROR_INTERNAL;
2095 /* Bind to local address */
2096 memset(&addr, 0, sizeof(addr));
2097 addr.sco_family = AF_BLUETOOTH;
2099 _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
2100 DBG("Bind to address %s", hs->remote_addr);
2101 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2103 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2104 ERR("Can't bind socket:\n");
2108 if (listen(sco_skt, 1)) {
2109 ERR("Can not listen on the socket:\n");
2113 sco_io = g_io_channel_unix_new(sco_skt);
2114 g_io_channel_set_close_on_unref(sco_io, TRUE);
2115 g_io_channel_set_encoding(sco_io, NULL, NULL);
2116 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2117 g_io_channel_set_buffered(sco_io, FALSE);
2119 hs->sco_server = sco_io;
2120 hs->sco_watch_id = g_io_add_watch(sco_io,
2121 G_IO_IN | G_IO_HUP | G_IO_ERR |
2122 G_IO_NVAL, __bt_ag_sco_server_cb, hs);
2124 hs->sco_server_started = TRUE;
2125 return BT_HFP_AGENT_ERROR_NONE;
2129 return BT_HFP_AGENT_ERROR_INTERNAL;
2132 void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
2134 DBG("Stop SCO server");
2135 if (hs->sco_server) {
2136 g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
2137 g_io_channel_unref(hs->sco_server);
2138 hs->sco_server = NULL;
2140 hs->sco_server_started = FALSE;
2143 static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
2145 GIOChannel *rfcomm = hs->rfcomm;
2148 g_io_channel_shutdown(rfcomm, TRUE, NULL);
2149 g_io_channel_unref(rfcomm);
2159 static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
2162 if (cond & G_IO_NVAL)
2165 if (name_owner_sig_id != -1)
2166 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
2168 name_owner_sig_id = -1;
2172 DBG("Audio connection disconnected");
2173 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2178 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
2180 bt_ag_slconn_t *slconn = hs->slc;
2181 const char *hs_state;
2182 hs_state_t org_state = hs->state;
2183 gboolean val = FALSE;
2185 if (org_state == state)
2188 hs_state = __bt_ag_state2str(state);
2191 case HEADSET_STATE_CONNECTING:
2192 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2194 BT_HEADSET_INTERFACE, "State",
2195 g_variant_new("s", hs_state));
2199 case HEADSET_STATE_CONNECTED:
2200 if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
2201 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2203 BT_HEADSET_INTERFACE, "State",
2204 g_variant_new("s", hs_state));
2206 if (hs->state < state) {
2208 active_devices = g_slist_append(active_devices, hs);
2209 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2211 BT_HEADSET_INTERFACE,
2213 g_variant_new("b", val));
2215 DBG("Device %s connected\n", hs->remote_addr);
2216 #if defined(TIZEN_SUPPORT_DUAL_HF)
2217 if (!hs->is_companion_device)
2218 __bt_ag_start_sco_server(hs);
2220 __bt_ag_start_sco_server(hs);
2223 /* Set default code as Gateway NB */
2224 __bt_ag_set_codec(hs, "SetNbParameters");
2225 } else if (hs->state == HEADSET_STATE_ON_CALL) {
2227 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2229 BT_HEADSET_INTERFACE,
2231 g_variant_new("b", val));
2236 case HEADSET_STATE_DISCONNECTED:
2237 __bt_ag_close_sco(hs);
2238 __bt_ag_headset_close_rfcomm(hs);
2240 if (hs->state == HEADSET_STATE_ON_CALL) {
2242 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2244 BT_HEADSET_INTERFACE,
2246 g_variant_new("b", val));
2250 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2252 BT_HEADSET_INTERFACE,
2254 g_variant_new("b", val));
2255 if (hs->state > HEADSET_STATE_CONNECTING)
2256 _bt_hfp_device_disconnected(hs);
2258 active_devices = g_slist_remove(active_devices, hs);
2260 __bt_ag_codec_negotiation_info_reset(hs, TRUE);
2261 #if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
2262 __bt_ag_set_codec(hs, "SetNbParameters");
2266 /* Since SCO server is binded on remote address */
2267 /* Need to stop SCO server once heasdet disconencted*/
2268 if (hs->sco_server_started)
2269 __bt_ag_stop_sco_server(hs);
2271 g_free(hs->remote_addr);
2275 case HEADSET_STATE_PLAY_IN_PROGRESS:
2276 case HEADSET_STATE_ON_CALL:
2278 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2280 BT_HEADSET_INTERFACE, "State",
2281 g_variant_new("s", hs_state));
2283 /*add watch for sco data */
2284 hs->sco_id = g_io_add_watch(hs->sco,
2285 G_IO_ERR | G_IO_NVAL,
2286 (GIOFunc) __bt_ag_sco_cb, hs);
2288 _bt_ag_agent_emit_property_changed(
2289 ag_dbus_conn, hs->path,
2290 BT_HEADSET_INTERFACE, "Playing",
2291 g_variant_new("b", val));
2293 if (slconn->microphone_gain >= 0)
2294 _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
2295 slconn->microphone_gain);
2297 if (slconn->speaker_gain >= 0)
2298 _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
2299 slconn->speaker_gain);
2309 INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
2310 __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
2313 static struct event at_event_callbacks[] = {
2314 { "AT+BRSF", _bt_hfp_supported_features },
2315 { "AT+CIND", _bt_hfp_report_indicators },
2316 { "AT+CMER", _bt_hfp_enable_indicators },
2317 { "AT+CHLD", _bt_hfp_call_hold },
2318 { "ATA", _bt_hfp_answer_call },
2319 { "ATD", _bt_hfp_dial_number },
2320 { "AT+VG", _bt_hfp_signal_gain_setting },
2321 { "AT+CHUP", _bt_hfp_terminate_call },
2322 { "AT+CKPD", _bt_hfp_key_press },
2323 { "AT+CLIP", _bt_hfp_cli_notification },
2324 { "AT+BTRH", _bt_hfp_response_and_hold },
2325 { "AT+BLDN", _bt_hfp_last_dialed_number },
2326 { "AT+VTS", _bt_hfp_dtmf_tone },
2327 { "AT+CNUM", _bt_hfp_subscriber_number },
2328 { "AT+CLCC", _bt_hfp_list_current_calls },
2329 { "AT+CMEE", _bt_hfp_extended_errors },
2330 { "AT+CCWA", _bt_hfp_call_waiting_notify },
2331 { "AT+COPS", _bt_hfp_operator_selection },
2332 { "AT+NREC", _bt_hfp_nr_and_ec },
2333 { "AT+BVRA", _bt_hfp_voice_dial },
2334 { "AT+XAPL", _bt_hfp_apl_command },
2335 { "AT+IPHONEACCEV", _bt_hfp_apl_command },
2336 { "AT+BIA", _bt_hfp_indicators_activation },
2337 { "AT+CPBS", _bt_hfp_select_pb_memory },
2338 { "AT+CPBR", _bt_hfp_read_pb_entries},
2339 { "AT+CPBF", _bt_hfp_find_pb_entires },
2340 { "AT+CSCS", _bt_hfp_select_character_set },
2341 { "AT+CSQ", _bt_hfp_get_signal_quality },
2342 { "AT+CBC", _bt_hfp_get_battery_charge_status },
2343 { "AT+CPAS", _bt_hfp_get_activity_status },
2344 { "AT+CGSN", _bt_hfp_get_equipment_identity },
2345 { "AT+CGMM", _bt_hfp_get_model_information },
2346 { "AT+CGMI", _bt_hfp_get_device_manufacturer },
2347 { "AT+CGMR", _bt_hfp_get_revision_information },
2348 { "AT+BAC", __bt_hfp_available_codecs },
2349 { "AT+BCC", __bt_hfp_codec_connection },
2350 { "AT+BCS", __bt_hfp_codec_selection },
2351 { "AT+XSAT", _bt_hfp_vendor_cmd },
2352 { "AT+CIMI", _bt_hfp_get_imsi },
2353 { "AT+CREG", _bt_hfp_get_creg_status },
2357 int num_of_secure_command = 4;
2358 static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
2360 void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
2364 char s[MAX_BUFFER_SIZE] = {0, };
2365 gboolean hide = FALSE;
2367 gboolean is_security_command = FALSE;
2370 strncpy(s, buf, MAX_BUFFER_SIZE - 1);
2372 for (i = 0; i < num_of_secure_command; i++) {
2373 if (strstr(buf, secure_command[i])) {
2374 is_security_command = TRUE;
2379 /* +XSAT: 11,DISC */
2380 xsat_ptr = strstr(s, "11,DISC,");
2382 xsat_ptr = xsat_ptr + 8;
2384 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2390 /* AT+XSAT=11,Q_CT,X,XXXX */
2391 xsat_ptr = strstr(s, "11,Q_CT,");
2393 xsat_ptr = xsat_ptr + 8;
2395 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2396 if (x > 1) /* ignore 0 and 1 position */
2403 while (s[i] != '\0') {
2404 if (s[i] == '\r' || s[i] == '\n') {
2408 hide = hide ? FALSE : TRUE;
2409 else if (is_security_command && hide) {
2417 INFO("%s Buffer = [%s], Len(%d)", message, s, strlen(s));
2422 static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
2426 __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
2428 for (ev = at_event_callbacks; ev->cmd; ev++) {
2429 if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
2430 return ev->callback(hs, buf);
2436 static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
2439 ssize_t final_written, count;
2440 char rsp_buffer[MAX_BUFFER_SIZE];
2444 count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
2446 ERR("count is %d", count);
2450 if (!hdset->io_chan) {
2451 ERR("__bt_ag_send_at_valist: headset not connected");
2457 fd = g_io_channel_unix_get_fd(hdset->io_chan);
2460 while (final_written < count) {
2464 written = write(fd, rsp_buffer + final_written,
2465 count - final_written);
2466 } while (written < 0 && errno == EINTR);
2470 ERR("write failed : %s (%d)", strerror(-err), -err);
2474 final_written += written;
2477 /* Synchronize the sending buffer */
2481 ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
2485 __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
2490 int __attribute__((format(printf, 2, 3)))
2491 _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
2496 va_start(ap, format);
2497 ret = __bt_ag_send_at_valist(hs, ap, format);
2503 void __attribute__((format(printf, 3, 4)))
2504 _bt_ag_send_foreach_headset(GSList *devices,
2505 int (*cmp) (bt_ag_info_t *hs),
2511 for (l = devices; l != NULL; l = l->next) {
2512 bt_ag_info_t *hs = l->data;
2515 if (cmp && cmp(hs) != 0)
2518 va_start(ap, format);
2519 ret = __bt_ag_send_at_valist(hs, ap, format);
2521 ERR("Failed to send to headset: %s (%d)",
2522 strerror(-ret), -ret);
2527 int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
2529 if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
2530 return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
2533 case HFP_STATE_MNGR_ERR_NONE:
2534 return _bt_ag_send_at(hs, "\r\nOK\r\n");
2535 case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
2536 return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
2538 return _bt_ag_send_at(hs, "\r\nERROR\r\n");
2542 static gboolean __bt_ag_event_handler(GIOChannel *channel,
2543 GIOCondition cond, void *user_data)
2545 bt_ag_slconn_t *slconn;
2546 unsigned char event_buf[MAX_BUFFER_SIZE];
2548 size_t available_buffer;
2550 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2553 if (cond & G_IO_NVAL)
2556 slconn = bt_ag_info->slc;
2557 if (cond & (G_IO_ERR | G_IO_HUP)) {
2558 if (bt_ag_info->watch_id)
2559 __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
2561 ERR("ERR or HUP on RFCOMM socket");
2562 INFO_C("Disconnected [AG role] [Terminated by remote dev]");
2566 fd = g_io_channel_unix_get_fd(channel);
2567 len = read(fd, event_buf, sizeof(event_buf) - 1);
2571 available_buffer = sizeof(slconn->buffer) - (slconn->start) -
2572 (slconn->length) - 1;
2573 if (available_buffer < (size_t) len) {
2574 ERR("Buffer over flow");
2578 memcpy(&slconn->buffer[slconn->start], event_buf, len);
2579 slconn->length += len;
2581 slconn->buffer[slconn->start + slconn->length] = '\0';
2583 while (slconn->length > 0) {
2588 get_cr = strchr(&slconn->buffer[slconn->start], '\r');
2592 cmd_len = 1 + (off_t) get_cr -
2593 (off_t) &slconn->buffer[slconn->start];
2597 DBG("Call AT handler");
2598 err = __bt_ag_at_handler(bt_ag_info,
2599 &slconn->buffer[slconn->start]);
2601 ERR("Failed to call AT handler");
2605 if (err == -EINVAL) {
2606 ERR("Unrecognized command: %s",
2607 &slconn->buffer[slconn->start]);
2608 err = _bt_ag_send_response(bt_ag_info,
2609 HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
2613 ERR("Error handling command %s: %s (%d)",
2614 &slconn->buffer[slconn->start],
2615 strerror(-err), -err);
2617 slconn->start += cmd_len;
2618 slconn->length -= cmd_len;
2620 if (!slconn->length)
2625 ERR("Failed in event handler - SLC Disconnect");
2626 _bt_ag_set_headset_state(bt_ag_info,
2627 HEADSET_STATE_DISCONNECTED);
2631 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
2632 const gchar *object_path)
2636 bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
2637 struct sockaddr_remote address;
2638 socklen_t address_len;
2640 INFO_C("Connected [AG role]");
2641 bt_ag_info->rfcomm = NULL;
2642 bt_ag_info->slc = NULL;
2643 bt_ag_info->hfp_active = TRUE;
2644 bt_ag_info->vr_blacklisted = FALSE;
2645 bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
2646 bt_ag_info->sco_server_started = FALSE;
2647 __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
2649 bt_ag_info->path = device_path;
2650 DBG("device_path = [%s]", device_path);
2652 address_len = sizeof(address);
2653 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2654 ERR("BD_ADDR is NULL");
2656 DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
2657 bt_ag_info->fd = fd;
2658 bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
2659 flags = g_io_channel_get_flags(bt_ag_info->io_chan);
2661 flags &= ~G_IO_FLAG_NONBLOCK;
2662 flags &= G_IO_FLAG_MASK;
2663 g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
2664 g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
2665 g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
2667 bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
2669 bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2670 __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
2671 address.remote_bdaddr.b);
2673 #if defined(TIZEN_SUPPORT_DUAL_HF)
2674 bt_ag_info->is_companion_device =
2675 __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
2678 DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
2680 if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
2681 DBG("HSP connection completed");
2682 _bt_ag_set_headset_state(bt_ag_info,
2683 HEADSET_STATE_CONNECTED);
2685 DBG("HFP connection connecting");
2686 _bt_ag_set_headset_state(bt_ag_info,
2687 HEADSET_STATE_CONNECTING);
2690 __bt_ag_agent_start_watch(bt_ag_info);
2692 bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
2693 bt_ag_info->slc->speaker_gain = 15;
2694 bt_ag_info->slc->microphone_gain = 15;
2695 bt_ag_info->slc->is_nrec = TRUE;
2700 static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
2709 fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
2712 ERR("Unable to open VR blacklist file");
2716 fseek(fp, 0, SEEK_END);
2719 ERR("size is not a positive number");
2726 buffer = g_malloc0(sizeof(char) * size);
2727 if (buffer == NULL) {
2728 ERR("g_malloc0 is failed");
2732 result = fread((char *)buffer, 1, size, fp);
2734 if (result != size) {
2740 token = strtok_r(buffer, "=", &saveptr);
2741 if (token == NULL) {
2746 while ((token = strtok_r(NULL, ",", &saveptr))) {
2747 if (strlen(token) > 8)
2749 if (0 == g_strcmp0(token, lap_addr)) {
2750 INFO("Voice Recognition blacklisted");
2759 static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
2761 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2762 sco_open_timer_id = 0;
2763 DBG("sco_open_request (%d)", sco_open_request);
2765 if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
2766 bt_ag_slconn_t *slconn = bt_ag_info->slc;
2768 INFO("try to open SCO");
2769 sco_open_request = FALSE;
2771 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2772 (slconn && (slconn->hs_features &
2773 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
2774 switch (bt_ag_info->codec_info.final_codec) {
2775 case BT_CVSD_CODEC_ID:
2776 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
2777 __bt_ag_sco_connect(bt_ag_info);
2779 case BT_MSBC_CODEC_ID:
2780 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
2781 __bt_ag_sco_connect(bt_ag_info);
2784 __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
2788 __bt_ag_sco_connect(bt_ag_info);
2795 * Service level connection complete
2796 * indication and state management
2798 void _bt_ag_slconn_complete(bt_ag_info_t *hs)
2800 char lap_address[BT_LOWER_ADDRESS_LENGTH];
2802 DBG("HFP Service Level Connection established\n");
2804 /* Check device Voice Recognition blacklist status */
2805 g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
2806 hs->vr_blacklisted =
2807 __bt_ag_agent_is_device_vr_blacklisted(lap_address);
2809 if (sco_open_timer_id > 0) {
2810 g_source_remove(sco_open_timer_id);
2811 sco_open_timer_id = 0;
2814 sco_open_request = FALSE;
2815 sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
2816 __bt_sco_open_delay_timeout_cb, hs);
2818 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2821 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
2824 g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
2825 g_io_channel_unref(hs->io_chan);
2829 __bt_ag_close_sco(hs);
2830 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2833 __bt_ag_agent_remove_watch(&hs->watch_id);
2835 _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
2839 static GQuark __bt_ag_agent_error_quark(void)
2843 static GQuark quark = 0;
2845 quark = g_quark_from_static_string("ag-agent");
2851 static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
2854 ERR("error[%d]\n", error);
2857 case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
2858 return g_error_new(BT_AG_AGENT_ERROR, error,
2859 BT_ERROR_NOT_AVAILABLE);
2860 case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
2861 return g_error_new(BT_AG_AGENT_ERROR, error,
2862 BT_ERROR_NOT_CONNECTED);
2863 case BT_HFP_AGENT_ERROR_BUSY:
2864 return g_error_new(BT_AG_AGENT_ERROR, error,
2866 case BT_HFP_AGENT_ERROR_INVALID_PARAM:
2867 return g_error_new(BT_AG_AGENT_ERROR, error,
2868 BT_ERROR_INVALID_PARAM);
2869 case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
2870 return g_error_new(BT_AG_AGENT_ERROR, error,
2871 BT_ERROR_ALREADY_EXSIST);
2872 case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
2873 return g_error_new(BT_AG_AGENT_ERROR, error,
2874 BT_ERROR_ALREADY_CONNECTED);
2875 case BT_HFP_AGENT_ERROR_NO_MEMORY:
2876 return g_error_new(BT_AG_AGENT_ERROR, error,
2877 BT_ERROR_NO_MEMORY);
2878 case BT_HFP_AGENT_ERROR_I_O_ERROR:
2879 return g_error_new(BT_AG_AGENT_ERROR, error,
2880 BT_ERROR_I_O_ERROR);
2881 case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
2882 return g_error_new(BT_AG_AGENT_ERROR, error,
2883 BT_ERROR_OPERATION_NOT_AVAILABLE);
2884 case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
2885 return g_error_new(BT_AG_AGENT_ERROR, error,
2887 case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
2888 return g_error_new(BT_AG_AGENT_ERROR, error,
2890 case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
2891 return g_error_new(BT_AG_AGENT_ERROR, error,
2892 BT_ERROR_NO_CALL_LOG);
2893 case BT_HFP_AGENT_ERROR_INTERNAL:
2895 return g_error_new(BT_AG_AGENT_ERROR, error,
2901 static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
2905 for (l = active_devices ; l; l = l->next) {
2906 bt_ag_info_t *data = l->data;
2907 if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
2909 if (g_strcmp0(data->path, device_path) == 0) {
2910 INFO("Active device found");
2915 INFO("Active device not found");
2919 static void __bt_ag_agent_method(GDBusConnection *connection,
2920 const gchar *sender,
2921 const gchar *object_path,
2922 const gchar *interface_name,
2923 const gchar *method_name,
2924 GVariant *parameters,
2925 GDBusMethodInvocation *invocation,
2930 INFO("method %s", method_name);
2931 INFO("object_path %s", object_path);
2932 int ret = BT_HFP_AGENT_ERROR_NONE;
2934 const gchar *device_path = NULL;
2936 if (g_strcmp0(method_name, "NewConnection") == 0) {
2940 GUnixFDList *fd_list;
2941 GVariant *options = NULL;
2942 int device_count = 0;
2944 device_count = g_slist_length(active_devices);
2946 INFO("device_count %d", device_count);
2948 if (device_count >= MAX_CONNECTED_DEVICES) {
2949 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2953 g_variant_get(parameters, "(oha{sv})",
2954 &device_path, &index, &options);
2955 #if defined(TIZEN_SUPPORT_DUAL_HF)
2957 __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
2958 INFO("not allow to connect 2nd HF connection");
2959 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2963 msg = g_dbus_method_invocation_get_message(invocation);
2964 fd_list = g_dbus_message_get_unix_fd_list(msg);
2965 if (fd_list == NULL) {
2966 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2970 fd = g_unix_fd_list_get(fd_list, index, NULL);
2972 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2976 DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
2978 if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
2979 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2983 g_dbus_method_invocation_return_value(invocation, NULL);
2984 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
2987 g_variant_get(parameters, "(o)", &device_path);
2988 INFO("device_path %s", device_path);
2990 for (l = active_devices; l; l = l->next) {
2991 bt_ag_info_t *data = l->data;
2993 INFO("data->path %s", data->path);
2994 if (g_strcmp0(data->path, device_path) == 0) {
2995 if (!__bt_ag_agent_connection_release(data)) {
2996 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2999 INFO_C("Disconnected [AG role] [Terminated by local host]");
3000 g_dbus_method_invocation_return_value(invocation, NULL);
3003 } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
3005 gchar *address = NULL;
3006 g_variant_get(parameters, "(&s&s)", &path, &address);
3007 /*local_addr = malloc(strlen(address));
3008 memcpy(local_addr, address, strlen(address));*/
3010 DBG("Sender = %s, Application path = %s\n", sender, path);
3011 ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
3016 local_addr = g_strdup(address);
3017 DBG("Address = %s\n", local_addr);
3018 g_dbus_method_invocation_return_value(invocation, NULL);
3019 } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
3021 g_variant_get(parameters, "(&s)", &path);
3023 DBG("Application path = %s\n", path);
3024 DBG("Sender = %s\n", sender);
3026 ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
3030 g_dbus_method_invocation_return_value(invocation, NULL);
3031 } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
3033 gchar *number = NULL;
3036 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3038 DBG("Application path = %s", path);
3039 DBG_SECURE("Phone number = %s", number);
3040 DBG("Call id = %d", call_id);
3042 DBG("Sender = %s", sender);
3044 ret = _bt_hfp_incoming_call(path, number, call_id, sender);
3047 g_dbus_method_invocation_return_value(invocation, NULL);
3048 } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
3050 gchar *number = NULL;
3053 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3055 DBG("Application path = %s", path);
3056 DBG_SECURE("Phone number = %s", number);
3057 DBG("Call id = %d", call_id);
3059 DBG("Sender = %s", sender);
3061 ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
3064 g_dbus_method_invocation_return_value(invocation, NULL);
3065 } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
3067 gchar *number = NULL;
3072 g_variant_get(parameters, "(&s&sii)",
3073 &path, &number, &status, &call_id);
3074 DBG("Application path = %s\n", path);
3075 DBG_SECURE("Number = %s\n", number);
3076 DBG("Status = %d\n", status);
3077 DBG("Call id = %d\n", call_id);
3078 DBG("Sender = %s\n", sender);
3080 ret = _bt_hfp_change_call_status(path,
3081 number, status, call_id, sender);
3083 if (_bt_hfp_is_call_exist() == FALSE) {
3084 for (l = active_devices; l; l = l->next) {
3085 bt_ag_info_t *data = l->data;
3087 if (data->state == HEADSET_STATE_ON_CALL) {
3088 __bt_ag_close_sco(data);
3089 _bt_ag_set_headset_state(data,
3090 HEADSET_STATE_CONNECTED);
3097 g_dbus_method_invocation_return_value(invocation, NULL);
3098 } else if (g_strcmp0(method_name, "GetProperties") == 0) {
3099 GVariantBuilder *builder;
3101 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3104 gchar *codec = g_strdup("codec");
3105 gchar *nrec = g_strdup("nrec");
3107 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3109 g_variant_builder_add(builder, "{sv}",
3110 codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
3111 g_variant_builder_add(builder, "{sv}",
3112 nrec, g_variant_new("b", bt_ag_info->nrec_status));
3114 var_data = g_variant_new("(a{sv})", builder);
3115 g_variant_builder_unref(builder);
3116 g_dbus_method_invocation_return_value(invocation, var_data);
3121 } else if (g_strcmp0(method_name, "Disconnect") == 0) {
3122 char hdset_address[18] = { 0, };
3125 for (l = active_devices; l; l = l->next) {
3126 bt_ag_info_t *data = l->data;
3128 __bt_convert_addr_type_to_rev_string(hdset_address,
3129 (unsigned char *)data->remote_addr);
3131 DBG("Disconnect Headset %s, %s\n",
3132 hdset_address, data->path);
3133 _bt_ag_set_headset_state(data,
3134 HEADSET_STATE_DISCONNECTED);
3136 g_dbus_method_invocation_return_value(invocation, NULL);
3137 } else if (g_strcmp0(method_name, "IsConnected") == 0) {
3138 gboolean is_connected = FALSE;
3141 for (l = active_devices; l; l = l->next) {
3142 bt_ag_info_t *data = l->data;
3144 if (data->state == HEADSET_STATE_CONNECTED)
3145 is_connected = TRUE;
3147 DBG("is_connected : %s",
3148 is_connected ? "Connected" : "Disconnected");
3150 g_dbus_method_invocation_return_value(invocation,
3151 g_variant_new("(b)", is_connected));
3152 } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
3155 if (0 == g_slist_length(active_devices)) {
3156 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3160 if (ag.ring_timer) {
3161 DBG("IndicateCall received when already indicating");
3162 g_dbus_method_invocation_return_value(invocation, NULL);
3165 for (l = active_devices; l; l = l->next) {
3166 bt_ag_info_t *data = l->data;
3168 if (data->state >= HEADSET_STATE_CONNECTED)
3169 _bt_ag_send_at(data, "\r\nRING\r\n");
3172 __bt_ring_timer_cb(NULL);
3173 ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
3174 __bt_ring_timer_cb, NULL);
3175 g_dbus_method_invocation_return_value(invocation, NULL);
3176 } else if (g_strcmp0(method_name, "CancelCall") == 0) {
3177 if (0 == g_slist_length(active_devices)) {
3178 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3182 if (ag.ring_timer) {
3183 g_source_remove(ag.ring_timer);
3186 DBG("Got CancelCall method call but no call is active");
3188 g_dbus_method_invocation_return_value(invocation, NULL);
3189 } else if (g_strcmp0(method_name, "Play") == 0) {
3190 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3191 bt_ag_slconn_t *slconn = NULL;
3194 slconn = bt_ag_info->slc;
3196 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3200 #ifndef __TIZEN_OPEN__
3203 if (slconn && FALSE == slconn->is_voice_recognition_running &&
3204 mdm_get_service() == MDM_RESULT_SUCCESS) {
3205 mode = mdm_get_allow_bluetooth_outgoing_call();
3206 mdm_release_service();
3208 if (mode == MDM_RESTRICTED) {
3209 ERR("[MDM] Not allow the outgoing call");
3210 ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
3217 switch (bt_ag_info->state) {
3218 case HEADSET_STATE_CONNECTING:
3219 case HEADSET_STATE_DISCONNECTED:
3220 ERR("HEADSET_STATE ERROR");
3221 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3223 case HEADSET_STATE_CONNECTED:
3225 case HEADSET_STATE_PLAY_IN_PROGRESS:
3226 ERR("Play In Progress");
3227 ret = BT_HFP_AGENT_ERROR_BUSY;
3235 if (sco_open_timer_id > 0) {
3236 INFO("SCO open delay");
3237 sco_open_request = TRUE;
3238 g_dbus_method_invocation_return_value(invocation, NULL);
3242 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
3243 (slconn && (slconn->hs_features &
3244 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
3245 switch (bt_ag_info->codec_info.final_codec) {
3246 case BT_CVSD_CODEC_ID:
3247 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
3248 ret = __bt_ag_sco_connect(bt_ag_info);
3250 case BT_MSBC_CODEC_ID:
3251 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
3252 ret = __bt_ag_sco_connect(bt_ag_info);
3255 ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
3259 ret = __bt_ag_sco_connect(bt_ag_info);
3265 sco_owner = g_strdup(sender);
3267 g_dbus_method_invocation_return_value(invocation, NULL);
3269 name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
3270 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
3271 __bt_ag_name_owner_changed_cb, NULL, NULL);
3272 } else if (g_strcmp0(method_name, "Stop") == 0) {
3275 for (l = active_devices; l; l = l->next) {
3276 bt_ag_info_t *data = l->data;
3278 if (data->state > HEADSET_STATE_CONNECTED) {
3279 __bt_ag_close_sco(data);
3280 _bt_ag_set_headset_state(data,
3281 HEADSET_STATE_CONNECTED);
3285 g_dbus_method_invocation_return_value(invocation, NULL);
3286 } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
3287 gboolean is_playing = FALSE;
3290 for (l = active_devices; l; l = l->next) {
3291 bt_ag_info_t *data = l->data;
3293 if (data->state == HEADSET_STATE_ON_CALL)
3296 DBG("is_playing : %s", is_playing ? "Playing" : "Not Playing");
3298 g_dbus_method_invocation_return_value(invocation,
3299 g_variant_new("(b)", is_playing));
3300 } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
3301 bt_ag_slconn_t *slconn = NULL;
3302 guint16 gain_value = 0;
3303 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3305 if (bt_ag_info == NULL) {
3306 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3310 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3311 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3315 slconn = bt_ag_info->slc;
3317 gain_value = (guint16) slconn->speaker_gain;
3319 g_dbus_method_invocation_return_value(invocation,
3320 g_variant_new("(q)", gain_value));
3321 } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
3323 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3325 g_variant_get(parameters, "(q)", &gain);
3326 DBG("Speaker gain = %d\n", gain);
3328 if (bt_ag_info == NULL) {
3329 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3333 ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
3336 g_dbus_method_invocation_return_value(invocation, NULL);
3337 } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
3338 bt_ag_slconn_t *slconn = NULL;
3339 guint16 gain_value = 0;
3340 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3342 if (bt_ag_info == NULL) {
3343 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3347 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3348 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3352 slconn = bt_ag_info->slc;
3354 gain_value = (guint16) slconn->microphone_gain;
3356 g_dbus_method_invocation_return_value(invocation,
3357 g_variant_new("(q)", gain_value));
3358 } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
3360 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3362 g_variant_get(parameters, "(q)", &gain);
3363 DBG("Microphone gain = %d\n", gain);
3365 if (bt_ag_info == NULL) {
3366 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3370 ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
3373 g_dbus_method_invocation_return_value(invocation, NULL);
3374 } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
3375 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3376 if (bt_ag_info == NULL) {
3377 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3381 bt_ag_slconn_t *slconn = bt_ag_info->slc;
3384 g_variant_get(parameters, "(b)", &enable);
3385 DBG("VoiceDail enable = %d\n", enable);
3387 if ((slconn && !(slconn->hs_features &
3388 BT_HF_FEATURE_VOICE_RECOGNITION)))
3389 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3390 else if (bt_ag_info->vr_blacklisted)
3391 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3393 ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
3396 slconn->is_voice_recognition_running = enable;
3400 g_dbus_method_invocation_return_value(invocation, NULL);
3401 } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
3403 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3404 if (bt_ag_info == NULL) {
3405 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3409 g_variant_get(parameters, "(&s)", &cmd);
3411 ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
3415 DBG("vendor cmd = %s", cmd);
3417 ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
3420 g_dbus_method_invocation_return_value(invocation, NULL);
3421 } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
3422 DBG("Already pass dbus SMACK for bt-service::platform");
3423 /* Return success */
3424 g_dbus_method_invocation_return_value(invocation, NULL);
3431 err = __bt_ag_agent_set_error(ret);
3432 g_dbus_method_invocation_return_gerror(invocation, err);
3437 static const GDBusInterfaceVTable method_table = {
3438 __bt_ag_agent_method,
3443 static GDBusNodeInfo *__bt_ag_create_method_node_info
3444 (const gchar *introspection_data)
3447 GDBusNodeInfo *node_info = NULL;
3449 if (introspection_data == NULL)
3452 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
3455 ERR("Unable to create node: %s", err->message);
3456 g_clear_error(&err);
3461 static GDBusConnection *__bt_ag_get_gdbus_connection(void)
3467 if (ag_dbus_conn == NULL)
3468 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
3470 if (!ag_dbus_conn) {
3472 ERR("Unable to connect to dbus: %s", err->message);
3473 g_clear_error(&err);
3479 return ag_dbus_conn;
3482 static gboolean __bt_ag_register_profile_methods(void)
3485 GError *error = NULL;
3487 GDBusNodeInfo *node_info = NULL;
3490 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
3492 G_BUS_NAME_OWNER_FLAGS_NONE,
3496 DBG("owner_id is [%d]", owner_id);
3498 node_info = __bt_ag_create_method_node_info(
3499 ag_agent_bluez_introspection_xml);
3500 if (node_info == NULL)
3503 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3504 DBG("path is [%s]", path);
3506 hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3507 node_info->interfaces[0],
3509 NULL, NULL, &error);
3510 if (hf_bluez_id == 0) {
3511 ERR("Failed to register: %s", error->message);
3512 g_error_free(error);
3514 g_dbus_node_info_unref(node_info);
3519 /* Ag register profile methods for HSP*/
3521 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
3522 DBG("path is [%s]", path);
3524 hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3525 node_info->interfaces[0],
3527 NULL, NULL, &error);
3528 if (hs_bluez_id == 0) {
3529 ERR("Failed to register: %s", error->message);
3530 g_error_free(error);
3532 g_dbus_node_info_unref(node_info);
3536 g_dbus_node_info_unref(node_info);
3538 node_info = __bt_ag_create_method_node_info
3539 (ag_agent_app_introspection_xml);
3540 if (node_info == NULL)
3543 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3544 DBG("path is [%s]", path);
3546 app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3547 node_info->interfaces[0],
3549 NULL, NULL, &error);
3551 ERR("Failed to register: %s", error->message);
3552 g_error_free(error);
3554 g_dbus_node_info_unref(node_info);
3558 g_dbus_node_info_unref(node_info);
3564 static void __bt_ag_unregister_profile_methods(void)
3568 if (hf_bluez_id > 0) {
3569 g_dbus_connection_unregister_object(ag_dbus_conn,
3574 if (hs_bluez_id > 0) {
3575 g_dbus_connection_unregister_object(ag_dbus_conn,
3581 g_dbus_connection_unregister_object(ag_dbus_conn,
3587 static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
3588 const gchar *path, const gchar *interface)
3590 return (service_gproxy) ? service_gproxy :
3591 __bt_ag_gdbus_init_service_proxy(service,
3595 static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
3596 char *profile_uuid, const char* profile_name)
3601 GError *error = NULL;
3602 GVariantBuilder *builder;
3604 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3605 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3610 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3612 g_variant_builder_add(builder, "{sv}",
3613 "Name", g_variant_new("s",
3615 g_variant_builder_add(builder, "{sv}",
3616 "Version", g_variant_new("q", profile_version));
3617 /*g_variant_builder_add(builder, "{sv}",
3618 "Role", g_variant_new("s","client"));*/
3619 if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
3620 g_variant_builder_add(builder, "{sv}",
3621 "features", g_variant_new("q", ag.sdp_features));
3624 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3625 g_variant_new("(osa{sv})", path,
3626 profile_uuid, builder),
3627 G_DBUS_CALL_FLAGS_NONE, -1,
3629 g_variant_builder_unref(builder);
3630 /* set the name and role for the profile*/
3632 /* dBUS-RPC is failed */
3633 ERR("dBUS-RPC is failed");
3635 if (error != NULL) {
3636 /* dBUS gives error cause */
3637 ERR("D-Bus API failure: errCode[%x], message[%s]",
3638 error->code, error->message);
3640 g_clear_error(&error);
3645 g_variant_unref(ret);
3652 static void __bt_ag_agent_unregister(gchar *path)
3657 GError *error = NULL;
3659 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3660 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3665 ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
3666 g_variant_new("(o)", path),
3667 G_DBUS_CALL_FLAGS_NONE, -1,
3670 /* set the name and role for the profile*/
3672 /* dBUS-RPC is failed */
3673 ERR("dBUS-RPC is failed");
3675 if (error != NULL) {
3676 /* dBUS gives error cause */
3677 ERR("D-Bus API failure: errCode[%x], message[%s]",
3678 error->code, error->message);
3680 g_clear_error(&error);
3684 g_variant_unref(ret);
3694 static void __bt_ag_agent_battery_status_cb(keynode_t *node)
3696 int batt = vconf_keynode_get_int(node);
3698 _bt_hfp_set_property_value("BatteryBarsChanged", batt);
3701 static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
3703 int signal_bar = vconf_keynode_get_int(node);
3705 BT_CHECK_SIGNAL_STRENGTH(signal_bar);
3706 _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
3709 #ifdef TIZEN_FEATURE_BT_LUNAR_DEVICE
3710 static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
3712 gboolean status = vconf_keynode_get_bool(node);
3714 DBG("status = %d", status);
3716 if (status == TRUE) {
3717 for (l = active_devices; l; l = l->next) {
3718 bt_ag_info_t *data = l->data;
3719 _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
3725 static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
3727 int service = vconf_keynode_get_int(node);
3728 bt_hfp_agent_network_registration_status_t network_service;
3732 DBG("Current Signal Level = [%d] \n", service);
3735 case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
3736 case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
3737 case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
3745 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
3747 ERR("Get roaming status failed err = %d\n", ret);
3751 if (roam_status == 0 && service == 1)
3752 network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
3753 else if (roam_status == 1 && service == 1)
3754 network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
3756 network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
3758 _bt_hfp_set_property_value("RegistrationChanged", network_service);
3761 static void __bt_ag_agent_subscribe_vconf_updates(void)
3767 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3768 (void *)__bt_ag_agent_battery_status_cb, NULL);
3770 ERR("Subsrciption to battery status failed err = [%d]\n", ret);
3772 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
3773 (void *)__bt_ag_agent_network_signal_status_cb, NULL);
3775 ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
3777 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3778 (void *)__bt_ag_agent_network_register_status_cb, NULL);
3780 ERR("Subsrciption to network failed err = [%d]\n", ret);
3782 #ifdef TIZEN_FEATURE_BT_LUNAR_DEVICE
3783 ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
3784 (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
3786 ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
3791 static void __bt_ag_agent_release_vconf_updates(void)
3797 ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3798 (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
3800 ERR("vconf_ignore_key_changed failed\n");
3802 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
3803 (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
3805 ERR("vconf_ignore_key_changed failed\n");
3807 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3808 (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
3810 ERR("vconf_ignore_key_changed failed\n");
3813 static gboolean __bt_ag_agent_send_subscriber_number_changed(
3816 const char *property = g_strdup("SubscriberNumberChanged");
3820 DBG("Number is %s", number);
3822 if (!_bt_hfp_set_property_name(property, number)) {
3823 DBG("Error- set property for subscriber no change - ERROR\n");
3824 g_free((void *)property);
3827 g_free((void *)property);
3831 static void __bt_ag_agent_sigterm_handler(int signo)
3836 ERR_C("***** Signal handler came with signal %d *****", signo);
3838 for (l = active_devices ; l; l = l->next) {
3839 bt_ag_info_t *data = l->data;
3840 if (!__bt_ag_agent_connection_release(data))
3841 ERR("__bt_ag_agent_connection_release failed");
3844 g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
3847 g_main_loop_quit(gmain_loop);
3851 INFO("Terminating AG agent");
3855 if (signo == SIGTERM)
3858 for (i = 0; i < BT_AG_SIG_NUM; i++)
3859 sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
3864 static void __bt_ag_agent_tel_cb(TapiHandle *handle,
3869 TelSimMsisdnList_t *number;
3870 gchar *subscriber_number;
3872 ERR("*********** result = %d", result);
3874 if (result == TAPI_API_SIM_LOCKED ||
3875 result == TAPI_API_SIM_NOT_INITIALIZED ||
3876 result == TAPI_API_SERVICE_NOT_READY) {
3877 DBG("initializing the tapi event for SIM status");
3878 __bt_ag_agent_reg_sim_event(handle, user_data);
3885 number = (TelSimMsisdnList_t *)data;
3886 subscriber_number = g_strdup(number->list[0].num);
3887 __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
3888 g_free(subscriber_number);
3891 static void __bt_ag_agent_on_noti_sim_status(TapiHandle *handle,
3892 const char *noti_id, void *data, void *user_data)
3894 TelSimCardStatus_t *status = data;
3897 DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
3899 if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
3900 __bt_ag_agent_dereg_sim_event(handle);
3901 tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
3903 if (tapi_result != TAPI_API_SUCCESS)
3904 ERR("Fail to get sim info: %d", tapi_result);
3908 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data)
3911 ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
3912 __bt_ag_agent_on_noti_sim_status, user_data);
3914 if (ret != TAPI_API_SUCCESS)
3915 ERR("event register failed(%d)", ret);
3918 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle)
3921 ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
3923 if (ret != TAPI_API_SUCCESS)
3924 ERR("event deregister failed(%d)", ret);
3927 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
3928 const gchar *sender_name,
3929 const gchar *object_path,
3930 const gchar *interface_name,
3931 const gchar *signal_name,
3932 GVariant *parameters,
3936 char *name_owner = NULL;
3937 char *old_owner = NULL;
3938 char *new_owner = NULL;
3940 if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
3943 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
3945 _bt_hfp_release_all_calls_by_sender(name_owner);
3947 if (sco_owner == NULL)
3950 if (strcasecmp(name_owner, sco_owner) == 0) {
3951 if (name_owner_sig_id != -1)
3952 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
3954 name_owner_sig_id = -1;
3958 for (l = active_devices ; l; l = l->next) {
3959 bt_ag_info_t *data = l->data;
3962 __bt_ag_close_sco(data);
3963 _bt_ag_set_headset_state(data,
3964 HEADSET_STATE_CONNECTED);
3971 static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
3972 const gchar *sender_name,
3973 const gchar *object_path,
3974 const gchar *interface_name,
3975 const gchar *signal_name,
3976 GVariant *parameters,
3981 GVariant *optional_param = NULL;
3983 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
3985 g_variant_get(parameters, "(&o@a{sa{sv}})",
3986 &path, &optional_param);
3989 g_variant_unref(optional_param);
3990 ERR("Invalid adapter path");
3994 INFO("Adapter Path = [%s]", path);
3995 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
3996 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3997 __bt_ag_agent_register(path, hfp_ver,
3998 HFP_AG_UUID, "Hands-Free Audio Gateway");
4000 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4001 __bt_ag_agent_register(path, hsp_ver,
4002 HSP_AG_UUID, "Headset Audio Gateway");
4004 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
4005 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
4008 g_variant_unref(optional_param);
4009 ERR("Invalid adapter path");
4013 INFO("Adapter Path = [%s]", path);
4014 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4015 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4016 __bt_ag_agent_unregister(path);
4018 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4019 __bt_ag_agent_unregister(path);
4024 g_variant_unref(optional_param);
4029 static void __bt_ag_agent_dbus_deinit(void)
4032 if (service_gproxy) {
4033 g_object_unref(service_gproxy);
4034 service_gproxy = NULL;
4038 g_object_unref(app_gproxy);
4043 __bt_ag_unregister_profile_methods();
4045 if (owner_sig_id != -1)
4046 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4049 if (name_owner_sig_id != -1)
4050 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4052 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4053 if (media_sig_id != -1)
4054 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4057 if (media_state_sig_id != -1)
4058 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4059 media_state_sig_id);
4061 name_owner_sig_id = -1;
4065 g_object_unref(ag_dbus_conn);
4066 ag_dbus_conn = NULL;
4071 static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
4074 GDBusProxy *manager_proxy = NULL;
4075 GVariant *result = NULL;
4076 char *adapter_path = NULL;
4079 return BT_HFP_AGENT_ERROR_INTERNAL;
4081 manager_proxy = g_dbus_proxy_new_sync(conn,
4082 G_DBUS_PROXY_FLAGS_NONE, NULL,
4085 BT_MANAGER_INTERFACE,
4088 if (!manager_proxy) {
4089 ERR("Unable to create proxy: %s", err->message);
4093 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
4094 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
4097 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
4099 ERR("Fail to get DefaultAdapter");
4104 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
4105 ERR("Incorrect result\n");
4109 g_variant_get(result, "(&o)", &adapter_path);
4111 if (adapter_path == NULL ||
4112 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
4113 ERR("Adapter path is inproper\n");
4118 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
4120 g_variant_unref(result);
4121 g_object_unref(manager_proxy);
4126 g_clear_error(&err);
4129 g_variant_unref(result);
4132 g_object_unref(manager_proxy);
4134 return BT_HFP_AGENT_ERROR_INTERNAL;
4138 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4139 void _bt_ag_agent_check_transport_state(void)
4143 if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
4147 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
4148 G_DBUS_PROXY_FLAGS_NONE, NULL,
4149 "org.PulseAudio2", A2DP_SOURCE_ENDPOINT,
4150 BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
4154 ERR("Unable to create proxy: %s", err->message);
4155 g_clear_error(&err);
4159 INFO_C("SuspendMedia initiated");
4161 g_dbus_proxy_call(proxy,
4162 "SuspendMedia", NULL,
4163 G_DBUS_CALL_FLAGS_NONE, 2000,
4165 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4171 static void __bt_ag_agent_transport_state_update(const char *value)
4174 if (!g_strcmp0(value, "idle"))
4175 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4176 else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
4177 transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
4179 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4181 INFO_C("transport_state %d", transport_state);
4184 static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
4185 const gchar *sender_name,
4186 const gchar *object_path,
4187 const gchar *interface_name,
4188 const gchar *signal_name,
4189 GVariant *parameters,
4194 GVariant *dict_param = NULL;
4195 GVariant *optional_param = NULL;
4197 if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
4198 if (g_strcmp0(g_variant_get_type_string(parameters),
4200 ERR("Incorrect parameters\n");
4204 g_variant_get(parameters, "(&s@a{sv}@as)",
4205 &inter, &dict_param, &optional_param);
4206 if (dict_param && (!g_strcmp0(inter,
4207 BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
4208 GVariantIter *iter = NULL;
4209 const gchar *key = NULL;
4210 GVariant *value_var = NULL;
4211 gchar *value = NULL;
4212 g_variant_get(dict_param, "a{sv}", &iter);
4213 while (g_variant_iter_loop(
4214 iter, "{sv}", &key, &value_var)) {
4216 if (g_strcmp0(key, "State") == 0) {
4217 value = (gchar *)g_variant_get_string(
4220 DBG("value %s", value);
4221 __bt_ag_agent_transport_state_update(value);
4225 g_variant_iter_free(iter);
4226 g_variant_unref(dict_param);
4228 } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
4229 char *profile_uuid = NULL;
4232 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
4233 if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
4234 (state == BT_PROFILE_STATE_DISCONNECTED)) {
4235 DBG("Updating the transport state");
4236 __bt_ag_agent_transport_state_update("Disconnect");
4241 g_variant_unref(dict_param);
4244 g_variant_unref(optional_param);
4249 static void __bt_ag_agent_dbus_init(void)
4253 if (__bt_ag_get_gdbus_connection() == NULL) {
4254 ERR("Error in creating the gdbus connection\n");
4257 if (!__bt_ag_register_profile_methods()) {
4258 ERR("Error in HFP / HSP register_profile_methods\n");
4262 if (!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
4264 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4265 __bt_ag_agent_register(path, hfp_ver,
4266 HFP_AG_UUID, "Hands-Free Audio Gateway");
4268 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4269 __bt_ag_agent_register(path, hsp_ver,
4270 HSP_AG_UUID, "Headset Audio Gateway");
4273 owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4274 NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
4275 __bt_ag_agent_filter_cb, NULL, NULL);
4276 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4277 media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4278 NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
4279 NULL, 0, __bt_ag_agent_media_filter_cb,
4282 media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4283 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
4284 NULL, 0, __bt_ag_agent_media_filter_cb,
4287 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4293 static uint32_t __bt_ag_agent_get_ag_features(void)
4296 uint32_t ag_features = BT_AG_FEATURE_EC_AND_NR |
4297 BT_AG_FEATURE_REJECT_CALL |
4298 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4299 BT_AG_FEATURE_THREE_WAY_CALL |
4300 #ifndef TIZEN_FEATURE_BT_KIRAN_DEVICE
4301 BT_AG_FEATURE_VOICE_RECOGNITION |
4303 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4306 #if defined(TIZEN_FEATURE_BT_HFP_AG)
4307 hfp_ver = HFP_VERSION_1_6;
4309 hfp_ver = HFP_VERSION_1_5;
4311 hsp_ver = HSP_VERSION_1_2;
4313 if (hfp_ver == HFP_VERSION_1_6)
4314 ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
4318 void *__bt_ag_agent_telephony_init(void *arg)
4322 uint32_t ag_features = *((uint32_t *)arg);
4324 INFO_C("Initializing the telephony info");
4326 _bt_hfp_initialize_telephony_manager(ag_features);
4327 __bt_ag_agent_subscribe_vconf_updates();
4329 tapi_handle = tel_init(NULL);
4330 tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
4332 if (tapi_result != TAPI_API_SUCCESS)
4333 ERR("Fail to get sim info: %d", tapi_result);
4340 uint32_t ag_features;
4341 struct sigaction sa;
4342 pthread_t thread_id;
4344 INFO_C("Starting Bluetooth AG agent");
4346 ag_features = __bt_ag_agent_get_ag_features();
4348 ag.sdp_features = (uint16_t) ag_features & 0x1F;
4350 if (hfp_ver == HFP_VERSION_1_6 && wbs_en == TRUE)
4351 ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
4353 memset(&sa, 0, sizeof(sa));
4354 sa.sa_flags = SA_NOCLDSTOP;
4355 sa.sa_handler = __bt_ag_agent_sigterm_handler;
4357 for (i = 0; i < BT_AG_SIG_NUM; i++)
4358 sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
4360 gmain_loop = g_main_loop_new(NULL, FALSE);
4362 if (gmain_loop == NULL) {
4363 ERR("GMainLoop create failed");
4364 return EXIT_FAILURE;
4367 __bt_ag_agent_dbus_init();
4368 if (pthread_create(&thread_id, NULL,
4369 (void *)&__bt_ag_agent_telephony_init,
4370 &ag_features) < 0) {
4371 ERR("pthread_create() is failed");
4372 return EXIT_FAILURE;
4375 if (pthread_detach(thread_id) < 0)
4376 ERR("pthread_detach() is failed");
4378 g_main_loop_run(gmain_loop);
4382 tel_deinit(tapi_handle);
4384 __bt_ag_agent_dbus_deinit();
4385 _bt_hfp_deinitialize_telephony_manager();
4386 __bt_ag_agent_release_vconf_updates();
4388 if (remote_dev_path)
4389 g_free(remote_dev_path);
4392 g_main_loop_unref(gmain_loop);
4394 INFO_C("Terminating Bluetooth AG agent");