2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include <dbus/dbus.h>
24 #include <vconf-keys.h>
26 #include "bt-common.h"
27 #include "bluetooth-telephony-api.h"
30 #define BT_SCO_TIMEOUT 3000
32 #define BT_CVSD_CODEC_ID 1
33 #define BT_MSBC_CODEC_ID 2
36 GDBusConnection *conn;
38 GDBusProxy *dbus_proxy;
39 GDBusProxy *manager_proxy;
40 } telephony_dbus_info_t;
43 bt_telephony_func_ptr cb;
44 unsigned int call_count;
46 char address[BT_ADDRESS_STR_LEN];
47 char call_path[BT_AUDIO_CALL_PATH_LEN];
48 bluetooth_headset_state_t headset_state;
50 } bt_telephony_info_t;
53 char *src_addr = NULL;
56 #define BLUETOOTH_TELEPHONY_ERROR (__bluetooth_telephony_error_quark())
58 #define BLUEZ_SERVICE_NAME "org.bluez"
59 #define BLUEZ_HEADSET_INTERFACE "org.bluez.Headset"
61 #define BLUEZ_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
62 #define BLUEZ_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
63 #define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
64 #define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
65 #define HFP_AGENT_SERVICE "org.bluez.ag_agent"
68 #define HFP_AGENT_PATH "/org/bluez/hfp_agent"
69 #define HFP_AGENT_INTERFACE "Org.Hfp.App.Interface"
71 #define TELEPHONY_APP_INTERFACE "org.tizen.csd.Call.Instance"
72 #define CSD_CALL_APP_PATH "/org/tizen/csd/%d"
73 #define HFP_NREC_STATUS_CHANGE "NrecStatusChanged"
74 #define HFP_ANSWER_CALL "Answer"
75 #define HFP_REJECT_CALL "Reject"
76 #define HFP_RELEASE_CALL "Release"
77 #define HFP_THREEWAY_CALL "Threeway"
79 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
81 /*Below Inrospection data is exposed to bluez from agent*/
82 static const gchar bt_telephony_introspection_xml[] =
84 " <interface name='org.tizen.csd.Call.Instance'>"
85 " <method name='SendDtmf'>"
86 " <arg type='s' name='dtmf' direction='in'/>"
88 " <method name='VendorCmd'>"
89 " <arg type='s' name='vendor' direction='in'/>"
94 #define BT_TELEPHONY_CHECK_ENABLED() \
96 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED) \
98 BT_ERR("BT is not enabled"); \
99 return BLUETOOTH_TELEPHONY_ERROR_NOT_ENABLED; \
103 static gboolean is_initialized = FALSE;
104 #define BT_TELEPHONY_CHECK_INITIALIZED() \
106 if (is_initialized == FALSE) \
108 BT_ERR("Bluetooth telephony not initilized"); \
109 return BLUETOOTH_TELEPHONY_ERROR_NOT_INITIALIZED; \
113 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
114 const gchar *sender_name,
115 const gchar *object_path,
116 const gchar *interface_name,
117 const gchar *signal_name,
118 GVariant *parameters,
121 static int __bt_telephony_get_src_addr(GVariant *value);
123 static bt_telephony_info_t telephony_info;
124 static telephony_dbus_info_t telephony_dbus_info;
125 static gboolean is_active = FALSE;
127 /*Function Declaration*/
128 static int __bt_telephony_get_error(const char *error_message);
129 static void __bt_telephony_event_cb(int event, int result, void *param_data);
130 static GQuark __bluetooth_telephony_error_quark(void);
131 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
132 const char *interface, const char *method,
133 GError **err, GVariant *parameters);
134 static int __bluetooth_telephony_send_call_status(
135 bt_telephony_call_status_t call_status,
136 unsigned int call_id, const char *ph_number);
137 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
138 bluetooth_telephony_error_t error, const char *err_msg);
140 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
141 const gchar *sender_name,
142 const gchar *object_path,
143 const gchar *interface_name,
144 const gchar *signal_name,
145 GVariant *parameters,
148 static int __bluetooth_telephony_proxy_init(void);
149 static void __bluetooth_telephony_proxy_deinit(void);
150 static int __bluetooth_telephony_register(void);
151 static int __bluetooth_telephony_unregister(void);
153 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class);
154 static int __bluetooth_telephony_get_connected_device(void);
155 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void);
157 /*Function Definition*/
158 static void __bt_telephony_method(GDBusConnection *connection,
160 const gchar *object_path,
161 const gchar *interface_name,
162 const gchar *method_name,
163 GVariant *parameters,
164 GDBusMethodInvocation *invocation,
169 BT_INFO("method %s", method_name);
170 BT_INFO("object_path %s", object_path);
172 if (g_strcmp0(method_name, "SendDtmf") == 0) {
174 telephony_event_dtmf_t call_data = { 0, };
176 g_variant_get(parameters, "(&s)", &dtmf);
179 BT_ERR("Number dial failed");
180 __bluetooth_telephony_error(invocation,
181 BLUETOOTH_TELEPHONY_ERROR_INVALID_DTMF,
184 DBG_SECURE("Dtmf = %s", dtmf);
186 call_data.dtmf = g_strdup(dtmf);
187 __bt_telephony_event_cb(
188 BLUETOOTH_EVENT_TELEPHONY_SEND_DTMF,
189 BLUETOOTH_TELEPHONY_ERROR_NONE,
192 g_free(call_data.dtmf);
194 g_dbus_method_invocation_return_value(invocation, NULL);
196 } else if (g_strcmp0(method_name, "VendorCmd") == 0) {
199 g_variant_get(parameters, "(&s)", &at_cmd);
200 BT_INFO("Vendor %s", at_cmd);
201 if (at_cmd == NULL) {
202 BT_ERR("Vendor command is NULL\n");
203 __bluetooth_telephony_error(invocation,
204 BLUETOOTH_TELEPHONY_ERROR_APPLICATION,
205 "Invalid at vendor cmd");
207 DBG_SECURE("Vendor AT cmd = %s", at_cmd);
209 __bt_telephony_event_cb(
210 BLUETOOTH_EVENT_TELEPHONY_VENDOR_AT_CMD,
211 BLUETOOTH_TELEPHONY_ERROR_NONE,
214 g_dbus_method_invocation_return_value(invocation, NULL);
221 static const GDBusInterfaceVTable method_table = {
222 __bt_telephony_method,
227 static int __bt_telephony_get_error(const char *error_message)
229 if (error_message == NULL) {
230 BT_ERR("Error message NULL");
231 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
234 BT_ERR("Error message = %s", error_message);
235 if (g_strcmp0(error_message, "NotAvailable") == 0)
236 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
237 else if (g_strcmp0(error_message, "NotConnected") == 0)
238 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
239 else if (g_strcmp0(error_message, "InProgress") == 0)
240 return BLUETOOTH_TELEPHONY_ERROR_BUSY;
241 else if (g_strcmp0(error_message, "InvalidArguments") == 0)
242 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
243 else if (g_strcmp0(error_message, "AlreadyExists") == 0)
244 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_EXSIST;
245 else if (g_strcmp0(error_message, "Already Connected") == 0)
246 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
247 else if (g_strcmp0(error_message, "No memory") == 0)
248 return BLUETOOTH_TELEPHONY_ERROR_NO_MEMORY;
249 else if (g_strcmp0(error_message, "I/O error") == 0)
250 return BLUETOOTH_TELEPHONY_ERROR_I_O_ERROR;
251 else if (g_strcmp0(error_message,
252 "Operation currently not available") == 0)
253 return BLUETOOTH_TELEPHONY_ERROR_OPERATION_NOT_AVAILABLE;
254 else if (g_strrstr(error_message, BT_ACCESS_DENIED_MSG))
255 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
257 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
260 static int __bt_telephony_check_privilege(void)
267 reply = __bluetooth_telephony_dbus_method_send(
268 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
269 "CheckPrivilege", &err, NULL);
272 BT_ERR("Error returned in method call");
274 g_dbus_error_strip_remote_error(err);
275 ret = __bt_telephony_get_error(err->message);
279 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
281 g_variant_unref(reply);
284 return BLUETOOTH_TELEPHONY_ERROR_NONE;
287 static void __bt_telephony_event_cb(int event, int result, void *param_data)
289 telephony_event_param_t bt_event = { 0, };
291 bt_event.event = event;
292 bt_event.result = result;
293 bt_event.param_data = param_data;
295 ret_if(telephony_info.cb == NULL);
296 telephony_info.cb(bt_event.event, &bt_event, telephony_info.user_data);
300 static GQuark __bluetooth_telephony_error_quark(void)
302 static GQuark quark = 0;
304 quark = g_quark_from_static_string("telephony");
309 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
310 const char *interface, const char *method,
311 GError **err, GVariant *parameters)
313 #ifdef TIZEN_WEARABLE
320 GDBusConnection *conn;
324 conn = telephony_dbus_info.conn;
325 retv_if(conn == NULL, NULL);
327 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
328 NULL, HFP_AGENT_SERVICE, path, interface, NULL, err);
330 BT_ERR("Unable to allocate new proxy");
334 reply = g_dbus_proxy_call_sync(proxy, method, parameters,
335 G_DBUS_CALL_FLAGS_NONE, timeout, NULL, err);
337 g_object_unref(proxy);
342 static int __bluetooth_telephony_send_call_status(
343 bt_telephony_call_status_t call_status,
344 unsigned int call_id, const char *ph_number)
349 char *path = g_strdup(telephony_info.call_path);
355 if (NULL == ph_number)
356 phone_number = g_strdup("");
358 phone_number = g_strdup(ph_number);
360 param = g_variant_new("(ssii)", path, phone_number,
361 call_status, call_id);
362 reply = __bluetooth_telephony_dbus_method_send(
363 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
364 "ChangeCallStatus", &err, param);
367 g_free(phone_number);
370 BT_ERR("Error returned in method call");
372 g_dbus_error_strip_remote_error(err);
373 ret = __bt_telephony_get_error(err->message);
377 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
380 g_variant_unref(reply);
382 return BLUETOOTH_TELEPHONY_ERROR_NONE;
385 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
386 bluetooth_telephony_error_t error, const char *err_msg)
388 g_dbus_method_invocation_return_error(invocation,
389 BLUETOOTH_TELEPHONY_ERROR, error,
393 static void __bluetooth_telephony_answer_call(GVariant *var)
395 telephony_event_callid_t call_data = { 0, };
400 g_variant_get(var, "(u)", &callid);
401 BT_DBG("call_id = [%d]", callid);
402 call_data.callid = callid;
404 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_ANSWER_CALL,
405 BLUETOOTH_TELEPHONY_ERROR_NONE,
410 static void __bluetooth_telephony_release_call(GVariant *var)
412 telephony_event_callid_t call_data = { 0, };
417 g_variant_get(var, "(u)", &callid);
418 BT_DBG("call_id = [%d]", callid);
419 call_data.callid = callid;
421 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_RELEASE_CALL,
422 BLUETOOTH_TELEPHONY_ERROR_NONE,
427 static void __bluetooth_telephony_reject_call(GVariant *var)
429 telephony_event_callid_t call_data = { 0, };
434 g_variant_get(var, "(u)", &callid);
435 BT_DBG("call_id = [%d]", callid);
436 call_data.callid = callid;
438 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_REJECT_CALL,
439 BLUETOOTH_TELEPHONY_ERROR_NONE,
444 static void __bluetooth_telephony_threeway_call(GVariant *var)
447 unsigned int chld_value;
451 g_variant_get(var, "(u)", &chld_value);
452 BT_DBG("chld value = [%d]", chld_value);
454 switch (chld_value) {
456 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_0_RELEASE_ALL_HELD_CALL;
459 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_1_RELEASE_ALL_ACTIVE_CALL;
462 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_2_ACTIVE_HELD_CALL;
465 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_3_MERGE_CALL;
468 BT_ERR("Invalid CHLD command");
472 __bt_telephony_event_cb(event,
473 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
477 static void __bluetooth_handle_nrec_status_change(GVariant *var)
479 gboolean status = FALSE;
481 g_variant_get(var, "(b)", &status);
482 BT_INFO("NREC status = %d", status);
484 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_NREC_CHANGED,
485 BLUETOOTH_TELEPHONY_ERROR_NONE, (void *)&status);
489 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
490 const gchar *sender_name,
491 const gchar *object_path,
492 const gchar *interface_name,
493 const gchar *signal_name,
494 GVariant *parameters,
499 if (strcasecmp(interface_name, HFP_AGENT_SERVICE) == 0) {
500 if (strcasecmp(signal_name, HFP_NREC_STATUS_CHANGE) == 0)
501 __bluetooth_handle_nrec_status_change(parameters);
502 else if (strcasecmp(signal_name, HFP_ANSWER_CALL) == 0)
503 __bluetooth_telephony_answer_call(parameters);
504 else if (strcasecmp(signal_name, HFP_REJECT_CALL) == 0)
505 __bluetooth_telephony_reject_call(parameters);
506 else if (strcasecmp(signal_name, HFP_RELEASE_CALL) == 0)
507 __bluetooth_telephony_release_call(parameters);
508 else if (strcasecmp(signal_name, HFP_THREEWAY_CALL) == 0)
509 __bluetooth_telephony_threeway_call(parameters);
510 } else if (strcasecmp(interface_name, BLUEZ_HEADSET_INTERFACE) == 0) {
511 if (strcasecmp(signal_name, "PropertyChanged") == 0) {
515 g_variant_get(parameters, "(&sv)", &property, &values);
516 BT_DBG("Property: %s", property);
518 if (strcasecmp(property, "State") == 0) {
520 state = (gchar *)g_variant_get_string(values, NULL);
523 BT_ERR("State is null");
526 BT_DBG("state: %s", state);
527 if (g_strcmp0(state, "connected") == 0) {
528 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
529 } else if (g_strcmp0(state, "playing") == 0) {
530 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
531 } else if (g_strcmp0(state, "disconnected") == 0) {
532 /* Headset state: playing -> disconnected */
533 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING) {
534 __bt_telephony_event_cb(
535 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
536 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
539 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
541 } else if (strcasecmp(property, "Connected") == 0) {
542 gboolean connected = FALSE;
543 char *dev_addr = NULL;
544 connected = g_variant_get_boolean(values);
545 BT_INFO("connected %d", connected);
547 /*Get device address*/
548 if (object_path != NULL)
549 dev_addr = strstr(object_path, "dev_");
551 if (dev_addr != NULL) {
553 g_strlcpy(telephony_info.address,
555 sizeof(telephony_info.address));
556 g_strdelimit(telephony_info.address, "_", ':');
557 BT_DBG("address is %s",
558 telephony_info.address);
560 telephony_info.headset_state =
561 BLUETOOTH_STATE_CONNECTED;
563 if (telephony_dbus_info.proxy != NULL) {
564 g_object_unref(telephony_dbus_info.proxy);
565 telephony_dbus_info.proxy = NULL;
568 telephony_dbus_info.proxy =
569 __bluetooth_telephony_get_connected_device_proxy();
571 BT_INFO("Headset Connected");
573 __bt_telephony_event_cb(
574 BLUETOOTH_EVENT_TELEPHONY_HFP_CONNECTED,
575 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
577 } else { /*Device disconnected*/
578 memset(telephony_info.address, 0x00,
579 sizeof(telephony_info.address));
580 telephony_info.headset_state =
581 BLUETOOTH_STATE_DISCONNETED;
583 if (telephony_dbus_info.proxy != NULL) {
584 g_object_unref(telephony_dbus_info.proxy);
585 telephony_dbus_info.proxy = NULL;
588 BT_INFO("Headset Disconnected");
590 __bt_telephony_event_cb(
591 BLUETOOTH_EVENT_TELEPHONY_HFP_DISCONNECTED,
592 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
594 } else if (strcasecmp(property, "SpeakerGain") == 0) {
595 unsigned int spkr_gain;
596 guint16 gain = g_variant_get_uint16(values);
598 spkr_gain = (unsigned int)gain;
599 BT_DBG("spk_gain[%d]", spkr_gain);
601 __bt_telephony_event_cb(
602 BLUETOOTH_EVENT_TELEPHONY_SET_SPEAKER_GAIN,
603 BLUETOOTH_TELEPHONY_ERROR_NONE,
605 } else if (strcasecmp(property, "MicrophoneGain") == 0) {
606 unsigned int mic_gain;
607 guint16 gain = g_variant_get_uint16(values);
609 mic_gain = (unsigned int)gain;
610 BT_DBG("mic_gain[%d]", mic_gain);
612 __bt_telephony_event_cb(
613 BLUETOOTH_EVENT_TELEPHONY_SET_MIC_GAIN,
614 BLUETOOTH_TELEPHONY_ERROR_NONE,
616 } else if (strcasecmp(property, "Playing") == 0) {
617 gboolean audio_sink_playing;
619 audio_sink_playing = g_variant_get_boolean(values);
620 if (audio_sink_playing) {
621 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
622 __bt_telephony_event_cb(
623 BLUETOOTH_EVENT_TELEPHONY_AUDIO_CONNECTED,
624 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
626 telephony_info.headset_state =
627 BLUETOOTH_STATE_CONNECTED;
628 __bt_telephony_event_cb(
629 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
630 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
634 g_variant_unref(values);
640 static GDBusNodeInfo *__bt_telephony_create_method_node_info
641 (const gchar *introspection_data)
644 GDBusNodeInfo *node_info = NULL;
646 if (introspection_data == NULL)
649 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
652 BT_ERR("Unable to create node: %s", err->message);
659 int __bluetooth_telephony_register_object(int reg, GDBusNodeInfo *node_info)
661 static guint bt_tel_id = 0;
662 GError *error = NULL;
666 if (node_info == NULL)
667 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
669 path = g_strdup(telephony_info.call_path);
670 BT_DBG("path is [%s]", path);
672 bt_tel_id = g_dbus_connection_register_object(telephony_dbus_info.conn,
673 path, node_info->interfaces[0],
678 if (bt_tel_id == 0) {
679 BT_ERR("Failed to register: %s", error->message);
681 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
685 g_dbus_connection_unregister_object(telephony_dbus_info.conn,
691 return BLUETOOTH_TELEPHONY_ERROR_NONE;
694 static int __bluetooth_telephony_proxy_init(void)
698 GDBusNodeInfo *node_info;
700 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
701 TELEPHONY_APP_INTERFACE,
702 G_BUS_NAME_OWNER_FLAGS_NONE,
705 BT_DBG("owner_id is [%d]", owner_id);
707 node_info = __bt_telephony_create_method_node_info(
708 bt_telephony_introspection_xml);
710 if (node_info == NULL) {
711 BT_ERR("node_info NULL");
712 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
714 if (__bluetooth_telephony_register_object(TRUE, node_info) !=
715 BLUETOOTH_TELEPHONY_ERROR_NONE) {
716 BT_ERR("Registation of Method Failed");
717 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
721 return BLUETOOTH_TELEPHONY_ERROR_NONE;
724 static void __bluetooth_telephony_proxy_deinit(void)
728 __bluetooth_telephony_register_object(FALSE, NULL);
734 static int __bluetooth_telephony_register(void)
739 char *path = g_strdup(telephony_info.call_path);
744 param = g_variant_new("(ss)", path, src_addr);
745 BT_DBG("Path[%s] Src_Address[%s]", path, src_addr);
747 reply = __bluetooth_telephony_dbus_method_send(
748 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
749 "RegisterApplication", &err, param);
754 BT_ERR("Error returned in method call");
756 g_dbus_error_strip_remote_error(err);
757 ret = __bt_telephony_get_error(err->message);
758 BT_ERR("Error here %d\n", ret);
762 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
765 g_variant_unref(reply);
766 BT_DBG("__bluetooth_telephony_register completed");
768 return BLUETOOTH_TELEPHONY_ERROR_NONE;
771 static int __bluetooth_telephony_unregister(void)
776 char *path = g_strdup(telephony_info.call_path);
781 param = g_variant_new("(s)", path);
782 reply = __bluetooth_telephony_dbus_method_send(
783 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
784 "UnregisterApplication", &err, param);
789 BT_ERR("Error returned in method call");
791 g_dbus_error_strip_remote_error(err);
792 ret = __bt_telephony_get_error(err->message);
796 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
799 g_variant_unref(reply);
800 BT_DBG("__bluetooth_telephony_unregister completed");
802 return BLUETOOTH_TELEPHONY_ERROR_NONE;
805 #ifndef TIZEN_WEARABLE
806 static void __bluetooth_telephony_init_headset_state(void)
810 gboolean status = FALSE;
814 if (telephony_dbus_info.conn == NULL) {
815 BT_ERR("Bluetooth telephony not initilized");
819 reply = __bluetooth_telephony_dbus_method_send(
820 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
821 "IsConnected", &err, NULL);
823 BT_ERR("Error returned in method call\n");
825 BT_ERR("Error message = %s", err->message);
831 g_variant_get(reply, "(b)", &status);
832 g_variant_unref(reply);
834 BT_INFO("Headset Connected Status = [%d]", status);
836 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
840 if (bluetooth_telephony_is_sco_connected())
841 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
847 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class)
849 gboolean flag = FALSE;
852 switch ((device_class & 0x1f00) >> 8) {
854 switch ((device_class & 0xfc) >> 2) {
872 /* Tizen Wearable device */
874 switch ((device_class & 0xfc) >> 2) {
875 case 0x01: /* Wrist Watch */
883 BT_DBG("[%d]", flag);
888 static gboolean __bluetooth_telephony_is_headset_by_uuid(gchar **uuids)
892 unsigned int service = 0;
896 retv_if(uuids == NULL, FALSE);
898 for (i = 0; uuids[i] != NULL; i++) {
899 parts = g_strsplit(uuids[i], "-", -1);
901 if (parts == NULL || parts[0] == NULL) {
906 service = g_ascii_strtoull(parts[0], NULL, 16);
909 if (service == BLUETOOTH_HS_PROFILE_UUID ||
910 service == BLUETOOTH_HF_PROFILE_UUID)
919 static int __bluetooth_telephony_get_connected_device(void)
921 GDBusConnection *conn;
922 GDBusProxy *headset_agent_proxy = NULL;
923 GDBusProxy *manager_proxy = NULL;
924 GDBusProxy *proxy = NULL;
925 GVariant *reply = NULL;
926 GVariant *getall = NULL;
927 GVariant *isPlayingReply = NULL;
928 GVariant *isConnectedReply = NULL;
929 GVariant *param = NULL;
930 GVariant *var_path = NULL;
931 GVariant *path_values = NULL;
932 GVariant *value = NULL;
933 GError *error = NULL;
935 GVariantIter iter_path;
936 GVariantIter property_iter;
937 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
940 conn = _bt_gdbus_get_system_gconn();
941 retv_if(conn == NULL, BLUETOOTH_TELEPHONY_ERROR_INTERNAL);
943 manager_proxy = g_dbus_proxy_new_sync(
944 conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
945 BLUEZ_SERVICE_NAME, "/",
946 BLUEZ_MANAGER_INTERFACE, NULL, &error);
947 if (manager_proxy == NULL) {
948 BT_ERR("Unable to allocate new proxy \n");
949 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
951 g_dbus_error_strip_remote_error(error);
952 ret = __bt_telephony_get_error(error->message);
953 BT_ERR("Error here %d\n", ret);
959 /* Synchronous call */
960 reply = g_dbus_proxy_call_sync(manager_proxy, "GetManagedObjects", NULL,
961 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
962 g_object_unref(manager_proxy);
965 BT_ERR("Can't get managed objects");
966 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
968 g_dbus_error_strip_remote_error(error);
969 ret = __bt_telephony_get_error(error->message);
970 BT_ERR("Error here %d\n", ret);
976 /* signature of GetManagedObjects: a{oa{sa{sv}}} */
977 g_variant_iter_init(&iter, reply);
979 while ((param = g_variant_iter_next_value(&iter))) {
980 g_variant_iter_init(&iter_path, param);
982 while ((var_path = g_variant_iter_next_value(&iter_path))) {
984 uint32_t device_class = 0;
985 gboolean playing = FALSE;
986 gboolean connected = FALSE;
987 char *object_path = NULL;
988 gchar *address = NULL;
990 gchar **uuids = NULL;
991 GVariant *getall_param = NULL;
993 g_variant_get(var_path, "{&o*}", &object_path,
995 g_variant_unref(path_values); /* path_values unused*/
997 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
998 G_DBUS_PROXY_FLAGS_NONE, NULL,
999 BLUEZ_SERVICE_NAME, object_path,
1000 BLUEZ_PROPERTIES_INTERFACE, NULL, &error);
1001 if (proxy == NULL) {
1002 BT_ERR("Unable to allocate new proxy \n");
1003 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1005 g_dbus_error_strip_remote_error(error);
1006 ret = __bt_telephony_get_error(error->message);
1007 BT_ERR("Error here %d\n", ret);
1008 g_error_free(error);
1014 getall_param = g_variant_new("s", BLUEZ_DEVICE_INTERFACE);
1015 getall = g_dbus_proxy_call_sync(proxy,
1016 "GetAll", getall_param,
1017 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1018 g_object_unref(proxy);
1021 BT_ERR("Can't get managed objects");
1022 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1024 g_dbus_error_strip_remote_error(error);
1025 ret = __bt_telephony_get_error(error->message);
1026 BT_ERR("Error here %d\n", ret);
1027 g_error_free(error);
1032 g_variant_iter_init(&property_iter, getall);
1034 while (g_variant_iter_loop(&property_iter, "{&sv}", &key, &value)) {
1035 if (!g_strcmp0(key, "Class")) {
1036 device_class = g_variant_get_uint32(value);
1037 BT_DBG("Device Class: %d", device_class);
1038 } else if (!g_strcmp0(key, "UUID")) {
1040 uuids = (gchar **)g_variant_get_strv(value, &len);
1041 BT_DBG_UUID(uuids, len, i);
1042 } else if (!g_strcmp0(key, "Address")) {
1043 address = (gchar *)g_variant_get_string(
1046 BT_DBG("Device Class: %s", address);
1048 g_variant_unref(value);
1050 g_variant_unref(getall);
1052 if (device_class == 0) {
1053 BT_DBG("COD is NULL (maybe paired by nfc)... Checking UUIDs");
1054 if (!__bluetooth_telephony_is_headset_by_uuid(uuids)) {
1055 BT_DBG("UUID checking completed. None HF device");
1058 BT_DBG("UUID checking completed. HF device");
1060 if (!__bluetooth_telephony_is_headset(device_class))
1064 /* this is headset; Check for Connection */
1065 headset_agent_proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1066 G_DBUS_PROXY_FLAGS_NONE, NULL,
1067 HFP_AGENT_SERVICE, object_path,
1068 HFP_AGENT_INTERFACE, NULL, &error);
1069 if (headset_agent_proxy == NULL) {
1070 BT_ERR("Unable to allocate new headset_agent_proxy");
1071 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1073 g_dbus_error_strip_remote_error(error);
1074 ret = __bt_telephony_get_error(error->message);
1075 BT_ERR("Error here %d\n", ret);
1076 g_error_free(error);
1081 isConnectedReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1082 "IsConnected", NULL,
1083 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1086 if (!isConnectedReply) {
1087 BT_ERR("Can't get managed objects");
1088 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1090 g_dbus_error_strip_remote_error(error);
1091 ret = __bt_telephony_get_error(error->message);
1092 BT_ERR("Error here %d\n", ret);
1093 g_error_free(error);
1097 connected = g_variant_get_boolean(isConnectedReply);
1098 g_variant_unref(isConnectedReply);
1101 g_strlcpy(telephony_info.address,
1103 sizeof(telephony_info.address));
1105 isPlayingReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1107 G_DBUS_CALL_FLAGS_NONE,
1109 if (!isPlayingReply) {
1110 BT_ERR("Can't get managed objects");
1111 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1113 g_dbus_error_strip_remote_error(error);
1114 ret = __bt_telephony_get_error(error->message);
1115 BT_ERR("Error here %d\n", ret);
1116 g_error_free(error);
1119 playing = g_variant_get_boolean(isPlayingReply);
1120 g_variant_unref(isPlayingReply);
1123 telephony_info.headset_state =
1124 BLUETOOTH_STATE_PLAYING;
1126 telephony_info.headset_state =
1127 BLUETOOTH_STATE_CONNECTED;
1134 g_object_unref(headset_agent_proxy);
1135 g_variant_unref(var_path);
1137 g_variant_unref(param);
1141 if (headset_agent_proxy)
1142 g_object_unref(headset_agent_proxy);
1144 g_variant_unref(reply);
1146 g_variant_unref(var_path);
1148 g_variant_unref(param);
1153 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void)
1155 GDBusProxy *proxy = NULL;
1156 GError *error = NULL;
1160 if (strlen(telephony_info.address) == 0)
1161 __bluetooth_telephony_get_connected_device();
1163 if (strlen(telephony_info.address) == 0)
1166 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1167 G_DBUS_PROXY_FLAGS_NONE, NULL,
1168 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1169 HFP_AGENT_INTERFACE, NULL, &error);
1170 if (proxy == NULL) {
1171 BT_ERR("Unable to allocate new proxy");
1173 g_dbus_error_strip_remote_error(error);
1174 ret = __bt_telephony_get_error(error->message);
1175 BT_ERR("Error here %d\n", ret);
1176 g_error_free(error);
1185 int __bt_telephony_subscribe_adapter_signal(GDBusConnection *conn,
1191 static int subscribe_adapter_id = -1;
1192 if (subscribe == TRUE) {
1193 if (subscribe_adapter_id == -1) {
1194 subscribe_adapter_id = g_dbus_connection_signal_subscribe(conn,
1195 NULL, "org.freedesktop.DBus.ObjectManager",
1196 "InterfacesAdded", NULL, NULL, 0,
1197 __bt_telephony_adapter_filter,
1200 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1202 if (subscribe_adapter_id != -1) {
1203 g_dbus_connection_signal_unsubscribe(conn,
1204 subscribe_adapter_id);
1205 subscribe_adapter_id = -1;
1207 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1211 int __bt_telephony_event_subscribe_signal(GDBusConnection *conn,
1217 static int subscribe_event1_id = -1;
1218 static int subscribe_event2_id = -1;
1219 static int subscribe_event3_id = -1;
1220 static int subscribe_event4_id = -1;
1221 static int subscribe_event5_id = -1;
1222 static int subscribe_event6_id = -1;
1223 if (subscribe == TRUE) {
1224 if (subscribe_event1_id == -1) {
1225 subscribe_event1_id = g_dbus_connection_signal_subscribe(conn,
1226 NULL, BLUEZ_HEADSET_INTERFACE,
1227 "PropertyChanged", NULL, NULL, 0,
1228 __bluetooth_telephony_event_filter,
1231 if (subscribe_event2_id == -1) {
1232 subscribe_event2_id = g_dbus_connection_signal_subscribe(conn,
1233 NULL, HFP_AGENT_SERVICE,
1234 HFP_NREC_STATUS_CHANGE, NULL, NULL, 0,
1235 __bluetooth_telephony_event_filter,
1239 if (subscribe_event3_id == -1) {
1240 subscribe_event3_id = g_dbus_connection_signal_subscribe(conn,
1241 NULL, HFP_AGENT_SERVICE,
1242 HFP_ANSWER_CALL, NULL, NULL, 0,
1243 __bluetooth_telephony_event_filter,
1246 if (subscribe_event4_id == -1) {
1247 subscribe_event4_id = g_dbus_connection_signal_subscribe(conn,
1248 NULL, HFP_AGENT_SERVICE,
1249 HFP_REJECT_CALL, NULL, NULL, 0,
1250 __bluetooth_telephony_event_filter,
1253 if (subscribe_event5_id == -1) {
1254 subscribe_event5_id = g_dbus_connection_signal_subscribe(conn,
1255 NULL, HFP_AGENT_SERVICE,
1256 HFP_RELEASE_CALL, NULL, NULL, 0,
1257 __bluetooth_telephony_event_filter,
1260 if (subscribe_event6_id == -1) {
1261 subscribe_event6_id = g_dbus_connection_signal_subscribe(conn,
1262 NULL, HFP_AGENT_SERVICE,
1263 HFP_THREEWAY_CALL, NULL, NULL, 0,
1264 __bluetooth_telephony_event_filter,
1268 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1270 if (subscribe_event1_id != -1) {
1271 g_dbus_connection_signal_unsubscribe(conn,
1272 subscribe_event1_id);
1273 subscribe_event1_id = -1;
1275 if (subscribe_event2_id != -1) {
1276 g_dbus_connection_signal_unsubscribe(conn,
1277 subscribe_event2_id);
1278 subscribe_event2_id = -1;
1280 if (subscribe_event3_id != -1) {
1281 g_dbus_connection_signal_unsubscribe(conn,
1282 subscribe_event3_id);
1283 subscribe_event3_id = -1;
1285 if (subscribe_event4_id != -1) {
1286 g_dbus_connection_signal_unsubscribe(conn,
1287 subscribe_event4_id);
1288 subscribe_event4_id = -1;
1290 if (subscribe_event5_id != -1) {
1291 g_dbus_connection_signal_unsubscribe(conn,
1292 subscribe_event5_id);
1293 subscribe_event5_id = -1;
1295 if (subscribe_event6_id != -1) {
1296 g_dbus_connection_signal_unsubscribe(conn,
1297 subscribe_event6_id);
1298 subscribe_event6_id = -1;
1300 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1304 BT_EXPORT_API int bluetooth_telephony_init(bt_telephony_func_ptr cb,
1307 bluetooth_device_address_t loc_address = { {0} };
1308 char src_address[BT_ADDRESS_STRING_SIZE] = { 0 };
1309 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1310 GError *error = NULL;
1314 if (is_initialized == TRUE) {
1315 BT_ERR("Bluetooth telephony already initilized");
1316 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_INITIALIZED;
1319 is_initialized = TRUE;
1321 telephony_dbus_info.conn = _bt_gdbus_init_system_gconn();
1322 if (!telephony_dbus_info.conn) {
1323 is_initialized = FALSE;
1324 BT_ERR("Could not get DBus Connection");
1325 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1329 snprintf(telephony_info.call_path, sizeof(telephony_info.call_path),
1330 CSD_CALL_APP_PATH, getpid());
1331 BT_DBG("Call Path = %s", telephony_info.call_path);
1332 memset(telephony_info.address, 0x00, sizeof(telephony_info.address));
1334 if (__bluetooth_telephony_proxy_init()) {
1335 BT_ERR("__bluetooth_telephony_proxy_init failed\n");
1336 telephony_dbus_info.conn = NULL;
1337 is_initialized = FALSE;
1338 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1341 telephony_dbus_info.manager_proxy = g_dbus_proxy_new_sync(
1342 telephony_dbus_info.conn,
1343 G_DBUS_PROXY_FLAGS_NONE, NULL,
1344 BLUEZ_SERVICE_NAME, "/",
1345 BLUEZ_MANAGER_INTERFACE, NULL, &error);
1346 if (telephony_dbus_info.manager_proxy == NULL) {
1347 BT_ERR("Could not create a manager proxy");
1348 __bluetooth_telephony_proxy_deinit();
1349 telephony_dbus_info.conn = NULL;
1350 is_initialized = FALSE;
1352 g_dbus_error_strip_remote_error(error);
1353 ret = __bt_telephony_get_error(error->message);
1354 BT_ERR("Error here %d\n", ret);
1355 g_error_free(error);
1358 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1361 telephony_dbus_info.dbus_proxy = g_dbus_proxy_new_sync(
1362 telephony_dbus_info.conn,
1363 G_DBUS_PROXY_FLAGS_NONE, NULL,
1364 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1365 DBUS_INTERFACE_DBUS, NULL, &error);
1366 if (NULL == telephony_dbus_info.dbus_proxy) {
1367 __bluetooth_telephony_proxy_deinit();
1368 telephony_dbus_info.conn = NULL;
1369 g_object_unref(telephony_dbus_info.manager_proxy);
1370 telephony_dbus_info.manager_proxy = NULL;
1371 is_initialized = FALSE;
1372 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1375 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, TRUE) != 0) {
1376 BT_ERR("Fail to Subscribe Adapter Signal");
1380 /*Callback and user applicaton data*/
1381 telephony_info.cb = cb;
1382 telephony_info.user_data = user_data;
1383 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1385 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, TRUE) != 0) {
1386 BT_ERR("Fail to Subscribe telephony event Signal");
1390 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED)
1391 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1393 /*Bluetooth is active, therefore set the flag */
1396 ret = bluetooth_get_local_address(&loc_address);
1397 if (ret != BLUETOOTH_ERROR_NONE) {
1398 BT_ERR("Fail to get local address\n");
1399 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1402 _bt_convert_addr_type_to_string(src_address, loc_address.addr);
1403 src_addr = g_strdup(src_address);
1405 ret = __bluetooth_telephony_register();
1406 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1407 BT_ERR("__bluetooth_telephony_register failed\n");
1411 #ifndef TIZEN_WEARABLE
1412 __bluetooth_telephony_init_headset_state();
1418 bluetooth_telephony_deinit();
1422 BT_EXPORT_API int bluetooth_telephony_deinit(void)
1425 BT_TELEPHONY_CHECK_INITIALIZED();
1427 is_initialized = FALSE;
1429 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, FALSE) != 0)
1430 BT_ERR("Fail to UnSubscribe telephony event Signal");
1432 if (bluetooth_check_adapter() != BLUETOOTH_ADAPTER_DISABLED ||
1433 bluetooth_check_adapter_le() != BLUETOOTH_ADAPTER_LE_DISABLED)
1434 __bluetooth_telephony_unregister();
1436 __bluetooth_telephony_proxy_deinit();
1438 telephony_info.cb = NULL;
1439 telephony_info.user_data = NULL;
1440 telephony_info.call_count = 0;
1441 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1443 /* Remove BT enabled signal */
1444 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, FALSE) != 0)
1445 BT_ERR("Fail to UnSubscribe Adapter event Signal");
1450 if (telephony_dbus_info.manager_proxy != NULL) {
1451 g_object_unref(telephony_dbus_info.manager_proxy);
1452 telephony_dbus_info.manager_proxy = NULL;
1455 if (telephony_dbus_info.conn != NULL) {
1456 telephony_dbus_info.conn = NULL;
1459 if (telephony_dbus_info.dbus_proxy != NULL) {
1460 g_object_unref(telephony_dbus_info.dbus_proxy);
1461 telephony_dbus_info.dbus_proxy = NULL;
1465 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1468 BT_EXPORT_API gboolean bluetooth_telephony_is_sco_connected(void)
1472 gboolean status = FALSE;
1476 retv_if(is_initialized == FALSE, FALSE);
1477 retv_if(bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED, FALSE);
1479 reply = __bluetooth_telephony_dbus_method_send(
1480 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1481 "IsPlaying", &err, NULL);
1484 BT_ERR("Error returned in method call\n");
1486 BT_ERR("Error message = %s", err->message);
1491 g_variant_get(reply, "(b)", &status);
1492 g_variant_unref(reply);
1494 #ifdef TIZEN_WEARABLE
1495 if (status == TRUE && telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1496 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
1499 BT_INFO("SCO Connected Status = [%d]", status);
1503 BT_EXPORT_API int bluetooth_telephony_is_nrec_enabled(gboolean *status)
1508 GVariant *param_inner;
1512 BT_TELEPHONY_CHECK_INITIALIZED();
1513 BT_TELEPHONY_CHECK_ENABLED();
1516 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1518 if (telephony_info.headset_state == BLUETOOTH_STATE_DISCONNETED)
1519 return BLUETOOTH_TELEPHONY_ERROR_AUDIO_NOT_CONNECTED;
1521 reply = __bluetooth_telephony_dbus_method_send(
1522 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1523 "GetProperties", &err, NULL);
1526 BT_ERR("Error returned in method call\n");
1528 BT_DBG("Error message = %s", err->message);
1531 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1534 g_variant_iter_init(&iter, reply);
1535 while ((param_inner = g_variant_iter_next_value(&iter))) {
1538 value = g_variant_lookup_value(param_inner,
1539 "nrec", G_VARIANT_TYPE_BOOLEAN);
1541 BT_DBG("Property NREC Found");
1542 *status = g_variant_get_boolean(value);
1543 BT_DBG("NREC status = [%d]", *status);
1544 g_variant_unref(value);
1545 g_variant_unref(param_inner);
1548 g_variant_unref(param_inner);
1550 BT_DBG("NREC status = [%d]", *status);
1551 g_variant_unref(reply);
1554 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1557 BT_EXPORT_API int bluetooth_telephony_is_wbs_mode(gboolean *status)
1563 GVariant *param_inner;
1567 BT_TELEPHONY_CHECK_INITIALIZED();
1568 BT_TELEPHONY_CHECK_ENABLED();
1571 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1575 reply = __bluetooth_telephony_dbus_method_send(
1576 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1577 "GetProperties", &err, NULL);
1580 BT_ERR("Error returned in method call");
1582 BT_ERR("Error message = %s", err->message);
1585 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1588 g_variant_iter_init(&iter, reply);
1589 while ((param_inner = g_variant_iter_next_value(&iter))) {
1592 value = g_variant_lookup_value(param_inner,
1593 "codec", G_VARIANT_TYPE_UINT32);
1595 BT_DBG("Property CODEC Found");
1596 codec = g_variant_get_uint32(value);
1597 g_variant_unref(value);
1598 BT_DBG("Codec = [%d]", codec);
1600 *status = codec == BT_MSBC_CODEC_ID ? TRUE : FALSE;
1601 BT_DBG("NREC status = [%d]", *status);
1602 g_variant_unref(value);
1603 g_variant_unref(param_inner);
1606 g_variant_unref(param_inner);
1609 g_variant_unref(reply);
1610 BT_DBG("MSBC status = [%d]", *status);
1613 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1616 BT_EXPORT_API int bluetooth_telephony_send_vendor_cmd(const char *cmd)
1618 GError *error = NULL;
1619 GVariant *reply, *parameters;
1623 BT_TELEPHONY_CHECK_INITIALIZED();
1624 BT_TELEPHONY_CHECK_ENABLED();
1626 BT_DBG("Send Vendor %s", cmd);
1628 if (telephony_dbus_info.proxy == NULL)
1629 telephony_dbus_info.proxy =
1630 __bluetooth_telephony_get_connected_device_proxy();
1632 if (telephony_dbus_info.proxy == NULL)
1633 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1635 parameters = g_variant_new("s", cmd);
1636 reply = g_dbus_proxy_call_sync(telephony_dbus_info.proxy,
1637 "SendVendorAtCmd", parameters,
1638 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1640 g_variant_unref(reply);
1643 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1646 BT_EXPORT_API int bluetooth_telephony_start_voice_recognition(void)
1652 gboolean state = TRUE;
1656 BT_TELEPHONY_CHECK_INITIALIZED();
1657 BT_TELEPHONY_CHECK_ENABLED();
1659 param = g_variant_new("(b)", &state);
1660 reply = __bluetooth_telephony_dbus_method_send(
1661 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1662 "SetVoiceDial", &err, param);
1665 BT_ERR("Error returned in method call\n");
1667 g_dbus_error_strip_remote_error(err);
1668 ret = __bt_telephony_get_error(err->message);
1672 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1675 g_variant_unref(reply);
1677 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1680 BT_EXPORT_API int bluetooth_telephony_stop_voice_recognition(void)
1686 gboolean state = FALSE;
1690 BT_TELEPHONY_CHECK_INITIALIZED();
1691 BT_TELEPHONY_CHECK_ENABLED();
1693 param = g_variant_new("(b)", &state);
1694 reply = __bluetooth_telephony_dbus_method_send(
1695 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1696 "SetVoiceDial", &err, param);
1699 BT_ERR("Error returned in method call\n");
1701 g_dbus_error_strip_remote_error(err);
1702 ret = __bt_telephony_get_error(err->message);
1706 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1709 g_variant_unref(reply);
1712 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1715 static void __bluetooth_telephony_sco_start_cb(GDBusProxy *proxy,
1716 GAsyncResult *res, gpointer user_data)
1718 GError *error = NULL;
1721 value = g_dbus_proxy_call_finish(proxy, res, &error);
1722 if (value == NULL) {
1723 if (error != NULL) {
1724 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1725 error->code, error->message);
1726 g_clear_error(&error);
1728 BT_ERR("SCo Start Failed");
1732 BT_DBG("sco_start_cb : -");
1733 g_object_unref(proxy);
1734 g_variant_unref(value);
1737 BT_EXPORT_API int bluetooth_telephony_audio_open(void)
1739 GDBusConnection *conn;
1746 BT_TELEPHONY_CHECK_INITIALIZED();
1747 BT_TELEPHONY_CHECK_ENABLED();
1749 /* Because this API is async call, so can't use dbus SMACK */
1750 if (__bt_telephony_check_privilege() ==
1751 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1752 BT_ERR("Don't have a privilege to use this API");
1753 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1756 conn = _bt_gdbus_get_system_gconn();
1758 BT_DBG("No System Bus found\n");
1759 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1762 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING)
1763 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
1765 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1766 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1767 HFP_AGENT_INTERFACE, NULL, &err);
1768 if (proxy == NULL) {
1769 BT_ERR("Unable to allocate new proxy");
1771 g_dbus_error_strip_remote_error(err);
1772 ret = __bt_telephony_get_error(err->message);
1773 BT_ERR("Error here %d\n", ret);
1777 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1780 g_dbus_proxy_call(proxy, "Play", NULL, G_DBUS_CALL_FLAGS_NONE,
1781 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_start_cb, NULL);
1784 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1787 static void __bluetooth_telephony_sco_close_cb(GDBusProxy *proxy,
1788 GAsyncResult *res, gpointer user_data)
1790 GError *error = NULL;
1793 value = g_dbus_proxy_call_finish(proxy, res, &error);
1794 if (value == NULL) {
1795 if (error != NULL) {
1796 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1797 error->code, error->message);
1798 g_clear_error(&error);
1800 BT_ERR("SCo close Failed");
1804 BT_DBG("sco_close_cb : -");
1805 g_object_unref(proxy);
1806 g_variant_unref(value);
1808 BT_EXPORT_API int bluetooth_telephony_audio_close(void)
1810 GDBusConnection *conn;
1817 BT_TELEPHONY_CHECK_INITIALIZED();
1818 BT_TELEPHONY_CHECK_ENABLED();
1820 /* Because this API is async call, so can't use dbus SMACK */
1821 if (__bt_telephony_check_privilege() ==
1822 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1823 BT_ERR("Don't have a privilege to use this API");
1824 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1827 conn = _bt_gdbus_get_system_gconn();
1829 BT_DBG("No System Bus found\n");
1830 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1833 if (telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1834 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
1836 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1837 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1838 HFP_AGENT_INTERFACE, NULL, &err);
1839 if (proxy == NULL) {
1840 BT_ERR("Unable to allocate new proxy");
1842 g_dbus_error_strip_remote_error(err);
1843 ret = __bt_telephony_get_error(err->message);
1844 BT_ERR("Error here %d\n", ret);
1848 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1851 g_dbus_proxy_call(proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE,
1852 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_close_cb, NULL);
1854 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
1857 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1860 BT_EXPORT_API int bluetooth_telephony_call_remote_ringing(unsigned int call_id)
1864 BT_TELEPHONY_CHECK_INITIALIZED();
1865 BT_TELEPHONY_CHECK_ENABLED();
1868 BT_DBG("call_id = [%d]", call_id);
1870 /*Make sure SCO is already connected */
1871 ret = __bluetooth_telephony_send_call_status(
1872 CSD_CALL_STATUS_MO_ALERTING, call_id, NULL);
1873 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1874 BT_ERR("send call status Failed = [%d]", ret);
1875 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1878 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1881 BT_EXPORT_API int bluetooth_telephony_call_answered(unsigned int call_id,
1882 unsigned int bt_audio)
1887 BT_DBG("call_id = [%d]", call_id);
1889 BT_TELEPHONY_CHECK_INITIALIZED();
1890 BT_TELEPHONY_CHECK_ENABLED();
1892 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1894 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1895 BT_ERR("send call status Failed = [%d]", ret);
1900 if (!bluetooth_telephony_is_sco_connected()) {
1901 ret = bluetooth_telephony_audio_open();
1903 BT_ERR("Audio connection call Failed[%d]", ret);
1904 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1913 BT_EXPORT_API int bluetooth_telephony_call_end(unsigned int call_id)
1918 BT_DBG("call_id = [%d]", call_id);
1920 BT_TELEPHONY_CHECK_INITIALIZED();
1921 BT_TELEPHONY_CHECK_ENABLED();
1923 if (telephony_info.call_count > 0)
1924 telephony_info.call_count = telephony_info.call_count - 1;
1926 if (telephony_info.call_count == 0) {
1927 if (bluetooth_telephony_is_sco_connected()) {
1928 ret = bluetooth_telephony_audio_close();
1929 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1930 BT_ERR(" Failed = [%d]", ret);
1934 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_MT_RELEASE,
1936 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1937 BT_ERR("send call status Failed = [%d]", ret);
1945 BT_EXPORT_API int bluetooth_telephony_call_held(unsigned int call_id)
1950 BT_DBG("call_id = [%d]", call_id);
1952 BT_TELEPHONY_CHECK_INITIALIZED();
1953 BT_TELEPHONY_CHECK_ENABLED();
1955 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_HOLD,
1957 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1958 BT_ERR("send call status Failed = [%d]", ret);
1964 BT_EXPORT_API int bluetooth_telephony_call_retrieved(unsigned int call_id)
1969 BT_DBG("call_id = [%d]", call_id);
1971 BT_TELEPHONY_CHECK_INITIALIZED();
1972 BT_TELEPHONY_CHECK_ENABLED();
1974 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1976 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1977 BT_ERR("send call status Failed = [%d]", ret);
1983 BT_EXPORT_API int bluetooth_telephony_call_swapped(void *call_list,
1984 unsigned int call_count)
1988 GList *list = call_list;
1989 bt_telephony_call_status_info_t *call_status;
1993 BT_TELEPHONY_CHECK_INITIALIZED();
1994 BT_TELEPHONY_CHECK_ENABLED();
1997 BT_ERR("call_list is invalid");
1998 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2001 /* Because this API is async call, so can't use dbus SMACK */
2002 if (__bt_telephony_check_privilege() ==
2003 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
2004 BT_ERR("Don't have a privilege to use this API");
2005 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
2008 BT_DBG(" call_count = [%d]", call_count);
2010 for (i = 0; i < call_count; i++) {
2011 call_status = g_list_nth_data(list, i);
2013 if (NULL == call_status)
2016 BT_DBG(" %d : Call id [%d] status[%d]", i,
2017 call_status->call_id,
2018 call_status->call_status);
2020 if (NULL != call_status->phone_number)
2021 DBG_SECURE("Number [%s]", call_status->phone_number);
2023 switch (call_status->call_status) {
2024 case BLUETOOTH_CALL_STATE_HELD:
2025 ret = __bluetooth_telephony_send_call_status(
2026 CSD_CALL_STATUS_HOLD,
2027 call_status->call_id,
2028 call_status->phone_number);
2029 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2030 BT_ERR("Failed = %d", ret);
2035 case BLUETOOTH_CALL_STATE_CONNECTED:
2036 ret = __bluetooth_telephony_send_call_status(
2037 CSD_CALL_STATUS_ACTIVE,
2038 call_status->call_id,
2039 call_status->phone_number);
2040 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2041 BT_ERR("Failed = [%d]", ret);
2047 if ((call_status->call_status <
2048 BLUETOOTH_CALL_STATE_NONE) ||
2049 (call_status->call_status >=
2050 BLUETOOTH_CALL_STATE_ERROR)) {
2051 BT_ERR("Unknown Call state");
2052 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
2058 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2061 BT_EXPORT_API int bluetooth_telephony_set_call_status(void *call_list,
2062 unsigned int call_count)
2068 ret = bluetooth_telephony_call_swapped(call_list, call_count);
2070 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2071 BT_ERR("Failed = [%d]", ret);
2075 telephony_info.call_count = call_count;
2078 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2081 BT_EXPORT_API int bluetooth_telephony_indicate_outgoing_call(
2082 const char *ph_number, unsigned int call_id,
2083 unsigned int bt_audio)
2088 const char *path = telephony_info.call_path;
2093 BT_TELEPHONY_CHECK_INITIALIZED();
2094 BT_TELEPHONY_CHECK_ENABLED();
2096 if (NULL == ph_number)
2097 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2099 param = g_variant_new("(ssi)", path, ph_number, call_id);
2100 reply = __bluetooth_telephony_dbus_method_send(
2101 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2102 "OutgoingCall", &err, param);
2105 BT_ERR("Error returned in method call\n");
2107 g_dbus_error_strip_remote_error(err);
2108 ret = __bt_telephony_get_error(err->message);
2112 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2115 g_variant_unref(reply);
2117 telephony_info.call_count++;
2118 BT_DBG(" ag_info.ag_call_count = [%d]", telephony_info.call_count);
2121 if (!bluetooth_telephony_is_sco_connected()) {
2122 ret = bluetooth_telephony_audio_open();
2124 BT_ERR(" Audio connection Failed = %d", ret);
2125 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2131 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2134 BT_EXPORT_API int bluetooth_telephony_indicate_incoming_call(
2135 const char *ph_number, unsigned int call_id)
2140 const char *path = telephony_info.call_path;
2145 BT_TELEPHONY_CHECK_INITIALIZED();
2146 BT_TELEPHONY_CHECK_ENABLED();
2148 if (NULL == ph_number)
2149 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2151 param = g_variant_new("(ssi)", path, ph_number, call_id);
2152 reply = __bluetooth_telephony_dbus_method_send(
2153 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2154 "IncomingCall", &err, param);
2157 BT_ERR("Error returned in method call\n");
2159 g_dbus_error_strip_remote_error(err);
2160 ret = __bt_telephony_get_error(err->message);
2164 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2167 g_variant_unref(reply);
2168 telephony_info.call_count++;
2169 BT_DBG("telephony_info.call_count = [%d]", telephony_info.call_count);
2171 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2174 BT_EXPORT_API int bluetooth_telephony_set_speaker_gain(
2175 unsigned short speaker_gain)
2184 BT_TELEPHONY_CHECK_INITIALIZED();
2185 BT_TELEPHONY_CHECK_ENABLED();
2187 BT_DBG("set speaker_gain= [%d]", speaker_gain);
2189 param = g_variant_new("(q)", speaker_gain);
2190 reply = __bluetooth_telephony_dbus_method_send(
2191 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2192 "SetSpeakerGain", &err, param);
2195 BT_ERR("Error returned in method call\n");
2197 g_dbus_error_strip_remote_error(err);
2198 ret = __bt_telephony_get_error(err->message);
2202 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2205 g_variant_unref(reply);
2207 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2210 BT_EXPORT_API int bluetooth_telephony_get_headset_volume(
2211 unsigned int *speaker_gain)
2220 BT_TELEPHONY_CHECK_INITIALIZED();
2221 BT_TELEPHONY_CHECK_ENABLED();
2223 reply = __bluetooth_telephony_dbus_method_send(
2224 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2225 "GetSpeakerGain", &err, NULL);
2228 BT_ERR("Error returned in method call\n");
2230 g_dbus_error_strip_remote_error(err);
2231 ret = __bt_telephony_get_error(err->message);
2235 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2237 g_variant_get(reply, "(q)", &gain);
2238 *speaker_gain = gain;
2239 BT_DBG("Get speaker_gain= [%d]", *speaker_gain);
2241 g_variant_unref(reply);
2244 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2247 BT_EXPORT_API int bluetooth_telephony_is_connected(gboolean *ag_connected)
2252 gboolean ag_connected_from_bt_agent;
2254 BT_CHECK_ENABLED(return);
2256 reply = __bluetooth_telephony_dbus_method_send(
2257 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2258 "IsConnected", &err, NULL);
2261 BT_ERR("Error returned in method call\n");
2263 g_dbus_error_strip_remote_error(err);
2264 ret = __bt_telephony_get_error(err->message);
2268 return BLUETOOTH_ERROR_INTERNAL;
2270 g_variant_get(reply, "(b)", &ag_connected_from_bt_agent);
2271 *ag_connected = ag_connected_from_bt_agent;
2273 BT_DBG("Conn Status: %s", *ag_connected ? "Connected" : "Disconnected");
2275 g_variant_unref(reply);
2277 return BLUETOOTH_ERROR_NONE;
2280 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
2281 const gchar *sender_name,
2282 const gchar *object_path,
2283 const gchar *interface_name,
2284 const gchar *signal_name,
2285 GVariant *parameters,
2292 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
2293 GVariant *optional_param = NULL;
2295 g_variant_get(parameters, "(&o@a{sa{sv}})",
2296 &path, &optional_param);
2299 BT_ERR("Invalid adapter path");
2303 BT_INFO("Adapter Path = [%s]", path);
2304 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
2305 if (__bt_telephony_get_src_addr(optional_param))
2306 BT_ERR("Fail to get the local adapter address");
2308 ret = __bluetooth_telephony_register();
2309 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
2310 BT_ERR("__bluetooth_telephony_register failed");
2317 static int __bt_telephony_get_src_addr(GVariant *value)
2320 GVariant *param = NULL;
2323 /* signature a{sa{sv}} */
2324 g_variant_iter_init(&iter, value);
2325 while ((param = g_variant_iter_next_value(&iter))) {
2326 char *interface_name;
2327 GVariant *interface_var = NULL;
2328 GVariant *param_inner = NULL;
2330 g_variant_get(param, "{&s*}", &interface_name, &interface_var);
2331 g_variant_unref(param);
2333 BT_DBG("interface_name: %s", interface_name);
2334 /* format of interface_var: a{sv}*/
2335 if (strcasecmp(interface_name, BLUEZ_ADAPTER_INTERFACE) == 0) {
2336 GVariantIter iter_inner;
2338 g_variant_iter_init(&iter_inner, interface_var);
2339 while ((param_inner = g_variant_iter_next_value(&iter_inner))) {
2340 char *property_name;
2341 GVariant *property_var;
2343 g_variant_get(param_inner, "{&sv}",
2346 g_variant_unref(param_inner);
2348 if (strcasecmp(property_name, "Address") == 0) {
2349 const gchar *bd_addr;
2351 bd_addr = g_variant_get_string(
2354 src_addr = g_strdup(bd_addr);
2355 BT_DBG("Address: %s", src_addr);
2357 g_variant_unref(interface_var);
2358 g_variant_unref(property_var);
2361 g_variant_unref(property_var);
2364 g_variant_unref(interface_var);
2368 return BLUETOOTH_ERROR_NONE;