4 * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Chethan T N <chethan.tn@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
9 * Rakesh MK <rakesh.mk@samsung.com>
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
28 #include <gio/gunixfdlist.h>
29 #include <bundle_internal.h>
30 #include "bluetooth-ag-agent.h"
31 #include "bluetooth-ag-handler.h"
32 #include "bluetooth-agent-profile.h"
34 #include <TapiUtility.h>
36 #include <ITapiModem.h>
37 #include <TelNetwork.h>
40 #include <system_info.h>
45 static GMainLoop *gmain_loop = NULL;
46 static GDBusProxy *service_gproxy;
47 static int owner_sig_id = -1;
48 static int name_owner_sig_id = -1;
49 GDBusConnection *ag_dbus_conn = NULL;
50 gchar *remote_dev_path = NULL;
54 static TapiHandle *tapi_handle;
55 extern wbs_options wbs_opts;
56 GSList *active_devices = NULL;
57 static gchar *local_addr = NULL;
58 static GDBusProxy *app_gproxy;
59 static gboolean call_launch_requested = FALSE;
60 static gchar* sco_owner = NULL;
61 static guint sco_open_timer_id = 0;
62 static gboolean sco_open_request = FALSE;
63 static guint hf_bluez_id;
64 static guint hs_bluez_id;
66 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
67 static int media_sig_id = -1;
68 static int media_state_sig_id = -1;
69 static bt_ag_media_transport_state_t transport_state;
72 #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
73 #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
74 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
75 #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
77 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
78 #define VCONF_KEY_BT_LUNAR_ENABLED "db/wms/bt_loop_device_hfp_connected"
80 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
81 #define CALL_APP_ID "org.tizen.call-ui"
84 #if defined(TIZEN_SUPPORT_DUAL_HF)
85 #define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac"
86 #define MAX_CONNECTED_DEVICES 2
88 #define MAX_CONNECTED_DEVICES 1
91 #define BT_AG_SIG_NUM 3
92 static struct sigaction bt_ag_sigoldact[BT_AG_SIG_NUM];
93 static int bt_ag_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
95 /*Below Inrospection data is exposed to bluez from agent*/
96 static const gchar ag_agent_bluez_introspection_xml[] =
98 " <interface name='org.bluez.Profile1'>"
99 " <method name='NewConnection'>"
100 " <arg type='o' name='device' direction='in'/>"
101 " <arg type='h' name='fd' direction='in'/>"
102 " <arg type='a{sv}' name='options' direction='in'/>"
104 " <method name='RequestDisconnection'>"
105 " <arg type='o' name='device' direction='in'/>"
110 /*Below Introspection data is exposed to application from agent*/
111 static const gchar ag_agent_app_introspection_xml[] =
113 " <interface name='Org.Hfp.App.Interface'>"
114 " <method name='RegisterApplication'>"
115 " <arg type='s' name='path' direction='in'/>"
116 " <arg type='s' name='address' direction='in'/>"
118 " <method name='UnregisterApplication'>"
119 " <arg type='s' name='path' direction='in'/>"
121 " <method name='IncomingCall'>"
122 " <arg type='s' name='path' direction='in'/>"
123 " <arg type='s' name='number' direction='in'/>"
124 " <arg type='i' name='id' direction='in'/>"
126 " <method name='OutgoingCall'>"
127 " <arg type='s' name='path' direction='in'/>"
128 " <arg type='s' name='number' direction='in'/>"
129 " <arg type='i' name='id' direction='in'/>"
131 " <method name='ChangeCallStatus'>"
132 " <arg type='s' name='path' direction='in'/>"
133 " <arg type='s' name='number' direction='in'/>"
134 " <arg type='i' name='status' direction='in'/>"
135 " <arg type='i' name='id' direction='in'/>"
137 " <method name='GetProperties'>"
138 " <arg type='a{sv}' name='properties' direction='out'/>"
140 " <method name='Disconnect'>"
142 " <method name='IsConnected'>"
143 " <arg type='b' name='connected' direction='out'/>"
145 " <method name='IndicateCall'>"
147 " <method name='CancelCall'>"
149 " <method name='Play'>"
151 " <method name='Stop'>"
153 " <method name='IsPlaying'>"
154 " <arg type='b' name='playing' direction='out'/>"
156 " <method name='GetSpeakerGain'>"
157 " <arg type='q' name='gain' direction='out'/>"
159 " <method name='GetMicrophoneGain'>"
160 " <arg type='q' name='gain' direction='out'/>"
162 " <method name='SetSpeakerGain'>"
163 " <arg type='q' name='gain' direction='in'/>"
165 " <method name='SetMicrophoneGain'>"
166 " <arg type='q' name='gain' direction='in'/>"
168 " <method name='SetVoiceDial'>"
169 " <arg type='b' name='enable' direction='in'/>"
171 " <method name='CheckPrivilege'>"
173 " <method name='SwapHeadset'>"
174 " <arg type='s' name='remote_addr' direction='in'/>"
181 int (*callback)(bt_ag_info_t *hs, const char *buf);
184 struct sco_socket_addr {
185 sa_family_t sco_family;
194 bt_ag_info_t *bt_ag_info;
198 bt_ag_status_t ag = {
199 .telephony_ready = FALSE,
203 .rh = BT_RSP_HOLD_NOT_SUPPORTED,
209 static void __bt_ag_agent_sigterm_handler(int signo);
210 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
211 const gchar *object_path);
212 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs);
213 static gboolean __bt_ag_event_handler(GIOChannel *channel, GIOCondition cond,
215 static int __bt_ag_sco_connect(bt_ag_info_t *hs);
216 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state);
217 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data);
218 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle);
219 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
220 const gchar *sender_name,
221 const gchar *object_path,
222 const gchar *interface_name,
223 const gchar *signal_name,
224 GVariant *parameters,
227 static void __bt_convert_addr_type_to_rev_string(char *address,
230 ret_if(address == NULL);
231 ret_if(addr == NULL);
233 g_snprintf(address, BT_ADDRESS_STRING_SIZE,
234 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
235 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
238 static GDBusProxy *__bt_ag_gdbus_init_service_proxy(const gchar *service,
239 const gchar *path, const gchar *interface)
246 if (ag_dbus_conn == NULL)
247 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
251 ERR("Unable to connect to gdbus: %s", err->message);
257 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
258 G_DBUS_PROXY_FLAGS_NONE, NULL,
260 interface, NULL, &err);
264 ERR("Unable to create proxy: %s", err->message);
274 static GDBusProxy *__bt_ag_gdbus_get_app_proxy(const gchar *service,
275 const gchar *path, const gchar *interface)
277 return (app_gproxy) ? app_gproxy :
278 __bt_ag_gdbus_init_service_proxy(service,
282 static int __bt_ag_agent_gdbus_method_send(const char *service,
283 const gchar *path, const char *interface,
284 const char *method, gboolean response,
285 GVariant *parameters)
291 GError *error = NULL;
293 proxy = __bt_ag_gdbus_get_app_proxy(service, path, interface);
295 return BT_HFP_AGENT_ERROR_INTERNAL;
298 ret = g_dbus_proxy_call_sync(proxy,
300 G_DBUS_CALL_FLAGS_NONE, -1,
303 /* dBUS-RPC is failed */
304 ERR("dBUS-RPC is failed");
306 /* dBUS gives error cause */
307 ERR("D-Bus API failure: errCode[%x], message[%s]",
308 error->code, error->message);
310 g_clear_error(&error);
312 return BT_HFP_AGENT_ERROR_INTERNAL;
315 g_variant_unref(ret);
317 g_dbus_proxy_call(proxy,
319 G_DBUS_CALL_FLAGS_NONE, 2000,
322 return BT_HFP_AGENT_ERROR_NONE;
325 gboolean _bt_ag_agent_emit_signal(
326 GDBusConnection *connection,
328 const char *interface,
334 GError *error = NULL;
336 ret = g_dbus_connection_emit_signal(connection,
337 NULL, path, interface,
342 /* dBUS gives error cause */
343 ERR("D-Bus API failure: errCode[%x], message[%s]",
344 error->code, error->message);
345 g_clear_error(&error);
348 INFO_C("Emit Signal done = [%s]", name);
354 gboolean _bt_ag_agent_emit_property_changed(
355 GDBusConnection *connection,
357 const char *interface,
366 var_data = g_variant_new("(sv)", name, property);
368 ret = _bt_ag_agent_emit_signal(connection,
370 "PropertyChanged", var_data);
375 static void __bt_ag_agent_start_watch(bt_ag_info_t *bt_ag_info)
377 bt_ag_info->watch_id = g_io_add_watch(bt_ag_info->io_chan,
378 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
379 (GIOFunc) __bt_ag_event_handler, bt_ag_info);
382 static void __bt_ag_agent_remove_watch(guint *watch_id)
384 DBG("Remove IO watch ID %d", *watch_id);
386 g_source_remove(*watch_id);
391 #if defined(TIZEN_SUPPORT_DUAL_HF)
392 gboolean __bt_ag_agent_is_companion_device(const char *addr)
394 #if defined(TIZEN_PROFILE_WEARABLE)
395 char *host_device_address = NULL;
396 host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR);
398 if (!host_device_address) {
399 INFO("Failed to get a companion device address");
403 if (g_strcmp0(host_device_address, addr) == 0) {
404 INFO("addr[%s] is companion device", addr);
410 /* TODO : Need to add companion device check condition for Phone models */
415 void __bt_convert_device_path_to_address(const gchar *device_path,
416 char *device_address)
418 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
421 ret_if(device_path == NULL);
422 ret_if(device_address == NULL);
424 dev_addr = strstr(device_path, "dev_");
425 if (dev_addr != NULL) {
428 g_strlcpy(address, dev_addr, sizeof(address));
430 while ((pos = strchr(address, '_')) != NULL)
433 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
437 static gboolean __bt_ag_agent_is_companion_device_connected(void)
441 for (l = active_devices ; l; l = l->next) {
442 bt_ag_info_t *data = l->data;
444 if (data->is_companion_device) {
445 DBG("Companion device found");
453 gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
455 char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
456 gboolean is_companion_device;
458 __bt_convert_device_path_to_address(device_path, device_address);
459 is_companion_device = __bt_ag_agent_is_companion_device(device_address);
461 DBG(" device_address[%s]", device_address);
462 DBG(" is_companion_device[%d]", is_companion_device);
464 if (__bt_ag_agent_is_companion_device_connected()) {
465 if (is_companion_device)
468 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 static gboolean __bt_ag_agent_launch_call_app(const char *number)
561 DBG_SECURE("number(%s)", number);
565 ERR("bundle_create() Failed");
569 bundle_add(b, "launch-type", "MO");
570 bundle_add(b, "dial-type", "HEADSET");
572 if (strlen(number) != 0)
573 bundle_add(b, "number", number);
575 aul_launch_app_async(CALL_APP_ID, b);
582 static void *__bt_ag_agent_launch_call_req(void *arg)
585 bundle *b = (bundle *)arg;
586 if (appsvc_run_service(b, 0, NULL, NULL) < 0)
587 ERR("Unable to run app svc");
589 call_launch_requested = FALSE;
594 static gboolean __bt_ag_agent_make_call(const char *number)
598 char telnum[BT_MAX_TEL_NUM_STRING];
602 if (TIZEN_PROFILE_WEARABLE)
603 return __bt_ag_agent_launch_call_app(number);
605 if (call_launch_requested == TRUE) {
606 DBG("Launch request is in progress");
614 appsvc_set_operation(b, APPSVC_OPERATION_CALL);
615 snprintf(telnum, sizeof(telnum), "tel:%s", number);
616 appsvc_set_uri(b, telnum);
617 appsvc_add_data(b, "ctindex", "-1");
619 call_launch_requested = TRUE;
620 if (pthread_create(&thread_id, NULL,
621 (void *)&__bt_ag_agent_launch_call_req,
623 ERR("pthread_create() is failed");
624 call_launch_requested = FALSE;
627 if (pthread_detach(thread_id) < 0)
628 ERR("pthread_detach() is failed");
634 static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
639 kb = bundle_create();
643 bundle_add(kb, "KEY_CALL_TYPE", "MO");
644 bundle_add(kb, "number", mo_number);
645 aul_launch_app("org.tizen.vtmain", kb);
652 gboolean _bt_ag_agent_answer_call(unsigned int call_id,
653 const gchar *path, const gchar *sender)
657 if (path == NULL || sender == NULL) {
658 DBG("Invalid Arguments");
662 DBG("Application path = %s", path);
663 DBG("Call Id = %d", call_id);
664 DBG("Sender = %s", sender);
666 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
667 BT_AG_SERVICE_NAME, "Answer",
668 g_variant_new("(u)", call_id));
673 gboolean _bt_ag_agent_reject_call(unsigned int call_id,
674 const gchar *path, const gchar *sender)
678 if (path == NULL || sender == NULL) {
679 DBG("Invalid Arguments");
683 DBG("Application path = %s", path);
684 DBG("Call Id = %d", call_id);
685 DBG("Sender = %s", sender);
687 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
688 BT_AG_SERVICE_NAME, "Reject",
689 g_variant_new("(u)", call_id));
694 gboolean _bt_ag_agent_release_call(unsigned int call_id,
695 const gchar *path, const gchar *sender)
699 if (path == NULL || sender == NULL) {
700 DBG("Invalid Arguments");
704 DBG("Application path = %s", path);
705 DBG("Call Id = %d", call_id);
706 DBG("Sender = %s", sender);
708 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
709 BT_AG_SERVICE_NAME, "Release",
710 g_variant_new("(u)", call_id));
716 bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
718 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
720 int phone_lock_state;
725 if (number == NULL) {
726 ERR("Invalid Argument");
727 error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
731 DBG("Number = %s", number);
732 DBG("flags = %d", flags);
734 if (!__bt_is_phone_locked(&phone_lock_state)) {
735 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
739 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
740 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
744 if (!__bt_get_outgoing_call_condition(&condition)) {
745 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
749 if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
750 VCONFKEY_IDLE_LOCK) {
751 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
755 if (callapp_type == BT_VIDEO_CALL) {
756 if (!__bt_ag_agent_make_video_call(number)) {
757 ERR("Problem launching application");
758 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
762 if (!__bt_ag_agent_make_call(number)) {
763 ERR("Problem launching application");
764 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
774 bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
776 bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
778 contacts_filter_h filter = NULL;
779 contacts_query_h query = NULL;
780 contacts_list_h list = NULL;
781 contacts_record_h record = NULL;
782 unsigned int projections[] = {
783 _contacts_speeddial.number,
788 DBG("location = %d", location);
790 /*Get number from contacts location*/
791 if (contacts_connect() != CONTACTS_ERROR_NONE) {
792 ERR(" contacts_connect failed");
793 return BT_HFP_AGENT_ERROR_INTERNAL;
796 contacts_filter_create(_contacts_speeddial._uri, &filter);
801 if (contacts_filter_add_int(filter,
802 _contacts_speeddial.speeddial_number,
803 CONTACTS_MATCH_EQUAL, location) !=
804 CONTACTS_ERROR_NONE) {
805 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
809 contacts_query_create(_contacts_speeddial._uri, &query);
814 contacts_query_set_filter(query, filter);
816 if (contacts_query_set_projection(query, projections,
817 sizeof(projections)/sizeof(unsigned int)) !=
818 CONTACTS_ERROR_NONE) {
819 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
823 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
824 CONTACTS_ERROR_NONE) {
825 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
829 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
830 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
834 if (contacts_list_get_current_record_p(list, &record) !=
835 CONTACTS_ERROR_NONE) {
836 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
843 if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
844 != CONTACTS_ERROR_NONE) {
845 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
849 if (number == NULL) {
850 ERR("No number at the location");
851 error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
855 DBG("number %s", number);
858 if (!__bt_ag_agent_make_call(number)) {
859 ERR("Problem launching application");
860 error_code = BT_HFP_AGENT_ERROR_INTERNAL;
866 contacts_list_destroy(list, TRUE);
869 contacts_filter_destroy(filter);
872 contacts_query_destroy(query);
874 contacts_disconnect();
881 bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
882 const gchar *path, const gchar *sender)
884 bt_hfp_agent_error_t ret;
888 if (dtmf == NULL || path == NULL || sender == NULL) {
889 ERR("Invalid Argument");
893 DBG("Dtmf = %s", dtmf);
894 DBG("Application path = %s", path);
895 DBG("Sender = %s", sender);
897 ret = __bt_ag_agent_gdbus_method_send(sender,
898 path, TELEPHONY_APP_INTERFACE,
900 g_variant_new("(s)", dtmf));
905 gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
906 const gchar *path, const gchar *sender)
910 if (path == NULL || sender == NULL) {
911 DBG("Invalid Arguments");
915 DBG("Application path = %s", path);
916 DBG("Value = %d", chld_value);
917 DBG("Sender = %s", sender);
919 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
920 /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
921 if not return FALSE */
922 if (chld_value != 0 && chld_value != 1 && chld_value != 2)
925 if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
929 _bt_ag_agent_emit_signal(ag_dbus_conn, path,
930 BT_AG_SERVICE_NAME, "Threeway",
931 g_variant_new("(u)", chld_value));
936 bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
938 bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
939 char *last_num = NULL;
942 int phone_lock_state;
944 contacts_list_h list = NULL;
945 contacts_query_h query = NULL;
946 contacts_filter_h filter = NULL;
947 contacts_record_h record = NULL;
948 unsigned int projections[] = {
949 _contacts_phone_log.address,
950 _contacts_phone_log.log_type,
955 if (contacts_connect() != CONTACTS_ERROR_NONE) {
956 ERR(" contacts_connect failed");
957 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
961 contacts_filter_create(_contacts_phone_log._uri, &filter);
966 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
967 CONTACTS_MATCH_EQUAL,
968 CONTACTS_PLOG_TYPE_VOICE_OUTGOING) !=
969 CONTACTS_ERROR_NONE) {
970 ERR(" contacts_filter_add_int failed");
971 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
975 if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) !=
976 CONTACTS_ERROR_NONE) {
977 ERR(" contacts_filter_add_operator failed");
978 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
982 if (contacts_filter_add_int(filter, _contacts_phone_log.log_type,
983 CONTACTS_MATCH_EQUAL,
984 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) !=
985 CONTACTS_ERROR_NONE) {
986 ERR(" contacts_filter_add_int failed");
987 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
991 contacts_query_create(_contacts_phone_log._uri, &query);
996 contacts_query_set_filter(query, filter);
998 if (contacts_query_set_projection(query, projections,
999 sizeof(projections)/sizeof(unsigned int)) !=
1000 CONTACTS_ERROR_NONE) {
1001 ERR(" contacts_query_set_projection failed");
1002 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1006 if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false)
1007 != CONTACTS_ERROR_NONE) {
1008 ERR(" contacts_query_set_sort failed");
1009 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1013 if (contacts_db_get_records_with_query(query, 0, 1, &list) !=
1014 CONTACTS_ERROR_NONE) {
1015 ERR(" contacts_db_get_records_with_query failed");
1016 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1020 if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
1021 ERR(" contacts_list_first failed");
1022 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1026 if (contacts_list_get_current_record_p(list, &record) !=
1027 CONTACTS_ERROR_NONE) {
1028 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1035 if (contacts_record_get_str(record, _contacts_phone_log.address,
1036 &last_num) != CONTACTS_ERROR_NONE) {
1037 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1041 if (last_num == NULL) {
1042 ERR("No last number");
1043 err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
1047 if (!__bt_is_phone_locked(&phone_lock_state)) {
1048 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1052 if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
1053 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1057 if (!__bt_get_outgoing_call_condition(&condition)) {
1058 ERR(" Failed to get the call condition");
1059 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1063 if (condition == BT_MO_ONLY_UNLOCKED &&
1064 phone_lock_state == VCONFKEY_IDLE_LOCK) {
1065 ERR(" call condition and phone lock state check fail");
1066 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1070 switch (callapp_type) {
1072 if (!__bt_ag_agent_make_call(last_num)) {
1073 ERR("Problem launching application");
1074 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1078 if (!__bt_ag_agent_make_video_call(last_num)) {
1079 ERR("Problem launching application");
1080 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1083 case BT_FOLLOW_CALL_LOG:
1084 if (contacts_record_get_int(record,
1085 _contacts_phone_log.log_type,
1086 &type) != CONTACTS_ERROR_NONE) {
1087 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1090 if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
1091 if (!__bt_ag_agent_make_call(last_num)) {
1092 ERR("Problem launching application");
1093 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1095 } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
1096 if (!__bt_ag_agent_make_video_call(last_num)) {
1097 ERR("Problem launching application");
1098 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1101 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1105 err_code = BT_HFP_AGENT_ERROR_INTERNAL;
1112 contacts_list_destroy(list, TRUE);
1115 contacts_filter_destroy(filter);
1118 contacts_query_destroy(query);
1120 contacts_disconnect();
1122 if (last_num != NULL)
1130 bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
1131 const gchar *path, const gchar *sender)
1133 bt_hfp_agent_error_t ret;
1137 if (cmd == NULL || path == NULL || sender == NULL) {
1138 ERR("Invalid Argument");
1139 return BT_HFP_AGENT_ERROR_INVALID_PARAM;
1142 DBG("cmd = %s", cmd);
1143 DBG("Application path = %s", path);
1144 DBG("Sender = %s", sender);
1146 ret = __bt_ag_agent_gdbus_method_send(sender,
1147 path, TELEPHONY_APP_INTERFACE,
1149 g_variant_new("(s)", cmd));
1154 gboolean _bt_ag_agent_get_signal_quality(void *device)
1160 if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
1161 DBG("VCONFKEY_TELEPHONY_RSSI failed\n");
1165 DBG("RSSI : %d", rssi);
1167 _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
1174 _bt_hfp_signal_quality_reply(-1, -1, device);
1178 gboolean _bt_ag_agent_get_battery_status(void *device)
1180 gint battery_chrg_status;
1181 gint battery_capacity;
1185 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
1186 &battery_chrg_status)) {
1187 DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n");
1191 DBG("Status : %d\n", battery_chrg_status);
1193 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
1194 &battery_capacity)) {
1195 DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n");
1199 DBG("Capacity : %d\n", battery_capacity);
1201 _bt_hfp_battery_property_reply(device,
1202 battery_chrg_status, battery_capacity);
1207 _bt_hfp_battery_property_reply(device, -1, -1);
1212 gboolean _bt_ag_agent_get_operator_name(void *device)
1214 char *operator_name;
1217 operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
1218 if (NULL == operator_name) {
1219 DBG("vconf_get_str failed");
1220 _bt_hfp_operator_reply(NULL, device);
1224 DBG("operator_name = [%s]", operator_name);
1226 _bt_hfp_operator_reply(operator_name, device);
1228 free(operator_name);
1234 gboolean _bt_hfp_agent_nrec_status(gboolean status,
1238 bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
1240 DBG("NREC status = %d", status);
1242 hs->nrec_status = FALSE;
1244 hs->nrec_status = TRUE;
1246 _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
1247 BT_AG_SERVICE_NAME, "NrecStatusChanged",
1248 g_variant_new("(b)", status));
1253 gboolean _bt_ag_agent_get_imei_number(void *device)
1258 imei_number = tel_get_misc_me_imei_sync(tapi_handle);
1259 if (NULL == imei_number) {
1260 ERR("tel_get_misc_me_imei_sync for imei_number failed");
1264 if (!g_utf8_validate(imei_number, -1, NULL)) {
1266 ERR("get_imei_number : invalid UTF8");
1270 DBG_SECURE("imei_number = [%s]", imei_number);
1271 _bt_hfp_get_imei_number_reply(imei_number, device);
1277 _bt_hfp_get_imei_number_reply(NULL, device);
1282 void _bt_ag_agent_get_manufacturer_name(void *device)
1285 char *manufacturer_name;
1288 ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
1289 &manufacturer_name);
1290 if (SYSTEM_INFO_ERROR_NONE != ret) {
1291 ERR("Get manufacturer_name failed : %d", ret);
1292 if (NULL != manufacturer_name)
1293 free(manufacturer_name);
1295 manufacturer_name = g_strdup("Unknown");
1296 } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
1297 free(manufacturer_name);
1298 manufacturer_name = g_strdup("Unknown");
1299 ERR("get_manufacturer_name : invalid UTF8");
1302 DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
1303 _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
1304 free(manufacturer_name);
1308 void _bt_ag_agent_get_imsi(void *device)
1311 TelSimImsiInfo_t imsi;
1312 memset(&imsi, 0, sizeof(TelSimImsiInfo_t));
1313 if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
1314 ERR("tel_get_sim_imsi failed");
1317 DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
1319 _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
1323 _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
1327 int _bt_ag_agent_registration_status_convert(int result)
1330 case TAPI_NETWORK_SERVICE_LEVEL_NO:
1331 return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
1332 case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
1333 return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
1334 case TAPI_NETWORK_SERVICE_LEVEL_FULL:
1335 return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
1336 case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
1337 return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
1339 return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
1344 void _bt_ag_agent_get_creg_status(void *device)
1350 int registration_status = 0;
1351 int roam_status = 0;
1353 ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
1355 if (ret != TAPI_API_SUCCESS) {
1356 ERR("tel_get_property_int failed");
1359 registration_status =
1360 _bt_ag_agent_registration_status_convert(result);
1362 DBG_SECURE("Registration status %d", result);
1363 DBG_SECURE("Mapped Status %d", registration_status);
1364 if (registration_status ==
1365 BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
1366 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
1368 ERR("Get roaming status failed err = %d\n", ret);
1371 DBG_SECURE("Roam status %d", roam_status);
1372 if (roam_status == 1) {
1373 registration_status =
1374 BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
1378 _bt_hfp_get_creg_status_reply(n, registration_status, device);
1384 void _bt_ag_agent_get_model_name(void *device)
1390 ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
1391 if (SYSTEM_INFO_ERROR_NONE != ret) {
1392 ERR("Get model_name failed: %d", ret);
1393 if (NULL != model_name)
1396 model_name = g_strdup("Unknown");
1397 } else if (!g_utf8_validate(model_name, -1, NULL)) {
1399 model_name = g_strdup("Unknown");
1400 ERR("get_model_name : invalid UTF8");
1403 DBG_SECURE("model_name = [%s]", model_name);
1404 _bt_hfp_get_model_info_reply(model_name, device);
1409 void _bt_ag_agent_get_revision_information(void *device)
1412 char *revision_info;
1415 ret = system_info_get_platform_string("http://tizen.org/system/build.string",
1417 if (SYSTEM_INFO_ERROR_NONE != ret) {
1418 ERR("Get revision_info failed: %d", ret);
1419 if (NULL != revision_info)
1420 free(revision_info);
1422 revision_info = g_strdup("Unknown");
1423 } else if (!g_utf8_validate(revision_info, -1, NULL)) {
1424 free(revision_info);
1425 revision_info = g_strdup("Unknown");
1426 ERR("get_revision_info: invalid UTF8");
1429 DBG_SECURE("revision_info = [%s]", revision_info);
1430 _bt_hfp_get_revision_info_reply(revision_info, device);
1431 free(revision_info);
1435 #if defined(TIZEN_PROFILE_WEARABLE) && defined(TIZEN_FEATURE_BT_HFP_AG)
1436 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1441 b = bundle_create();
1443 ERR("bundle_create() Failed");
1447 bundle_add(b, "domain", "bt_headset");
1449 bundle_add(b, "action_type", "deactivate");
1451 aul_launch_app_async("org.tizen.svoice", b);
1457 static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
1460 app_control_h service = NULL;
1462 app_control_create(&service);
1464 if (service == NULL) {
1465 ERR("Service create failed");
1469 app_control_set_app_id(service, "org.tizen.svoice");
1470 app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
1471 if (app_control_add_extra_data(service, "domain", "bt_headset")
1472 != APP_CONTROL_ERROR_NONE) {
1473 ERR("app_control_add_extra_data failed");
1474 app_control_destroy(service);
1479 if (app_control_add_extra_data(service, "action_type", "deactivate")
1480 != APP_CONTROL_ERROR_NONE) {
1481 ERR("app_control_add_extra_data failed");
1482 app_control_destroy(service);
1486 if (app_control_send_launch_request(service, NULL, NULL) !=
1487 APP_CONTROL_ERROR_NONE) {
1488 ERR("launch failed");
1489 app_control_destroy(service);
1493 app_control_destroy(service);
1499 gboolean _bt_ag_agent_voice_dial(gboolean activate)
1501 DBG("Activate = %d", activate);
1503 return __bt_ag_agent_launch_voice_dial(activate);
1506 static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
1509 hs->codec_info.is_negotiating = FALSE;
1510 hs->codec_info.requested_by_hf = FALSE;
1511 hs->codec_info.sending_codec = 0;
1513 hs->codec_info.remote_codecs = 0;
1514 hs->codec_info.final_codec = 0;
1515 hs->nrec_status = FALSE;
1518 if (hs->codec_info.nego_timer) {
1519 g_source_remove(hs->codec_info.nego_timer);
1520 hs->codec_info.nego_timer = 0;
1522 wbs_opts.wbs_enable = wbs_en;
1525 static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
1527 struct ag_codec *data = (struct ag_codec *)user_data;
1529 if (g_strcmp0(data->codec_status, "finish") == 0) {
1530 DBG("Codec negotiation finished");
1531 __bt_ag_sco_connect(data->bt_ag_info);
1532 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1533 g_free(data->codec_status);
1536 } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
1537 DBG("Timeout is occured in codec negotiation");
1540 if (data->bt_ag_info->codec_info.requested_by_hf) {
1541 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1543 __bt_ag_sco_connect(data->bt_ag_info);
1544 __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
1546 g_free(data->codec_status);
1552 static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
1557 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
1559 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
1560 G_DBUS_PROXY_FLAGS_NONE, NULL,
1561 BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
1562 BT_ADAPTER_INTERFACE, NULL, &err);
1566 ERR("Unable to create proxy: %s", err->message);
1567 g_clear_error(&err);
1569 return BT_HFP_AGENT_ERROR_INTERNAL;
1572 ret = g_dbus_proxy_call_sync(proxy, method,
1573 g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
1574 G_DBUS_CALL_FLAGS_NONE, -1,
1577 /* dBUS-RPC is failed */
1578 ERR("dBUS-RPC is failed");
1580 /* dBUS gives error cause */
1581 ERR("D-Bus API failure: errCode[%x], message[%s]",
1582 err->code, err->message);
1584 g_clear_error(&err);
1586 return BT_HFP_AGENT_ERROR_INTERNAL;
1588 g_variant_unref(ret);
1590 return BT_HFP_AGENT_ERROR_NONE;
1593 static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
1596 bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
1598 DBG("Codec setup [%x]", codec);
1600 /* 1. Compare sending codec & recieved code */
1601 if (hs->codec_info.sending_codec != codec)
1602 err = BT_HFP_AGENT_ERROR_INTERNAL;
1604 /* 2. Send WB or NB command */
1606 case BT_CVSD_CODEC_ID:
1607 err = __bt_ag_set_codec(hs, "SetNbParameters");
1609 case BT_MSBC_CODEC_ID:
1610 err = __bt_ag_set_codec(hs, "SetWbsParameters");
1613 err = BT_HFP_AGENT_ERROR_INTERNAL;
1617 /* If the vendor specific calling returns error or codec is not correct,
1618 * we send CVSD Codec parameter to MM module. and also returns
1619 * normal value to HF
1621 if (err != BT_HFP_AGENT_ERROR_NONE)
1622 codec = BT_CVSD_CODEC_ID;
1624 hs->codec_info.final_codec = codec;
1629 static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
1630 gboolean init_by_hf)
1633 struct ag_codec *data = NULL;;
1635 if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
1636 codec = BT_MSBC_CODEC_ID;
1638 codec = BT_CVSD_CODEC_ID;
1640 if (wbs_opts.wbs_enable == FALSE)
1641 codec = BT_CVSD_CODEC_ID;
1645 if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
1646 return BT_HFP_AGENT_ERROR_INTERNAL;
1648 DBG("Send +BCS:%d\n", codec);
1650 /* Send +BCS command to HF, and wait some times */
1651 hs->codec_info.is_negotiating = TRUE;
1652 hs->codec_info.sending_codec = codec;
1653 hs->codec_info.requested_by_hf = init_by_hf;
1654 hs->codec_info.final_codec = codec;
1656 data = g_new0(struct ag_codec, 1);
1658 return BT_HFP_AGENT_ERROR_NO_MEMORY;
1660 data->bt_ag_info = hs;
1661 data->codec_status = g_strdup("timeout");
1663 hs->codec_info.nego_timer = g_timeout_add_seconds(
1664 HFP_CODEC_NEGOTIATION_TIMEOUT,
1665 (GSourceFunc)__bt_ag_codec_negotiation_finished,
1668 return BT_HFP_AGENT_ERROR_NONE;
1672 static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
1673 bt_ag_info_t *hs, gboolean init_by_hf)
1675 DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
1677 if (hs->state < HEADSET_STATE_CONNECTED)
1678 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1680 if (hs->codec_info.is_negotiating == TRUE) {
1681 /* In codec negotiation, return and wait */
1682 ERR("Codec nogotiation is in progress");
1683 return BT_HFP_AGENT_ERROR_BUSY;
1686 /* Not support Codec Negotiation or Not recieved BAC command */
1687 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
1688 hs->codec_info.remote_codecs == 0) {
1689 ERR("No support for Codec Negotiation or receive BAC command");
1691 return BT_HFP_AGENT_ERROR_INTERNAL;
1693 __bt_ag_sco_connect(hs);
1694 return BT_HFP_AGENT_ERROR_INTERNAL;
1698 /* If HF initiated codec connection setup, it should send OK command
1699 * before +BCS command transmission.
1702 return HFP_STATE_MNGR_ERR_NONE;
1704 return __bt_hfp_send_bcs_command(hs, init_by_hf);
1708 static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
1711 *codecs = 0x00000000;
1713 str = strchr(cmd, '=');
1717 while (str != NULL) {
1720 if (atoi(str) == BT_CVSD_CODEC_ID)
1721 *codecs |= BT_CVSD_CODEC_MASK;
1722 else if (atoi(str) == BT_MSBC_CODEC_ID)
1723 *codecs |= BT_MSBC_CODEC_MASK;
1725 str = strchr(str, ',');
1728 if (*codecs == 0x00000000)
1734 /* AT+BAC (Bluetooth Available Codecs) */
1735 static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
1737 uint32_t codecs = 0x00000000;
1738 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1740 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
1741 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1742 } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
1743 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1745 DBG("Update remote available codecs [%x]", codecs);
1746 hs->codec_info.remote_codecs = codecs;
1749 _bt_ag_send_response(hs, err);
1751 /* Reset codec information and
1752 * restart codec connection setup by AG
1754 hs->codec_info.final_codec = 0;
1755 if (hs->codec_info.nego_timer) {
1756 hs->codec_info.is_negotiating = FALSE;
1757 hs->codec_info.requested_by_hf = FALSE;
1758 hs->codec_info.sending_codec = 0;
1759 g_source_remove(hs->codec_info.nego_timer);
1760 __bt_hfp_codec_connection_setup(hs, FALSE);
1766 /* AT+BCC (Bluetooth Codec Connection) */
1767 static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
1769 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1771 err = __bt_hfp_codec_connection_setup(hs, TRUE);
1773 _bt_ag_send_response(hs, err);
1775 if (err == HFP_STATE_MNGR_ERR_NONE)
1776 err = __bt_hfp_send_bcs_command(hs, TRUE);
1778 if (err != HFP_STATE_MNGR_ERR_NONE)
1779 ERR("Fail to request codec connection setup");
1784 /* AT+BCS (Bluetooth Codec Selection) */
1785 static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
1787 uint32_t codec = 0x00000000;
1788 hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
1789 struct ag_codec *data = g_new0(struct ag_codec, 1);
1792 if (hs->codec_info.nego_timer) {
1793 g_source_remove(hs->codec_info.nego_timer);
1794 hs->codec_info.nego_timer = 0;
1797 if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
1798 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1799 else if (__hfp_parse_available_codecs(buf, &codec) < 0)
1800 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1801 else if (__bt_ag_codec_selection_setup(hs, codec) !=
1802 BT_HFP_AGENT_ERROR_NONE)
1803 err = HFP_STATE_MNGR_ERR_AG_FAILURE;
1805 data->bt_ag_info = hs;
1806 data->codec_status = g_strdup("finish");
1807 _bt_ag_send_response(hs, err);
1808 __bt_ag_codec_negotiation_finished(data);
1813 static void __bt_ag_str2ba(const char *str, bt_addr *ba)
1816 for (i = 5; i >= 0; i--, str += 3)
1817 ba->b[i] = strtol(str, NULL, 16);
1820 static const char *__bt_ag_state2str(hs_state_t state)
1823 case HEADSET_STATE_DISCONNECTED:
1824 return "disconnected";
1825 case HEADSET_STATE_CONNECTING:
1826 return "connecting";
1827 case HEADSET_STATE_CONNECTED:
1829 case HEADSET_STATE_PLAY_IN_PROGRESS:
1830 return "Play In Progress";
1831 case HEADSET_STATE_ON_CALL:
1838 void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
1839 const char *address)
1844 ret_if(address == NULL);
1845 ret_if(addr == NULL);
1847 for (i = 0; i < 6; i++) {
1848 addr[5 - i] = strtol(address, &ptr, 16);
1849 if (ptr[0] != '\0') {
1858 static gboolean __bt_ag_check_nval(GIOChannel *chan)
1860 struct pollfd file_desc;
1862 memset(&file_desc, 0, sizeof(file_desc));
1863 file_desc.fd = g_io_channel_unix_get_fd(chan);
1864 file_desc.events = POLLNVAL;
1866 if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
1872 static int __bt_ag_sco_connect(bt_ag_info_t *hs)
1874 struct sco_socket_addr sco_addr;
1879 bt_ag_slconn_t *slconn = hs->slc;
1882 if (hs->state == HEADSET_STATE_ON_CALL)
1883 return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED;
1885 if (hs->state != HEADSET_STATE_CONNECTED)
1886 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
1887 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
1888 _bt_ag_agent_check_transport_state();
1891 /* Create Sco socket */
1892 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
1894 ERR("ERROR: Create socket failed.\n");
1895 return BT_HFP_AGENT_ERROR_INTERNAL;
1898 /* Bind Sco Socket to Local BD addr */
1899 memset(&sco_addr, 0, sizeof(sco_addr));
1900 sco_addr.sco_family = AF_BLUETOOTH;
1902 __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
1903 DBG("Local BD address: %s", local_addr);
1905 err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1907 ERR("ERROR: sco socket binding failed");
1908 ERR("Close SCO skt");
1910 return BT_HFP_AGENT_ERROR_INTERNAL;
1913 DBG("Socket FD : %d", sco_skt);
1915 io = g_io_channel_unix_new(sco_skt);
1916 g_io_channel_set_close_on_unref(io, TRUE);
1917 /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
1918 g_io_channel_set_buffered(io, FALSE);
1919 g_io_channel_set_encoding(io, NULL, NULL);*/
1921 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
1922 (slconn && (slconn->hs_features &
1923 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
1924 wbs_opts.wbs_enable == TRUE) {
1925 bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
1926 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
1928 DBG("set Bluetooth voice: %d", bt_vo.setting);
1929 err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
1930 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
1932 ERR("ERROR: sco socket set socket option failed");
1933 ERR("Close SCO skt");
1934 g_io_channel_unref(io);
1936 return BT_HFP_AGENT_ERROR_INTERNAL;
1939 DBG("Set NB codec parameter");
1940 __bt_ag_set_codec(hs, "SetNbParameters");
1943 memset(&sco_addr, 0, sizeof(sco_addr));
1944 sco_addr.sco_family = AF_BLUETOOTH;
1945 __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
1946 DBG("remotel BD address: %s", hs->remote_addr);
1948 err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
1949 if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
1950 ERR("ERROR: sco socket connect failed : %d", err);
1951 ERR("Close SCO skt");
1952 g_io_channel_unref(io);
1954 return BT_HFP_AGENT_ERROR_INTERNAL;
1957 /* Disabling the watch since SCO is connected */
1958 /*watch_id = __bt_ag_set_watch(io,
1959 (GIOFunc) __bt_ag_sco_connect_cb, hs);
1961 DBG("SCO watch set Success");*/
1965 _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
1966 return BT_HFP_AGENT_ERROR_NONE;
1969 static void __bt_ag_close_sco(bt_ag_info_t *hs)
1973 int sock = g_io_channel_unix_get_fd(hs->sco);
1974 shutdown(sock, SHUT_RDWR);
1975 g_io_channel_unref(hs->sco);
1980 __bt_ag_agent_remove_watch(&hs->sco_id);
1983 static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
1984 GIOCondition cond, gpointer user_data)
1986 bt_ag_info_t *ag_info = user_data;
1989 if (cond & G_IO_NVAL)
1992 if (cond & (G_IO_HUP | G_IO_ERR)) {
1993 ag_info->sco = NULL;
1994 if (ag_info->sco_id)
1995 __bt_ag_agent_remove_watch(&ag_info->sco_id);
1997 if (ag_info->watch_id)
1998 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
2004 static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
2005 GIOCondition cond, gpointer user_data)
2007 bt_ag_info_t *ag_info = user_data;
2011 bt_ag_slconn_t *slconn = ag_info->slc;
2015 if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
2016 __bt_ag_check_nval(chan)) {
2017 ERR("cond or chan is not valid");
2021 INFO_C("Incoming SCO....");
2023 if (ag_info->state < HEADSET_STATE_CONNECTED)
2024 return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
2026 sco_skt = g_io_channel_unix_get_fd(chan);
2028 cli_sco_sock = accept(sco_skt, NULL, NULL);
2029 if (cli_sco_sock < 0) {
2030 ERR("accept is failed");
2034 sco_io = g_io_channel_unix_new(cli_sco_sock);
2035 g_io_channel_set_close_on_unref(sco_io, TRUE);
2036 g_io_channel_set_encoding(sco_io, NULL, NULL);
2037 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2038 g_io_channel_set_buffered(sco_io, FALSE);
2040 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2041 (slconn && (slconn->hs_features &
2042 BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
2043 wbs_opts.wbs_enable == TRUE) {
2044 bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
2045 BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
2047 DBG("set Bluetooth voice: %d", bt_vo.setting);
2048 err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
2049 BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
2051 ERR("Sco socket set socket option failed");
2052 close(cli_sco_sock);
2057 ag_info->sco = sco_io;
2058 ag_info->sco_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
2059 __bt_ag_sco_server_conn_cb, ag_info);
2061 if (remote_dev_path)
2062 g_free(remote_dev_path);
2064 remote_dev_path = g_strdup(ag_info->path);
2066 _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
2071 static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
2073 DBG("Start SCO server");
2074 struct sco_socket_addr addr;
2077 bdaddr_t bd_addr = {{0},};
2079 if (hs->sco_server_started) {
2080 DBG("Already exsist");
2081 return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
2085 sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
2087 ERR("Can't create socket:\n");
2088 return BT_HFP_AGENT_ERROR_INTERNAL;
2091 /* Bind to local address */
2092 memset(&addr, 0, sizeof(addr));
2093 addr.sco_family = AF_BLUETOOTH;
2095 _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
2096 DBG("Bind to address %s", hs->remote_addr);
2097 memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
2099 if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2100 ERR("Can't bind socket:\n");
2104 if (listen(sco_skt, 1)) {
2105 ERR("Can not listen on the socket:\n");
2109 sco_io = g_io_channel_unix_new(sco_skt);
2110 g_io_channel_set_close_on_unref(sco_io, TRUE);
2111 g_io_channel_set_encoding(sco_io, NULL, NULL);
2112 g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
2113 g_io_channel_set_buffered(sco_io, FALSE);
2115 hs->sco_server = sco_io;
2116 hs->sco_watch_id = g_io_add_watch(sco_io,
2117 G_IO_IN | G_IO_HUP | G_IO_ERR |
2118 G_IO_NVAL, __bt_ag_sco_server_cb, hs);
2120 hs->sco_server_started = TRUE;
2121 return BT_HFP_AGENT_ERROR_NONE;
2125 return BT_HFP_AGENT_ERROR_INTERNAL;
2128 void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
2130 DBG("Stop SCO server");
2131 if (hs->sco_server) {
2132 g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
2133 g_io_channel_unref(hs->sco_server);
2134 hs->sco_server = NULL;
2136 hs->sco_server_started = FALSE;
2139 static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
2141 GIOChannel *rfcomm = hs->rfcomm;
2144 g_io_channel_shutdown(rfcomm, TRUE, NULL);
2145 g_io_channel_unref(rfcomm);
2155 static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
2158 if (cond & G_IO_NVAL)
2161 if (name_owner_sig_id != -1)
2162 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
2164 name_owner_sig_id = -1;
2168 DBG("Audio connection disconnected");
2169 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2174 void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
2176 bt_ag_slconn_t *slconn = hs->slc;
2177 const char *hs_state;
2178 hs_state_t org_state = hs->state;
2179 gboolean val = FALSE;
2181 if (org_state == state)
2184 hs_state = __bt_ag_state2str(state);
2187 case HEADSET_STATE_CONNECTING:
2188 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2190 BT_HEADSET_INTERFACE, "State",
2191 g_variant_new("s", hs_state));
2195 case HEADSET_STATE_CONNECTED:
2196 if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
2197 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2199 BT_HEADSET_INTERFACE, "State",
2200 g_variant_new("s", hs_state));
2202 if (hs->state < state) {
2204 active_devices = g_slist_append(active_devices, hs);
2205 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2207 BT_HEADSET_INTERFACE,
2209 g_variant_new("b", val));
2211 DBG("Device %s connected\n", hs->remote_addr);
2212 #if defined(TIZEN_SUPPORT_DUAL_HF)
2213 if (!hs->is_companion_device)
2214 __bt_ag_start_sco_server(hs);
2216 __bt_ag_start_sco_server(hs);
2219 /* Set default code as Gateway NB */
2220 __bt_ag_set_codec(hs, "SetNbParameters");
2221 } else if (hs->state == HEADSET_STATE_ON_CALL) {
2223 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2225 BT_HEADSET_INTERFACE,
2227 g_variant_new("b", val));
2232 case HEADSET_STATE_DISCONNECTED:
2233 __bt_ag_close_sco(hs);
2234 __bt_ag_headset_close_rfcomm(hs);
2236 if (hs->state == HEADSET_STATE_ON_CALL) {
2238 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2240 BT_HEADSET_INTERFACE,
2242 g_variant_new("b", val));
2246 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2248 BT_HEADSET_INTERFACE,
2250 g_variant_new("b", val));
2251 if (hs->state > HEADSET_STATE_CONNECTING)
2252 _bt_hfp_device_disconnected(hs);
2254 active_devices = g_slist_remove(active_devices, hs);
2256 __bt_ag_codec_negotiation_info_reset(hs, TRUE);
2257 #if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
2258 __bt_ag_set_codec(hs, "SetNbParameters");
2262 /* Since SCO server is binded on remote address */
2263 /* Need to stop SCO server once heasdet disconencted*/
2264 if (hs->sco_server_started)
2265 __bt_ag_stop_sco_server(hs);
2267 g_free(hs->remote_addr);
2271 case HEADSET_STATE_PLAY_IN_PROGRESS:
2272 case HEADSET_STATE_ON_CALL:
2274 _bt_ag_agent_emit_property_changed(ag_dbus_conn,
2276 BT_HEADSET_INTERFACE, "State",
2277 g_variant_new("s", hs_state));
2279 /*add watch for sco data */
2280 hs->sco_id = g_io_add_watch(hs->sco,
2281 G_IO_ERR | G_IO_NVAL,
2282 (GIOFunc) __bt_ag_sco_cb, hs);
2284 _bt_ag_agent_emit_property_changed(
2285 ag_dbus_conn, hs->path,
2286 BT_HEADSET_INTERFACE, "Playing",
2287 g_variant_new("b", val));
2289 if (slconn->microphone_gain >= 0)
2290 _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
2291 slconn->microphone_gain);
2293 if (slconn->speaker_gain >= 0)
2294 _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
2295 slconn->speaker_gain);
2305 INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
2306 __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
2309 static struct event at_event_callbacks[] = {
2310 { "AT+BRSF", _bt_hfp_supported_features },
2311 { "AT+CIND", _bt_hfp_report_indicators },
2312 { "AT+CMER", _bt_hfp_enable_indicators },
2313 { "AT+CHLD", _bt_hfp_call_hold },
2314 { "ATA", _bt_hfp_answer_call },
2315 { "ATD", _bt_hfp_dial_number },
2316 { "AT+VG", _bt_hfp_signal_gain_setting },
2317 { "AT+CHUP", _bt_hfp_terminate_call },
2318 { "AT+CKPD", _bt_hfp_key_press },
2319 { "AT+CLIP", _bt_hfp_cli_notification },
2320 { "AT+BTRH", _bt_hfp_response_and_hold },
2321 { "AT+BLDN", _bt_hfp_last_dialed_number },
2322 { "AT+VTS", _bt_hfp_dtmf_tone },
2323 { "AT+CNUM", _bt_hfp_subscriber_number },
2324 { "AT+CLCC", _bt_hfp_list_current_calls },
2325 { "AT+CMEE", _bt_hfp_extended_errors },
2326 { "AT+CCWA", _bt_hfp_call_waiting_notify },
2327 { "AT+COPS", _bt_hfp_operator_selection },
2328 { "AT+NREC", _bt_hfp_nr_and_ec },
2329 { "AT+BVRA", _bt_hfp_voice_dial },
2330 { "AT+XAPL", _bt_hfp_apl_command },
2331 { "AT+IPHONEACCEV", _bt_hfp_apl_command },
2332 { "AT+BIA", _bt_hfp_indicators_activation },
2333 { "AT+CPBS", _bt_hfp_select_pb_memory },
2334 { "AT+CPBR", _bt_hfp_read_pb_entries},
2335 { "AT+CPBF", _bt_hfp_find_pb_entires },
2336 { "AT+CSCS", _bt_hfp_select_character_set },
2337 { "AT+CSQ", _bt_hfp_get_signal_quality },
2338 { "AT+CBC", _bt_hfp_get_battery_charge_status },
2339 { "AT+CPAS", _bt_hfp_get_activity_status },
2340 { "AT+CGSN", _bt_hfp_get_equipment_identity },
2341 { "AT+CGMM", _bt_hfp_get_model_information },
2342 { "AT+CGMI", _bt_hfp_get_device_manufacturer },
2343 { "AT+CGMR", _bt_hfp_get_revision_information },
2344 { "AT+BAC", __bt_hfp_available_codecs },
2345 { "AT+BCC", __bt_hfp_codec_connection },
2346 { "AT+BCS", __bt_hfp_codec_selection },
2347 { "AT+XSAT", _bt_hfp_vendor_cmd },
2348 { "AT+CIMI", _bt_hfp_get_imsi },
2349 { "AT+CREG", _bt_hfp_get_creg_status },
2353 int num_of_secure_command = 4;
2354 static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
2356 void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
2360 char s[MAX_BUFFER_SIZE] = {0, };
2361 gboolean hide = FALSE;
2363 gboolean is_security_command = FALSE;
2366 strncpy(s, buf, MAX_BUFFER_SIZE - 1);
2368 for (i = 0; i < num_of_secure_command; i++) {
2369 if (strstr(buf, secure_command[i])) {
2370 is_security_command = TRUE;
2375 /* +XSAT: 11,DISC */
2376 xsat_ptr = strstr(s, "11,DISC,");
2378 xsat_ptr = xsat_ptr + 8;
2380 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2386 /* AT+XSAT=11,Q_CT,X,XXXX */
2387 xsat_ptr = strstr(s, "11,Q_CT,");
2389 xsat_ptr = xsat_ptr + 8;
2391 while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
2392 if (x > 1) /* ignore 0 and 1 position */
2399 while (s[i] != '\0') {
2400 if (s[i] == '\r' || s[i] == '\n') {
2404 hide = hide ? FALSE : TRUE;
2405 else if (is_security_command && hide) {
2413 INFO("%s Buffer = [%s], Len(%d)", message, s, strlen(s));
2418 static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
2422 __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
2424 for (ev = at_event_callbacks; ev->cmd; ev++) {
2425 if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
2426 return ev->callback(hs, buf);
2432 static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
2435 ssize_t final_written, count;
2436 char rsp_buffer[MAX_BUFFER_SIZE];
2440 count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
2442 ERR("count is %d", count);
2446 if (!hdset->io_chan) {
2447 ERR("__bt_ag_send_at_valist: headset not connected");
2453 fd = g_io_channel_unix_get_fd(hdset->io_chan);
2456 while (final_written < count) {
2460 written = write(fd, rsp_buffer + final_written,
2461 count - final_written);
2462 } while (written < 0 && errno == EINTR);
2466 ERR("write failed : %s (%d)", strerror(-err), -err);
2470 final_written += written;
2473 /* Synchronize the sending buffer */
2477 ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
2481 __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
2486 int __attribute__((format(printf, 2, 3)))
2487 _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
2492 va_start(ap, format);
2493 ret = __bt_ag_send_at_valist(hs, ap, format);
2499 void __attribute__((format(printf, 3, 4)))
2500 _bt_ag_send_foreach_headset(GSList *devices,
2501 int (*cmp) (bt_ag_info_t *hs),
2507 for (l = devices; l != NULL; l = l->next) {
2508 bt_ag_info_t *hs = l->data;
2511 if (cmp && cmp(hs) != 0)
2514 va_start(ap, format);
2515 ret = __bt_ag_send_at_valist(hs, ap, format);
2517 ERR("Failed to send to headset: %s (%d)",
2518 strerror(-ret), -ret);
2523 int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
2525 if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
2526 return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
2529 case HFP_STATE_MNGR_ERR_NONE:
2530 return _bt_ag_send_at(hs, "\r\nOK\r\n");
2531 case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
2532 return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
2534 return _bt_ag_send_at(hs, "\r\nERROR\r\n");
2538 static gboolean __bt_ag_event_handler(GIOChannel *channel,
2539 GIOCondition cond, void *user_data)
2541 bt_ag_slconn_t *slconn;
2542 unsigned char event_buf[MAX_BUFFER_SIZE];
2544 size_t available_buffer;
2546 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2549 if (cond & G_IO_NVAL)
2552 slconn = bt_ag_info->slc;
2553 if (cond & (G_IO_ERR | G_IO_HUP)) {
2554 if (bt_ag_info->watch_id)
2555 __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
2557 ERR("ERR or HUP on RFCOMM socket");
2558 INFO_C("Disconnected [AG role] [Terminated by remote dev]");
2562 fd = g_io_channel_unix_get_fd(channel);
2563 len = read(fd, event_buf, sizeof(event_buf) - 1);
2567 available_buffer = sizeof(slconn->buffer) - (slconn->start) -
2568 (slconn->length) - 1;
2569 if (available_buffer < (size_t) len) {
2570 ERR("Buffer over flow");
2574 memcpy(&slconn->buffer[slconn->start], event_buf, len);
2575 slconn->length += len;
2577 slconn->buffer[slconn->start + slconn->length] = '\0';
2579 while (slconn->length > 0) {
2584 get_cr = strchr(&slconn->buffer[slconn->start], '\r');
2588 cmd_len = 1 + (off_t) get_cr -
2589 (off_t) &slconn->buffer[slconn->start];
2593 DBG("Call AT handler");
2594 err = __bt_ag_at_handler(bt_ag_info,
2595 &slconn->buffer[slconn->start]);
2597 ERR("Failed to call AT handler");
2601 if (err == -EINVAL) {
2602 ERR("Unrecognized command: %s",
2603 &slconn->buffer[slconn->start]);
2604 err = _bt_ag_send_response(bt_ag_info,
2605 HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
2609 ERR("Error handling command %s: %s (%d)",
2610 &slconn->buffer[slconn->start],
2611 strerror(-err), -err);
2613 slconn->start += cmd_len;
2614 slconn->length -= cmd_len;
2616 if (!slconn->length)
2621 ERR("Failed in event handler - SLC Disconnect");
2622 _bt_ag_set_headset_state(bt_ag_info,
2623 HEADSET_STATE_DISCONNECTED);
2627 static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
2628 const gchar *object_path)
2632 bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
2633 struct sockaddr_remote address;
2634 socklen_t address_len;
2636 INFO_C("Connected [AG role]");
2637 bt_ag_info->rfcomm = NULL;
2638 bt_ag_info->slc = NULL;
2639 bt_ag_info->hfp_active = TRUE;
2640 bt_ag_info->vr_blacklisted = FALSE;
2641 bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
2642 bt_ag_info->sco_server_started = FALSE;
2643 __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
2645 bt_ag_info->path = device_path;
2646 DBG("device_path = [%s]", device_path);
2648 address_len = sizeof(address);
2649 if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
2650 ERR("BD_ADDR is NULL");
2652 DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
2653 bt_ag_info->fd = fd;
2654 bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
2655 flags = g_io_channel_get_flags(bt_ag_info->io_chan);
2657 flags &= ~G_IO_FLAG_NONBLOCK;
2658 flags &= G_IO_FLAG_MASK;
2659 g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
2660 g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
2661 g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
2663 bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
2665 bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
2666 __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
2667 address.remote_bdaddr.b);
2669 #if defined(TIZEN_SUPPORT_DUAL_HF)
2670 bt_ag_info->is_companion_device =
2671 __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
2674 DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
2676 if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
2677 DBG("HSP connection completed");
2678 _bt_ag_set_headset_state(bt_ag_info,
2679 HEADSET_STATE_CONNECTED);
2681 DBG("HFP connection connecting");
2682 _bt_ag_set_headset_state(bt_ag_info,
2683 HEADSET_STATE_CONNECTING);
2686 __bt_ag_agent_start_watch(bt_ag_info);
2688 bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
2689 bt_ag_info->slc->speaker_gain = 15;
2690 bt_ag_info->slc->microphone_gain = 15;
2691 bt_ag_info->slc->is_nrec = TRUE;
2696 static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
2705 fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
2708 ERR("Unable to open VR blacklist file");
2712 fseek(fp, 0, SEEK_END);
2715 ERR("size is not a positive number");
2722 buffer = g_malloc0(sizeof(char) * size);
2723 if (buffer == NULL) {
2724 ERR("g_malloc0 is failed");
2728 result = fread((char *)buffer, 1, size, fp);
2730 if (result != size) {
2736 token = strtok_r(buffer, "=", &saveptr);
2737 if (token == NULL) {
2742 while ((token = strtok_r(NULL, ",", &saveptr))) {
2743 if (strlen(token) > 8)
2745 if (0 == g_strcmp0(token, lap_addr)) {
2746 INFO("Voice Recognition blacklisted");
2755 static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
2757 bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
2758 sco_open_timer_id = 0;
2759 DBG("sco_open_request (%d)", sco_open_request);
2761 if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
2762 bt_ag_slconn_t *slconn = bt_ag_info->slc;
2764 INFO("try to open SCO");
2765 sco_open_request = FALSE;
2767 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
2768 (slconn && (slconn->hs_features &
2769 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
2770 switch (bt_ag_info->codec_info.final_codec) {
2771 case BT_CVSD_CODEC_ID:
2772 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
2773 __bt_ag_sco_connect(bt_ag_info);
2775 case BT_MSBC_CODEC_ID:
2776 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
2777 __bt_ag_sco_connect(bt_ag_info);
2780 __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
2784 __bt_ag_sco_connect(bt_ag_info);
2791 * Service level connection complete
2792 * indication and state management
2794 void _bt_ag_slconn_complete(bt_ag_info_t *hs)
2796 char lap_address[BT_LOWER_ADDRESS_LENGTH];
2798 DBG("HFP Service Level Connection established\n");
2800 /* Check device Voice Recognition blacklist status */
2801 g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
2802 hs->vr_blacklisted =
2803 __bt_ag_agent_is_device_vr_blacklisted(lap_address);
2805 if (sco_open_timer_id > 0) {
2806 g_source_remove(sco_open_timer_id);
2807 sco_open_timer_id = 0;
2810 sco_open_request = FALSE;
2811 sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
2812 __bt_sco_open_delay_timeout_cb, hs);
2814 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2817 static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
2820 g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
2821 g_io_channel_unref(hs->io_chan);
2825 __bt_ag_close_sco(hs);
2826 _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
2829 __bt_ag_agent_remove_watch(&hs->watch_id);
2831 _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
2835 static GQuark __bt_ag_agent_error_quark(void)
2839 static GQuark quark = 0;
2841 quark = g_quark_from_static_string("ag-agent");
2847 static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
2850 ERR("error[%d]\n", error);
2853 case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
2854 return g_error_new(BT_AG_AGENT_ERROR, error,
2855 BT_ERROR_NOT_AVAILABLE);
2856 case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
2857 return g_error_new(BT_AG_AGENT_ERROR, error,
2858 BT_ERROR_NOT_CONNECTED);
2859 case BT_HFP_AGENT_ERROR_BUSY:
2860 return g_error_new(BT_AG_AGENT_ERROR, error,
2862 case BT_HFP_AGENT_ERROR_INVALID_PARAM:
2863 return g_error_new(BT_AG_AGENT_ERROR, error,
2864 BT_ERROR_INVALID_PARAM);
2865 case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
2866 return g_error_new(BT_AG_AGENT_ERROR, error,
2867 BT_ERROR_ALREADY_EXSIST);
2868 case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
2869 return g_error_new(BT_AG_AGENT_ERROR, error,
2870 BT_ERROR_ALREADY_CONNECTED);
2871 case BT_HFP_AGENT_ERROR_NO_MEMORY:
2872 return g_error_new(BT_AG_AGENT_ERROR, error,
2873 BT_ERROR_NO_MEMORY);
2874 case BT_HFP_AGENT_ERROR_I_O_ERROR:
2875 return g_error_new(BT_AG_AGENT_ERROR, error,
2876 BT_ERROR_I_O_ERROR);
2877 case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
2878 return g_error_new(BT_AG_AGENT_ERROR, error,
2879 BT_ERROR_OPERATION_NOT_AVAILABLE);
2880 case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
2881 return g_error_new(BT_AG_AGENT_ERROR, error,
2883 case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
2884 return g_error_new(BT_AG_AGENT_ERROR, error,
2886 case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
2887 return g_error_new(BT_AG_AGENT_ERROR, error,
2888 BT_ERROR_NO_CALL_LOG);
2889 case BT_HFP_AGENT_ERROR_INTERNAL:
2891 return g_error_new(BT_AG_AGENT_ERROR, error,
2897 static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
2901 for (l = active_devices ; l; l = l->next) {
2902 bt_ag_info_t *data = l->data;
2903 if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
2905 if (g_strcmp0(data->path, device_path) == 0) {
2906 INFO("Active device found");
2911 INFO("Active device not found");
2915 static void __bt_ag_agent_method(GDBusConnection *connection,
2916 const gchar *sender,
2917 const gchar *object_path,
2918 const gchar *interface_name,
2919 const gchar *method_name,
2920 GVariant *parameters,
2921 GDBusMethodInvocation *invocation,
2926 INFO("method %s", method_name);
2927 INFO("object_path %s", object_path);
2928 int ret = BT_HFP_AGENT_ERROR_NONE;
2930 const gchar *device_path = NULL;
2932 if (g_strcmp0(method_name, "NewConnection") == 0) {
2936 GUnixFDList *fd_list;
2937 GVariant *options = NULL;
2938 int device_count = 0;
2940 device_count = g_slist_length(active_devices);
2942 INFO("device_count %d", device_count);
2944 if (device_count >= MAX_CONNECTED_DEVICES) {
2945 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2949 g_variant_get(parameters, "(oha{sv})",
2950 &device_path, &index, &options);
2952 #if defined(TIZEN_SUPPORT_DUAL_HF) && defined(TIZEN_PROFILE_WEARABLE)
2954 * Below code is not required for dual HF support for
2958 __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
2959 INFO("not allow to connect 2nd HF connection");
2960 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2964 msg = g_dbus_method_invocation_get_message(invocation);
2965 fd_list = g_dbus_message_get_unix_fd_list(msg);
2966 if (fd_list == NULL) {
2967 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2971 fd = g_unix_fd_list_get(fd_list, index, NULL);
2973 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2977 DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
2979 if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
2980 ret = BT_HFP_AGENT_ERROR_INTERNAL;
2984 g_dbus_method_invocation_return_value(invocation, NULL);
2985 } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
2988 g_variant_get(parameters, "(o)", &device_path);
2989 INFO("device_path %s", device_path);
2991 for (l = active_devices; l; l = l->next) {
2992 bt_ag_info_t *data = l->data;
2994 INFO("data->path %s", data->path);
2995 if (g_strcmp0(data->path, device_path) == 0) {
2996 if (!__bt_ag_agent_connection_release(data)) {
2997 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3000 INFO_C("Disconnected [AG role] [Terminated by local host]");
3001 g_dbus_method_invocation_return_value(invocation, NULL);
3004 } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
3006 gchar *address = NULL;
3007 g_variant_get(parameters, "(&s&s)", &path, &address);
3008 /*local_addr = malloc(strlen(address));
3009 memcpy(local_addr, address, strlen(address));*/
3011 DBG("Sender = %s, Application path = %s\n", sender, path);
3012 ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
3017 local_addr = g_strdup(address);
3018 DBG("Address = %s\n", local_addr);
3019 g_dbus_method_invocation_return_value(invocation, NULL);
3020 } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
3022 g_variant_get(parameters, "(&s)", &path);
3024 DBG("Application path = %s\n", path);
3025 DBG("Sender = %s\n", sender);
3027 ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
3031 g_dbus_method_invocation_return_value(invocation, NULL);
3032 } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
3034 gchar *number = NULL;
3037 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3039 DBG("Application path = %s", path);
3040 DBG_SECURE("Phone number = %s", number);
3041 DBG("Call id = %d", call_id);
3043 DBG("Sender = %s", sender);
3045 ret = _bt_hfp_incoming_call(path, number, call_id, sender);
3048 g_dbus_method_invocation_return_value(invocation, NULL);
3049 } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
3051 gchar *number = NULL;
3054 g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
3056 DBG("Application path = %s", path);
3057 DBG_SECURE("Phone number = %s", number);
3058 DBG("Call id = %d", call_id);
3060 DBG("Sender = %s", sender);
3062 ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
3065 g_dbus_method_invocation_return_value(invocation, NULL);
3066 } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
3068 gchar *number = NULL;
3073 g_variant_get(parameters, "(&s&sii)",
3074 &path, &number, &status, &call_id);
3075 DBG("Application path = %s\n", path);
3076 DBG_SECURE("Number = %s\n", number);
3077 DBG("Status = %d\n", status);
3078 DBG("Call id = %d\n", call_id);
3079 DBG("Sender = %s\n", sender);
3081 ret = _bt_hfp_change_call_status(path,
3082 number, status, call_id, sender);
3084 if (_bt_hfp_is_call_exist() == FALSE) {
3085 for (l = active_devices; l; l = l->next) {
3086 bt_ag_info_t *data = l->data;
3088 if (data->state == HEADSET_STATE_ON_CALL) {
3089 __bt_ag_close_sco(data);
3090 _bt_ag_set_headset_state(data,
3091 HEADSET_STATE_CONNECTED);
3098 g_dbus_method_invocation_return_value(invocation, NULL);
3099 } else if (g_strcmp0(method_name, "GetProperties") == 0) {
3100 GVariantBuilder *builder;
3102 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3105 gchar *codec = g_strdup("codec");
3106 gchar *nrec = g_strdup("nrec");
3108 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3110 g_variant_builder_add(builder, "{sv}",
3111 codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
3112 g_variant_builder_add(builder, "{sv}",
3113 nrec, g_variant_new("b", bt_ag_info->nrec_status));
3115 var_data = g_variant_new("(a{sv})", builder);
3116 g_variant_builder_unref(builder);
3117 g_dbus_method_invocation_return_value(invocation, var_data);
3122 } else if (g_strcmp0(method_name, "Disconnect") == 0) {
3123 char hdset_address[18] = { 0, };
3126 for (l = active_devices; l; l = l->next) {
3127 bt_ag_info_t *data = l->data;
3129 __bt_convert_addr_type_to_rev_string(hdset_address,
3130 (unsigned char *)data->remote_addr);
3132 DBG("Disconnect Headset %s, %s\n",
3133 hdset_address, data->path);
3134 _bt_ag_set_headset_state(data,
3135 HEADSET_STATE_DISCONNECTED);
3137 g_dbus_method_invocation_return_value(invocation, NULL);
3138 } else if (g_strcmp0(method_name, "IsConnected") == 0) {
3139 gboolean is_connected = FALSE;
3142 for (l = active_devices; l; l = l->next) {
3143 bt_ag_info_t *data = l->data;
3145 if (data->state == HEADSET_STATE_CONNECTED)
3146 is_connected = TRUE;
3148 DBG("is_connected : %s",
3149 is_connected ? "Connected" : "Disconnected");
3151 g_dbus_method_invocation_return_value(invocation,
3152 g_variant_new("(b)", is_connected));
3153 } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
3156 if (0 == g_slist_length(active_devices)) {
3157 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3161 if (ag.ring_timer) {
3162 DBG("IndicateCall received when already indicating");
3163 g_dbus_method_invocation_return_value(invocation, NULL);
3166 for (l = active_devices; l; l = l->next) {
3167 bt_ag_info_t *data = l->data;
3169 if (data->state >= HEADSET_STATE_CONNECTED)
3170 _bt_ag_send_at(data, "\r\nRING\r\n");
3173 __bt_ring_timer_cb(NULL);
3174 ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
3175 __bt_ring_timer_cb, NULL);
3176 g_dbus_method_invocation_return_value(invocation, NULL);
3177 } else if (g_strcmp0(method_name, "CancelCall") == 0) {
3178 if (0 == g_slist_length(active_devices)) {
3179 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3183 if (ag.ring_timer) {
3184 g_source_remove(ag.ring_timer);
3187 DBG("Got CancelCall method call but no call is active");
3189 g_dbus_method_invocation_return_value(invocation, NULL);
3190 } else if (g_strcmp0(method_name, "Play") == 0) {
3191 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3192 bt_ag_slconn_t *slconn = NULL;
3195 slconn = bt_ag_info->slc;
3197 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3201 #ifndef __TIZEN_OPEN__
3204 if (slconn && FALSE == slconn->is_voice_recognition_running &&
3205 mdm_get_service() == MDM_RESULT_SUCCESS) {
3206 mode = mdm_get_allow_bluetooth_outgoing_call();
3207 mdm_release_service();
3209 if (mode == MDM_RESTRICTED) {
3210 ERR("[MDM] Not allow the outgoing call");
3211 ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
3218 switch (bt_ag_info->state) {
3219 case HEADSET_STATE_CONNECTING:
3220 case HEADSET_STATE_DISCONNECTED:
3221 ERR("HEADSET_STATE ERROR");
3222 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3224 case HEADSET_STATE_CONNECTED:
3226 case HEADSET_STATE_PLAY_IN_PROGRESS:
3227 ERR("Play In Progress");
3228 ret = BT_HFP_AGENT_ERROR_BUSY;
3236 if (sco_open_timer_id > 0) {
3237 INFO("SCO open delay");
3238 sco_open_request = TRUE;
3239 g_dbus_method_invocation_return_value(invocation, NULL);
3243 if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
3244 (slconn && (slconn->hs_features &
3245 BT_HF_FEATURE_CODEC_NEGOTIATION))) {
3246 switch (bt_ag_info->codec_info.final_codec) {
3247 case BT_CVSD_CODEC_ID:
3248 __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
3249 ret = __bt_ag_sco_connect(bt_ag_info);
3251 case BT_MSBC_CODEC_ID:
3252 __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
3253 ret = __bt_ag_sco_connect(bt_ag_info);
3256 ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
3260 ret = __bt_ag_sco_connect(bt_ag_info);
3266 sco_owner = g_strdup(sender);
3268 g_dbus_method_invocation_return_value(invocation, NULL);
3270 name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
3271 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
3272 __bt_ag_name_owner_changed_cb, NULL, NULL);
3273 } else if (g_strcmp0(method_name, "Stop") == 0) {
3276 for (l = active_devices; l; l = l->next) {
3277 bt_ag_info_t *data = l->data;
3279 if (data->state > HEADSET_STATE_CONNECTED) {
3280 __bt_ag_close_sco(data);
3281 _bt_ag_set_headset_state(data,
3282 HEADSET_STATE_CONNECTED);
3286 g_dbus_method_invocation_return_value(invocation, NULL);
3287 } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
3288 gboolean is_playing = FALSE;
3291 for (l = active_devices; l; l = l->next) {
3292 bt_ag_info_t *data = l->data;
3294 if (data->state == HEADSET_STATE_ON_CALL)
3297 DBG("is_playing : %s", is_playing ? "Playing" : "Not Playing");
3299 g_dbus_method_invocation_return_value(invocation,
3300 g_variant_new("(b)", is_playing));
3301 } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
3302 bt_ag_slconn_t *slconn = NULL;
3303 guint16 gain_value = 0;
3304 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3306 if (bt_ag_info == NULL) {
3307 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3311 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3312 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3316 slconn = bt_ag_info->slc;
3318 gain_value = (guint16) slconn->speaker_gain;
3320 g_dbus_method_invocation_return_value(invocation,
3321 g_variant_new("(q)", gain_value));
3322 } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
3324 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3326 g_variant_get(parameters, "(q)", &gain);
3327 DBG("Speaker gain = %d\n", gain);
3329 if (bt_ag_info == NULL) {
3330 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3334 ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
3337 g_dbus_method_invocation_return_value(invocation, NULL);
3338 } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
3339 bt_ag_slconn_t *slconn = NULL;
3340 guint16 gain_value = 0;
3341 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3343 if (bt_ag_info == NULL) {
3344 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3348 if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
3349 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3353 slconn = bt_ag_info->slc;
3355 gain_value = (guint16) slconn->microphone_gain;
3357 g_dbus_method_invocation_return_value(invocation,
3358 g_variant_new("(q)", gain_value));
3359 } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
3361 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3363 g_variant_get(parameters, "(q)", &gain);
3364 DBG("Microphone gain = %d\n", gain);
3366 if (bt_ag_info == NULL) {
3367 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3371 ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
3374 g_dbus_method_invocation_return_value(invocation, NULL);
3375 } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
3376 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3377 if (bt_ag_info == NULL) {
3378 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3382 bt_ag_slconn_t *slconn = bt_ag_info->slc;
3385 g_variant_get(parameters, "(b)", &enable);
3386 DBG("VoiceDail enable = %d\n", enable);
3388 if ((slconn && !(slconn->hs_features &
3389 BT_HF_FEATURE_VOICE_RECOGNITION)))
3390 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3391 else if (bt_ag_info->vr_blacklisted)
3392 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3394 ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
3397 slconn->is_voice_recognition_running = enable;
3401 g_dbus_method_invocation_return_value(invocation, NULL);
3402 } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
3404 bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
3405 if (bt_ag_info == NULL) {
3406 ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
3410 g_variant_get(parameters, "(&s)", &cmd);
3412 ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
3416 DBG("vendor cmd = %s", cmd);
3418 ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
3421 g_dbus_method_invocation_return_value(invocation, NULL);
3422 } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
3423 DBG("Already pass dbus SMACK for bt-service::platform");
3424 /* Return success */
3425 g_dbus_method_invocation_return_value(invocation, NULL);
3426 } else if (g_strcmp0(method_name, "SwapHeadset") == 0) {
3429 char address[BT_ADDRESS_STRING_SIZE];
3430 char remote_addr[BT_ADDRESS_STRING_SIZE];
3431 gboolean device_found = FALSE;
3433 g_variant_get(parameters, "(s)", &addr);
3434 g_strlcpy(address, addr, sizeof(address));
3435 DBG("Sender = %s", sender);
3437 /* Loop through connected headset list
3438 * If found, update the remote_dev_path.
3440 for (l = active_devices ; l; l = l->next) {
3441 bt_ag_info_t *data = l->data;
3442 g_strlcpy(remote_addr, data->remote_addr, sizeof(remote_addr));
3443 if (g_strcmp0(remote_addr, address) == 0) {
3444 DBG("Active device found");
3445 if (data->path == NULL) {
3446 DBG("device path is null");
3447 ret = BT_HFP_AGENT_ERROR_INTERNAL;
3450 remote_dev_path = g_strdup(data->path);
3451 DBG("Setting device path %s as active device path", remote_dev_path);
3452 device_found = TRUE;
3457 if (!device_found) {
3458 ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
3462 g_dbus_method_invocation_return_value(invocation, NULL);
3469 err = __bt_ag_agent_set_error(ret);
3470 g_dbus_method_invocation_return_gerror(invocation, err);
3475 static const GDBusInterfaceVTable method_table = {
3476 __bt_ag_agent_method,
3481 static GDBusNodeInfo *__bt_ag_create_method_node_info
3482 (const gchar *introspection_data)
3485 GDBusNodeInfo *node_info = NULL;
3487 if (introspection_data == NULL)
3490 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
3493 ERR("Unable to create node: %s", err->message);
3494 g_clear_error(&err);
3499 static GDBusConnection *__bt_ag_get_gdbus_connection(void)
3505 if (ag_dbus_conn == NULL)
3506 ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
3508 if (!ag_dbus_conn) {
3510 ERR("Unable to connect to dbus: %s", err->message);
3511 g_clear_error(&err);
3517 return ag_dbus_conn;
3520 static gboolean __bt_ag_register_profile_methods(void)
3523 GError *error = NULL;
3525 GDBusNodeInfo *node_info = NULL;
3528 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
3530 G_BUS_NAME_OWNER_FLAGS_NONE,
3534 DBG("owner_id is [%d]", owner_id);
3536 node_info = __bt_ag_create_method_node_info(
3537 ag_agent_bluez_introspection_xml);
3538 if (node_info == NULL)
3541 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3542 DBG("path is [%s]", path);
3544 hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3545 node_info->interfaces[0],
3547 NULL, NULL, &error);
3548 if (hf_bluez_id == 0) {
3549 ERR("Failed to register: %s", error->message);
3550 g_error_free(error);
3552 g_dbus_node_info_unref(node_info);
3557 /* Ag register profile methods for HSP*/
3559 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
3560 DBG("path is [%s]", path);
3562 hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3563 node_info->interfaces[0],
3565 NULL, NULL, &error);
3566 if (hs_bluez_id == 0) {
3567 ERR("Failed to register: %s", error->message);
3568 g_error_free(error);
3570 g_dbus_node_info_unref(node_info);
3574 g_dbus_node_info_unref(node_info);
3576 node_info = __bt_ag_create_method_node_info
3577 (ag_agent_app_introspection_xml);
3578 if (node_info == NULL)
3581 path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
3582 DBG("path is [%s]", path);
3584 app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
3585 node_info->interfaces[0],
3587 NULL, NULL, &error);
3589 ERR("Failed to register: %s", error->message);
3590 g_error_free(error);
3592 g_dbus_node_info_unref(node_info);
3596 g_dbus_node_info_unref(node_info);
3602 static void __bt_ag_unregister_profile_methods(void)
3606 if (hf_bluez_id > 0) {
3607 g_dbus_connection_unregister_object(ag_dbus_conn,
3612 if (hs_bluez_id > 0) {
3613 g_dbus_connection_unregister_object(ag_dbus_conn,
3619 g_dbus_connection_unregister_object(ag_dbus_conn,
3625 static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
3626 const gchar *path, const gchar *interface)
3628 return (service_gproxy) ? service_gproxy :
3629 __bt_ag_gdbus_init_service_proxy(service,
3633 static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
3634 char *profile_uuid, const char* profile_name)
3639 GError *error = NULL;
3640 GVariantBuilder *builder;
3642 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3643 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3648 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
3650 g_variant_builder_add(builder, "{sv}",
3651 "Name", g_variant_new("s",
3653 g_variant_builder_add(builder, "{sv}",
3654 "Version", g_variant_new("q", profile_version));
3655 /*g_variant_builder_add(builder, "{sv}",
3656 "Role", g_variant_new("s","client"));*/
3657 if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
3658 g_variant_builder_add(builder, "{sv}",
3659 "features", g_variant_new("q", ag.sdp_features));
3662 ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
3663 g_variant_new("(osa{sv})", path,
3664 profile_uuid, builder),
3665 G_DBUS_CALL_FLAGS_NONE, -1,
3667 g_variant_builder_unref(builder);
3668 /* set the name and role for the profile*/
3670 /* dBUS-RPC is failed */
3671 ERR("dBUS-RPC is failed");
3673 if (error != NULL) {
3674 /* dBUS gives error cause */
3675 ERR("D-Bus API failure: errCode[%x], message[%s]",
3676 error->code, error->message);
3678 g_clear_error(&error);
3683 g_variant_unref(ret);
3690 static void __bt_ag_agent_unregister(gchar *path)
3695 GError *error = NULL;
3697 proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
3698 "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
3703 ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
3704 g_variant_new("(o)", path),
3705 G_DBUS_CALL_FLAGS_NONE, -1,
3708 /* set the name and role for the profile*/
3710 /* dBUS-RPC is failed */
3711 ERR("dBUS-RPC is failed");
3713 if (error != NULL) {
3714 /* dBUS gives error cause */
3715 ERR("D-Bus API failure: errCode[%x], message[%s]",
3716 error->code, error->message);
3718 g_clear_error(&error);
3722 g_variant_unref(ret);
3732 static void __bt_ag_agent_battery_status_cb(keynode_t *node)
3734 int batt = vconf_keynode_get_int(node);
3736 _bt_hfp_set_property_value("BatteryBarsChanged", batt);
3739 static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
3741 int signal_bar = vconf_keynode_get_int(node);
3743 BT_CHECK_SIGNAL_STRENGTH(signal_bar);
3744 _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
3747 static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
3749 gboolean status = vconf_keynode_get_bool(node);
3751 DBG("status = %d", status);
3753 if (status == TRUE) {
3754 for (l = active_devices; l; l = l->next) {
3755 bt_ag_info_t *data = l->data;
3756 _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
3761 static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
3763 int service = vconf_keynode_get_int(node);
3764 bt_hfp_agent_network_registration_status_t network_service;
3768 DBG("Current Signal Level = [%d] \n", service);
3771 case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
3772 case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
3773 case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
3781 ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
3783 ERR("Get roaming status failed err = %d\n", ret);
3787 if (roam_status == 0 && service == 1)
3788 network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
3789 else if (roam_status == 1 && service == 1)
3790 network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
3792 network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
3794 _bt_hfp_set_property_value("RegistrationChanged", network_service);
3797 static void __bt_ag_agent_subscribe_vconf_updates(void)
3803 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3804 (void *)__bt_ag_agent_battery_status_cb, NULL);
3806 ERR("Subsrciption to battery status failed err = [%d]\n", ret);
3808 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
3809 (void *)__bt_ag_agent_network_signal_status_cb, NULL);
3811 ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
3813 ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3814 (void *)__bt_ag_agent_network_register_status_cb, NULL);
3816 ERR("Subsrciption to network failed err = [%d]\n", ret);
3818 if (TIZEN_PROFILE_WEARABLE) {
3819 ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
3820 (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
3822 ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
3826 static void __bt_ag_agent_release_vconf_updates(void)
3832 ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
3833 (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
3835 ERR("vconf_ignore_key_changed failed\n");
3837 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
3838 (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
3840 ERR("vconf_ignore_key_changed failed\n");
3842 ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
3843 (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
3845 ERR("vconf_ignore_key_changed failed\n");
3848 static gboolean __bt_ag_agent_send_subscriber_number_changed(
3851 const char *property = g_strdup("SubscriberNumberChanged");
3855 DBG("Number is %s", number);
3857 if (!_bt_hfp_set_property_name(property, number)) {
3858 DBG("Error- set property for subscriber no change - ERROR\n");
3859 g_free((void *)property);
3862 g_free((void *)property);
3866 static void __bt_ag_agent_sigterm_handler(int signo)
3871 ERR_C("***** Signal handler came with signal %d *****", signo);
3873 for (l = active_devices ; l; l = l->next) {
3874 bt_ag_info_t *data = l->data;
3875 if (!__bt_ag_agent_connection_release(data))
3876 ERR("__bt_ag_agent_connection_release failed");
3879 g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
3882 g_main_loop_quit(gmain_loop);
3886 INFO("Terminating AG agent");
3890 if (signo == SIGTERM)
3893 for (i = 0; i < BT_AG_SIG_NUM; i++)
3894 sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
3899 static void __bt_ag_agent_tel_cb(TapiHandle *handle,
3904 TelSimMsisdnList_t *number;
3905 gchar *subscriber_number;
3907 ERR("*********** result = %d", result);
3909 if (result == TAPI_API_SIM_LOCKED ||
3910 result == TAPI_API_SIM_NOT_INITIALIZED ||
3911 result == TAPI_API_SERVICE_NOT_READY) {
3912 DBG("initializing the tapi event for SIM status");
3913 __bt_ag_agent_reg_sim_event(handle, user_data);
3920 number = (TelSimMsisdnList_t *)data;
3921 subscriber_number = g_strdup(number->list[0].num);
3922 __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
3923 g_free(subscriber_number);
3926 static void __bt_ag_agent_on_noti_sim_status(TapiHandle *handle,
3927 const char *noti_id, void *data, void *user_data)
3929 TelSimCardStatus_t *status = data;
3932 DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
3934 if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
3935 __bt_ag_agent_dereg_sim_event(handle);
3936 tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
3938 if (tapi_result != TAPI_API_SUCCESS)
3939 ERR("Fail to get sim info: %d", tapi_result);
3943 static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data)
3946 ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
3947 __bt_ag_agent_on_noti_sim_status, user_data);
3949 if (ret != TAPI_API_SUCCESS)
3950 ERR("event register failed(%d)", ret);
3953 static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle)
3956 ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
3958 if (ret != TAPI_API_SUCCESS)
3959 ERR("event deregister failed(%d)", ret);
3962 static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
3963 const gchar *sender_name,
3964 const gchar *object_path,
3965 const gchar *interface_name,
3966 const gchar *signal_name,
3967 GVariant *parameters,
3971 char *name_owner = NULL;
3972 char *old_owner = NULL;
3973 char *new_owner = NULL;
3975 if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
3978 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
3980 _bt_hfp_release_all_calls_by_sender(name_owner);
3982 if (sco_owner == NULL)
3985 if (strcasecmp(name_owner, sco_owner) == 0) {
3986 if (name_owner_sig_id != -1)
3987 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
3989 name_owner_sig_id = -1;
3993 for (l = active_devices ; l; l = l->next) {
3994 bt_ag_info_t *data = l->data;
3997 __bt_ag_close_sco(data);
3998 _bt_ag_set_headset_state(data,
3999 HEADSET_STATE_CONNECTED);
4006 static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
4007 const gchar *sender_name,
4008 const gchar *object_path,
4009 const gchar *interface_name,
4010 const gchar *signal_name,
4011 GVariant *parameters,
4016 GVariant *optional_param = NULL;
4018 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
4020 g_variant_get(parameters, "(&o@a{sa{sv}})",
4021 &path, &optional_param);
4024 g_variant_unref(optional_param);
4025 ERR("Invalid adapter path");
4029 INFO("Adapter Path = [%s]", path);
4030 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4031 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4032 __bt_ag_agent_register(path, hfp_ver,
4033 HFP_AG_UUID, "Hands-Free Audio Gateway");
4035 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4036 __bt_ag_agent_register(path, hsp_ver,
4037 HSP_AG_UUID, "Headset Audio Gateway");
4039 } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
4040 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
4043 g_variant_unref(optional_param);
4044 ERR("Invalid adapter path");
4048 INFO("Adapter Path = [%s]", path);
4049 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
4050 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4051 __bt_ag_agent_unregister(path);
4053 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4054 __bt_ag_agent_unregister(path);
4059 g_variant_unref(optional_param);
4064 static void __bt_ag_agent_dbus_deinit(void)
4067 if (service_gproxy) {
4068 g_object_unref(service_gproxy);
4069 service_gproxy = NULL;
4073 g_object_unref(app_gproxy);
4078 __bt_ag_unregister_profile_methods();
4080 if (owner_sig_id != -1)
4081 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4084 if (name_owner_sig_id != -1)
4085 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4087 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4088 if (media_sig_id != -1)
4089 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4092 if (media_state_sig_id != -1)
4093 g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
4094 media_state_sig_id);
4096 name_owner_sig_id = -1;
4100 g_object_unref(ag_dbus_conn);
4101 ag_dbus_conn = NULL;
4106 static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
4109 GDBusProxy *manager_proxy = NULL;
4110 GVariant *result = NULL;
4111 char *adapter_path = NULL;
4114 return BT_HFP_AGENT_ERROR_INTERNAL;
4116 manager_proxy = g_dbus_proxy_new_sync(conn,
4117 G_DBUS_PROXY_FLAGS_NONE, NULL,
4120 BT_MANAGER_INTERFACE,
4123 if (!manager_proxy) {
4124 ERR("Unable to create proxy: %s", err->message);
4128 result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
4129 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
4132 ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
4134 ERR("Fail to get DefaultAdapter");
4139 if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
4140 ERR("Incorrect result\n");
4144 g_variant_get(result, "(&o)", &adapter_path);
4146 if (adapter_path == NULL ||
4147 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
4148 ERR("Adapter path is inproper\n");
4153 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
4155 g_variant_unref(result);
4156 g_object_unref(manager_proxy);
4161 g_clear_error(&err);
4164 g_variant_unref(result);
4167 g_object_unref(manager_proxy);
4169 return BT_HFP_AGENT_ERROR_INTERNAL;
4173 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4174 void _bt_ag_agent_check_transport_state(void)
4178 if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
4182 proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
4183 G_DBUS_PROXY_FLAGS_NONE, NULL,
4184 "org.PulseAudio2", A2DP_SOURCE_ENDPOINT,
4185 BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
4189 ERR("Unable to create proxy: %s", err->message);
4190 g_clear_error(&err);
4194 INFO_C("SuspendMedia initiated");
4196 g_dbus_proxy_call(proxy,
4197 "SuspendMedia", NULL,
4198 G_DBUS_CALL_FLAGS_NONE, 2000,
4200 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4206 static void __bt_ag_agent_transport_state_update(const char *value)
4209 if (!g_strcmp0(value, "idle"))
4210 transport_state = MEDIA_TRANSPORT_STATE_IDLE;
4211 else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
4212 transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
4214 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4216 INFO_C("transport_state %d", transport_state);
4219 static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
4220 const gchar *sender_name,
4221 const gchar *object_path,
4222 const gchar *interface_name,
4223 const gchar *signal_name,
4224 GVariant *parameters,
4229 GVariant *dict_param = NULL;
4230 GVariant *optional_param = NULL;
4232 if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
4233 if (g_strcmp0(g_variant_get_type_string(parameters),
4235 ERR("Incorrect parameters\n");
4239 g_variant_get(parameters, "(&s@a{sv}@as)",
4240 &inter, &dict_param, &optional_param);
4241 if (dict_param && (!g_strcmp0(inter,
4242 BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
4243 GVariantIter *iter = NULL;
4244 const gchar *key = NULL;
4245 GVariant *value_var = NULL;
4246 gchar *value = NULL;
4247 g_variant_get(dict_param, "a{sv}", &iter);
4248 while (g_variant_iter_loop(
4249 iter, "{sv}", &key, &value_var)) {
4251 if (g_strcmp0(key, "State") == 0) {
4252 value = (gchar *)g_variant_get_string(
4255 DBG("value %s", value);
4256 __bt_ag_agent_transport_state_update(value);
4260 g_variant_iter_free(iter);
4261 g_variant_unref(dict_param);
4263 } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
4264 char *profile_uuid = NULL;
4267 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
4268 if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
4269 (state == BT_PROFILE_STATE_DISCONNECTED)) {
4270 DBG("Updating the transport state");
4271 __bt_ag_agent_transport_state_update("Disconnect");
4276 g_variant_unref(dict_param);
4279 g_variant_unref(optional_param);
4284 static void __bt_ag_agent_dbus_init(void)
4288 if (__bt_ag_get_gdbus_connection() == NULL) {
4289 ERR("Error in creating the gdbus connection\n");
4292 if (!__bt_ag_register_profile_methods()) {
4293 ERR("Error in HFP / HSP register_profile_methods\n");
4297 if (!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
4299 gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
4300 __bt_ag_agent_register(path, hfp_ver,
4301 HFP_AG_UUID, "Hands-Free Audio Gateway");
4303 path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
4304 __bt_ag_agent_register(path, hsp_ver,
4305 HSP_AG_UUID, "Headset Audio Gateway");
4308 owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4309 NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
4310 __bt_ag_agent_filter_cb, NULL, NULL);
4311 #ifdef TIZEN_FEATURE_BT_MEDIA_ENHANCE
4312 media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4313 NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
4314 NULL, 0, __bt_ag_agent_media_filter_cb,
4317 media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
4318 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
4319 NULL, 0, __bt_ag_agent_media_filter_cb,
4322 transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
4328 static uint32_t __bt_ag_agent_get_ag_features(void)
4331 uint32_t ag_features = BT_AG_FEATURE_EC_AND_NR |
4332 BT_AG_FEATURE_REJECT_CALL |
4333 BT_AG_FEATURE_ENHANCED_CALL_STATUS |
4334 BT_AG_FEATURE_THREE_WAY_CALL |
4335 BT_AG_FEATURE_VOICE_RECOGNITION |
4336 BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
4339 #if defined(TIZEN_FEATURE_BT_HFP_AG)
4340 hfp_ver = HFP_VERSION_1_6;
4342 hfp_ver = HFP_VERSION_1_5;
4344 hsp_ver = HSP_VERSION_1_2;
4346 if (hfp_ver == HFP_VERSION_1_6)
4347 ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
4351 void *__bt_ag_agent_telephony_init(void *arg)
4355 uint32_t ag_features = *((uint32_t *)arg);
4357 INFO_C("Initializing the telephony info");
4359 _bt_hfp_initialize_telephony_manager(ag_features);
4360 __bt_ag_agent_subscribe_vconf_updates();
4362 tapi_handle = tel_init(NULL);
4363 tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
4365 if (tapi_result != TAPI_API_SUCCESS)
4366 ERR("Fail to get sim info: %d", tapi_result);
4373 uint32_t ag_features;
4374 struct sigaction sa;
4375 pthread_t thread_id;
4377 INFO_C("### Starting Bluetooth AG agent");
4379 ag_features = __bt_ag_agent_get_ag_features();
4381 ag.sdp_features = (uint16_t) ag_features & 0x1F;
4383 if (hfp_ver == HFP_VERSION_1_6 && wbs_en == TRUE)
4384 ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
4386 memset(&sa, 0, sizeof(sa));
4387 sa.sa_flags = SA_NOCLDSTOP;
4388 sa.sa_handler = __bt_ag_agent_sigterm_handler;
4390 for (i = 0; i < BT_AG_SIG_NUM; i++)
4391 sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
4393 gmain_loop = g_main_loop_new(NULL, FALSE);
4395 if (gmain_loop == NULL) {
4396 ERR("GMainLoop create failed");
4397 return EXIT_FAILURE;
4400 __bt_ag_agent_dbus_init();
4401 if (pthread_create(&thread_id, NULL,
4402 (void *)&__bt_ag_agent_telephony_init,
4403 &ag_features) < 0) {
4404 ERR("pthread_create() is failed");
4405 return EXIT_FAILURE;
4408 if (pthread_detach(thread_id) < 0)
4409 ERR("pthread_detach() is failed");
4411 g_main_loop_run(gmain_loop);
4415 tel_deinit(tapi_handle);
4417 __bt_ag_agent_dbus_deinit();
4418 _bt_hfp_deinitialize_telephony_manager();
4419 __bt_ag_agent_release_vconf_updates();
4421 if (remote_dev_path)
4422 g_free(remote_dev_path);
4425 g_main_loop_unref(gmain_loop);
4427 INFO_C("### Terminating Bluetooth AG agent");