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) { \
97 BT_ERR("BT is not enabled"); \
98 return BLUETOOTH_TELEPHONY_ERROR_NOT_ENABLED; \
102 static gboolean is_initialized = FALSE;
103 #define BT_TELEPHONY_CHECK_INITIALIZED() \
105 if (is_initialized == FALSE) { \
106 BT_ERR("Bluetooth telephony not initilized"); \
107 return BLUETOOTH_TELEPHONY_ERROR_NOT_INITIALIZED; \
111 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
112 const gchar *sender_name,
113 const gchar *object_path,
114 const gchar *interface_name,
115 const gchar *signal_name,
116 GVariant *parameters,
119 static int __bt_telephony_get_src_addr(GVariant *value);
121 static bt_telephony_info_t telephony_info;
122 static telephony_dbus_info_t telephony_dbus_info;
123 static gboolean is_active = FALSE;
125 /*Function Declaration*/
126 static int __bt_telephony_get_error(const char *error_message);
127 static void __bt_telephony_event_cb(int event, int result, void *param_data);
128 static GQuark __bluetooth_telephony_error_quark(void);
129 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
130 const char *interface, const char *method,
131 GError **err, GVariant *parameters);
132 static int __bluetooth_telephony_send_call_status(
133 bt_telephony_call_status_t call_status,
134 unsigned int call_id, const char *ph_number);
135 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
136 bluetooth_telephony_error_t error, const char *err_msg);
138 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
139 const gchar *sender_name,
140 const gchar *object_path,
141 const gchar *interface_name,
142 const gchar *signal_name,
143 GVariant *parameters,
146 static int __bluetooth_telephony_proxy_init(void);
147 static void __bluetooth_telephony_proxy_deinit(void);
148 static int __bluetooth_telephony_register(void);
149 static int __bluetooth_telephony_unregister(void);
151 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class);
152 static int __bluetooth_telephony_get_connected_device(void);
153 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void);
155 /*Function Definition*/
156 static void __bt_telephony_method(GDBusConnection *connection,
158 const gchar *object_path,
159 const gchar *interface_name,
160 const gchar *method_name,
161 GVariant *parameters,
162 GDBusMethodInvocation *invocation,
167 BT_INFO("method %s", method_name);
168 BT_INFO("object_path %s", object_path);
170 if (g_strcmp0(method_name, "SendDtmf") == 0) {
172 telephony_event_dtmf_t call_data = { 0, };
174 g_variant_get(parameters, "(&s)", &dtmf);
177 BT_ERR("Number dial failed");
178 __bluetooth_telephony_error(invocation,
179 BLUETOOTH_TELEPHONY_ERROR_INVALID_DTMF,
182 DBG_SECURE("Dtmf = %s", dtmf);
184 call_data.dtmf = g_strdup(dtmf);
185 __bt_telephony_event_cb(
186 BLUETOOTH_EVENT_TELEPHONY_SEND_DTMF,
187 BLUETOOTH_TELEPHONY_ERROR_NONE,
190 g_free(call_data.dtmf);
192 g_dbus_method_invocation_return_value(invocation, NULL);
194 } else if (g_strcmp0(method_name, "VendorCmd") == 0) {
197 g_variant_get(parameters, "(&s)", &at_cmd);
198 BT_INFO("Vendor %s", at_cmd);
199 if (at_cmd == NULL) {
200 BT_ERR("Vendor command is NULL\n");
201 __bluetooth_telephony_error(invocation,
202 BLUETOOTH_TELEPHONY_ERROR_APPLICATION,
203 "Invalid at vendor cmd");
205 DBG_SECURE("Vendor AT cmd = %s", at_cmd);
207 __bt_telephony_event_cb(
208 BLUETOOTH_EVENT_TELEPHONY_VENDOR_AT_CMD,
209 BLUETOOTH_TELEPHONY_ERROR_NONE,
212 g_dbus_method_invocation_return_value(invocation, NULL);
219 static const GDBusInterfaceVTable method_table = {
220 __bt_telephony_method,
225 static int __bt_telephony_get_error(const char *error_message)
227 if (error_message == NULL) {
228 BT_ERR("Error message NULL");
229 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
232 BT_ERR("Error message = %s", error_message);
233 if (g_strcmp0(error_message, "NotAvailable") == 0)
234 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
235 else if (g_strcmp0(error_message, "NotConnected") == 0)
236 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
237 else if (g_strcmp0(error_message, "InProgress") == 0)
238 return BLUETOOTH_TELEPHONY_ERROR_BUSY;
239 else if (g_strcmp0(error_message, "InvalidArguments") == 0)
240 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
241 else if (g_strcmp0(error_message, "AlreadyExists") == 0)
242 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_EXSIST;
243 else if (g_strcmp0(error_message, "Already Connected") == 0)
244 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
245 else if (g_strcmp0(error_message, "No memory") == 0)
246 return BLUETOOTH_TELEPHONY_ERROR_NO_MEMORY;
247 else if (g_strcmp0(error_message, "I/O error") == 0)
248 return BLUETOOTH_TELEPHONY_ERROR_I_O_ERROR;
249 else if (g_strcmp0(error_message,
250 "Operation currently not available") == 0)
251 return BLUETOOTH_TELEPHONY_ERROR_OPERATION_NOT_AVAILABLE;
252 else if (g_strrstr(error_message, BT_ACCESS_DENIED_MSG))
253 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
255 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
258 static int __bt_telephony_check_privilege(void)
265 reply = __bluetooth_telephony_dbus_method_send(
266 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
267 "CheckPrivilege", &err, NULL);
270 BT_ERR("Error returned in method call");
272 g_dbus_error_strip_remote_error(err);
273 ret = __bt_telephony_get_error(err->message);
277 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
279 g_variant_unref(reply);
282 return BLUETOOTH_TELEPHONY_ERROR_NONE;
285 static void __bt_telephony_event_cb(int event, int result, void *param_data)
287 telephony_event_param_t bt_event = { 0, };
289 bt_event.event = event;
290 bt_event.result = result;
291 bt_event.param_data = param_data;
293 ret_if(telephony_info.cb == NULL);
294 telephony_info.cb(bt_event.event, &bt_event, telephony_info.user_data);
298 static GQuark __bluetooth_telephony_error_quark(void)
300 static GQuark quark = 0;
302 quark = g_quark_from_static_string("telephony");
307 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
308 const char *interface, const char *method,
309 GError **err, GVariant *parameters)
311 #ifdef TIZEN_PROFILE_WEARABLE
318 GDBusConnection *conn;
322 conn = telephony_dbus_info.conn;
323 retv_if(conn == NULL, NULL);
325 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
326 NULL, HFP_AGENT_SERVICE, path, interface, NULL, err);
328 BT_ERR("Unable to allocate new proxy");
332 reply = g_dbus_proxy_call_sync(proxy, method, parameters,
333 G_DBUS_CALL_FLAGS_NONE, timeout, NULL, err);
335 g_object_unref(proxy);
340 static int __bluetooth_telephony_send_call_status(
341 bt_telephony_call_status_t call_status,
342 unsigned int call_id, const char *ph_number)
347 char *path = g_strdup(telephony_info.call_path);
353 if (NULL == ph_number)
354 phone_number = g_strdup("");
356 phone_number = g_strdup(ph_number);
358 param = g_variant_new("(ssii)", path, phone_number,
359 call_status, call_id);
360 reply = __bluetooth_telephony_dbus_method_send(
361 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
362 "ChangeCallStatus", &err, param);
365 g_free(phone_number);
368 BT_ERR("Error returned in method call");
370 g_dbus_error_strip_remote_error(err);
371 ret = __bt_telephony_get_error(err->message);
375 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
378 g_variant_unref(reply);
380 return BLUETOOTH_TELEPHONY_ERROR_NONE;
383 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
384 bluetooth_telephony_error_t error, const char *err_msg)
386 g_dbus_method_invocation_return_error(invocation,
387 BLUETOOTH_TELEPHONY_ERROR, error,
391 static void __bluetooth_telephony_answer_call(GVariant *var)
393 telephony_event_callid_t call_data = { 0, };
398 g_variant_get(var, "(u)", &callid);
399 BT_DBG("call_id = [%d]", callid);
400 call_data.callid = callid;
402 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_ANSWER_CALL,
403 BLUETOOTH_TELEPHONY_ERROR_NONE,
408 static void __bluetooth_telephony_release_call(GVariant *var)
410 telephony_event_callid_t call_data = { 0, };
415 g_variant_get(var, "(u)", &callid);
416 BT_DBG("call_id = [%d]", callid);
417 call_data.callid = callid;
419 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_RELEASE_CALL,
420 BLUETOOTH_TELEPHONY_ERROR_NONE,
425 static void __bluetooth_telephony_reject_call(GVariant *var)
427 telephony_event_callid_t call_data = { 0, };
432 g_variant_get(var, "(u)", &callid);
433 BT_DBG("call_id = [%d]", callid);
434 call_data.callid = callid;
436 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_REJECT_CALL,
437 BLUETOOTH_TELEPHONY_ERROR_NONE,
442 static void __bluetooth_telephony_threeway_call(GVariant *var)
445 unsigned int chld_value;
449 g_variant_get(var, "(u)", &chld_value);
450 BT_DBG("chld value = [%d]", chld_value);
452 switch (chld_value) {
454 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_0_RELEASE_ALL_HELD_CALL;
457 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_1_RELEASE_ALL_ACTIVE_CALL;
460 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_2_ACTIVE_HELD_CALL;
463 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_3_MERGE_CALL;
466 BT_ERR("Invalid CHLD command");
470 __bt_telephony_event_cb(event,
471 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
475 static void __bluetooth_handle_nrec_status_change(GVariant *var)
477 gboolean status = FALSE;
479 g_variant_get(var, "(b)", &status);
480 BT_INFO("NREC status = %d", status);
482 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_NREC_CHANGED,
483 BLUETOOTH_TELEPHONY_ERROR_NONE, (void *)&status);
487 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
488 const gchar *sender_name,
489 const gchar *object_path,
490 const gchar *interface_name,
491 const gchar *signal_name,
492 GVariant *parameters,
497 if (strcasecmp(interface_name, HFP_AGENT_SERVICE) == 0) {
498 if (strcasecmp(signal_name, HFP_NREC_STATUS_CHANGE) == 0)
499 __bluetooth_handle_nrec_status_change(parameters);
500 else if (strcasecmp(signal_name, HFP_ANSWER_CALL) == 0)
501 __bluetooth_telephony_answer_call(parameters);
502 else if (strcasecmp(signal_name, HFP_REJECT_CALL) == 0)
503 __bluetooth_telephony_reject_call(parameters);
504 else if (strcasecmp(signal_name, HFP_RELEASE_CALL) == 0)
505 __bluetooth_telephony_release_call(parameters);
506 else if (strcasecmp(signal_name, HFP_THREEWAY_CALL) == 0)
507 __bluetooth_telephony_threeway_call(parameters);
508 } else if (strcasecmp(interface_name, BLUEZ_HEADSET_INTERFACE) == 0) {
509 if (strcasecmp(signal_name, "PropertyChanged") == 0) {
513 g_variant_get(parameters, "(&sv)", &property, &values);
514 BT_DBG("Property: %s", property);
516 if (strcasecmp(property, "State") == 0) {
518 state = (gchar *)g_variant_get_string(values, NULL);
521 BT_ERR("State is null");
524 BT_DBG("state: %s", state);
525 if (g_strcmp0(state, "connected") == 0) {
526 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
527 } else if (g_strcmp0(state, "playing") == 0) {
528 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
529 } else if (g_strcmp0(state, "disconnected") == 0) {
530 /* Headset state: playing -> disconnected */
531 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING) {
532 __bt_telephony_event_cb(
533 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
534 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
537 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
539 } else if (strcasecmp(property, "Connected") == 0) {
540 gboolean connected = FALSE;
541 char *dev_addr = NULL;
542 connected = g_variant_get_boolean(values);
543 BT_INFO("connected %d", connected);
545 /*Get device address*/
546 if (object_path != NULL)
547 dev_addr = strstr(object_path, "dev_");
549 if (dev_addr != NULL) {
551 g_strlcpy(telephony_info.address,
553 sizeof(telephony_info.address));
554 g_strdelimit(telephony_info.address, "_", ':');
555 BT_DBG("address is %s",
556 telephony_info.address);
558 telephony_info.headset_state =
559 BLUETOOTH_STATE_CONNECTED;
561 if (telephony_dbus_info.proxy != NULL) {
562 g_object_unref(telephony_dbus_info.proxy);
563 telephony_dbus_info.proxy = NULL;
566 telephony_dbus_info.proxy =
567 __bluetooth_telephony_get_connected_device_proxy();
569 BT_INFO("Headset Connected");
571 __bt_telephony_event_cb(
572 BLUETOOTH_EVENT_TELEPHONY_HFP_CONNECTED,
573 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
575 } else { /*Device disconnected*/
576 memset(telephony_info.address, 0x00,
577 sizeof(telephony_info.address));
578 telephony_info.headset_state =
579 BLUETOOTH_STATE_DISCONNETED;
581 if (telephony_dbus_info.proxy != NULL) {
582 g_object_unref(telephony_dbus_info.proxy);
583 telephony_dbus_info.proxy = NULL;
586 BT_INFO("Headset Disconnected");
588 __bt_telephony_event_cb(
589 BLUETOOTH_EVENT_TELEPHONY_HFP_DISCONNECTED,
590 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
592 } else if (strcasecmp(property, "SpeakerGain") == 0) {
593 unsigned int spkr_gain;
594 guint16 gain = g_variant_get_uint16(values);
596 spkr_gain = (unsigned int)gain;
597 BT_DBG("spk_gain[%d]", spkr_gain);
599 __bt_telephony_event_cb(
600 BLUETOOTH_EVENT_TELEPHONY_SET_SPEAKER_GAIN,
601 BLUETOOTH_TELEPHONY_ERROR_NONE,
603 } else if (strcasecmp(property, "MicrophoneGain") == 0) {
604 unsigned int mic_gain;
605 guint16 gain = g_variant_get_uint16(values);
607 mic_gain = (unsigned int)gain;
608 BT_DBG("mic_gain[%d]", mic_gain);
610 __bt_telephony_event_cb(
611 BLUETOOTH_EVENT_TELEPHONY_SET_MIC_GAIN,
612 BLUETOOTH_TELEPHONY_ERROR_NONE,
614 } else if (strcasecmp(property, "Playing") == 0) {
615 gboolean audio_sink_playing;
617 audio_sink_playing = g_variant_get_boolean(values);
618 if (audio_sink_playing) {
619 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
620 __bt_telephony_event_cb(
621 BLUETOOTH_EVENT_TELEPHONY_AUDIO_CONNECTED,
622 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
624 telephony_info.headset_state =
625 BLUETOOTH_STATE_CONNECTED;
626 __bt_telephony_event_cb(
627 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
628 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
632 g_variant_unref(values);
638 static GDBusNodeInfo *__bt_telephony_create_method_node_info
639 (const gchar *introspection_data)
642 GDBusNodeInfo *node_info = NULL;
644 if (introspection_data == NULL)
647 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
650 BT_ERR("Unable to create node: %s", err->message);
657 int __bluetooth_telephony_register_object(int reg, GDBusNodeInfo *node_info)
659 static guint bt_tel_id = 0;
660 GError *error = NULL;
664 if (node_info == NULL)
665 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
667 path = g_strdup(telephony_info.call_path);
668 BT_DBG("path is [%s]", path);
670 bt_tel_id = g_dbus_connection_register_object(telephony_dbus_info.conn,
671 path, node_info->interfaces[0],
676 if (bt_tel_id == 0) {
677 BT_ERR("Failed to register: %s", error->message);
679 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
683 g_dbus_connection_unregister_object(telephony_dbus_info.conn,
689 return BLUETOOTH_TELEPHONY_ERROR_NONE;
692 static int __bluetooth_telephony_proxy_init(void)
696 GDBusNodeInfo *node_info;
698 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
699 TELEPHONY_APP_INTERFACE,
700 G_BUS_NAME_OWNER_FLAGS_NONE,
703 BT_DBG("owner_id is [%d]", owner_id);
705 node_info = __bt_telephony_create_method_node_info(
706 bt_telephony_introspection_xml);
708 if (node_info == NULL) {
709 BT_ERR("node_info NULL");
710 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
712 if (__bluetooth_telephony_register_object(TRUE, node_info) !=
713 BLUETOOTH_TELEPHONY_ERROR_NONE) {
714 BT_ERR("Registation of Method Failed");
715 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
719 return BLUETOOTH_TELEPHONY_ERROR_NONE;
722 static void __bluetooth_telephony_proxy_deinit(void)
726 __bluetooth_telephony_register_object(FALSE, NULL);
732 static int __bluetooth_telephony_register(void)
737 char *path = g_strdup(telephony_info.call_path);
742 param = g_variant_new("(ss)", path, src_addr);
743 BT_DBG("Path[%s] Src_Address[%s]", path, src_addr);
745 reply = __bluetooth_telephony_dbus_method_send(
746 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
747 "RegisterApplication", &err, param);
752 BT_ERR("Error returned in method call");
754 g_dbus_error_strip_remote_error(err);
755 ret = __bt_telephony_get_error(err->message);
756 BT_ERR("Error here %d\n", ret);
760 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
763 g_variant_unref(reply);
764 BT_DBG("__bluetooth_telephony_register completed");
766 return BLUETOOTH_TELEPHONY_ERROR_NONE;
769 static int __bluetooth_telephony_unregister(void)
774 char *path = g_strdup(telephony_info.call_path);
779 param = g_variant_new("(s)", path);
780 reply = __bluetooth_telephony_dbus_method_send(
781 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
782 "UnregisterApplication", &err, param);
787 BT_ERR("Error returned in method call");
789 g_dbus_error_strip_remote_error(err);
790 ret = __bt_telephony_get_error(err->message);
794 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
797 g_variant_unref(reply);
798 BT_DBG("__bluetooth_telephony_unregister completed");
800 return BLUETOOTH_TELEPHONY_ERROR_NONE;
803 #ifndef TIZEN_PROFILE_WEARABLE
804 static void __bluetooth_telephony_init_headset_state(void)
808 gboolean status = FALSE;
812 if (telephony_dbus_info.conn == NULL) {
813 BT_ERR("Bluetooth telephony not initilized");
817 reply = __bluetooth_telephony_dbus_method_send(
818 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
819 "IsConnected", &err, NULL);
821 BT_ERR("Error returned in method call\n");
823 BT_ERR("Error message = %s", err->message);
829 g_variant_get(reply, "(b)", &status);
830 g_variant_unref(reply);
832 BT_INFO("Headset Connected Status = [%d]", status);
834 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
838 if (bluetooth_telephony_is_sco_connected())
839 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
845 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class)
847 gboolean flag = FALSE;
850 switch ((device_class & 0x1f00) >> 8) {
852 switch ((device_class & 0xfc) >> 2) {
870 /* Tizen Wearable device */
872 switch ((device_class & 0xfc) >> 2) {
873 case 0x01: /* Wrist Watch */
881 BT_DBG("[%d]", flag);
886 static gboolean __bluetooth_telephony_is_headset_by_uuid(gchar **uuids)
890 unsigned int service = 0;
894 retv_if(uuids == NULL, FALSE);
896 for (i = 0; uuids[i] != NULL; i++) {
897 parts = g_strsplit(uuids[i], "-", -1);
899 if (parts == NULL || parts[0] == NULL) {
904 service = g_ascii_strtoull(parts[0], NULL, 16);
907 if (service == BLUETOOTH_HS_PROFILE_UUID ||
908 service == BLUETOOTH_HF_PROFILE_UUID)
917 static int __bluetooth_telephony_get_connected_device(void)
919 GDBusConnection *conn;
920 GDBusProxy *headset_agent_proxy = NULL;
921 GDBusProxy *manager_proxy = NULL;
922 GDBusProxy *proxy = NULL;
923 GVariant *reply = NULL;
924 GVariant *getall = NULL;
925 GVariant *isPlayingReply = NULL;
926 GVariant *isConnectedReply = NULL;
927 GVariant *param = NULL;
928 GVariant *var_path = NULL;
929 GVariant *path_values = NULL;
930 GVariant *value = NULL;
931 GError *error = NULL;
933 GVariantIter iter_path;
934 GVariantIter property_iter;
935 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
938 conn = _bt_gdbus_get_system_gconn();
939 retv_if(conn == NULL, BLUETOOTH_TELEPHONY_ERROR_INTERNAL);
941 manager_proxy = g_dbus_proxy_new_sync(
942 conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
943 BLUEZ_SERVICE_NAME, "/",
944 BLUEZ_MANAGER_INTERFACE, NULL, &error);
945 if (manager_proxy == NULL) {
946 BT_ERR("Unable to allocate new proxy \n");
947 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
949 g_dbus_error_strip_remote_error(error);
950 ret = __bt_telephony_get_error(error->message);
951 BT_ERR("Error here %d\n", ret);
957 /* Synchronous call */
958 reply = g_dbus_proxy_call_sync(manager_proxy, "GetManagedObjects", NULL,
959 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
960 g_object_unref(manager_proxy);
963 BT_ERR("Can't get managed objects");
964 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
966 g_dbus_error_strip_remote_error(error);
967 ret = __bt_telephony_get_error(error->message);
968 BT_ERR("Error here %d\n", ret);
974 /* signature of GetManagedObjects: a{oa{sa{sv}}} */
975 g_variant_iter_init(&iter, reply);
977 while ((param = g_variant_iter_next_value(&iter))) {
978 g_variant_iter_init(&iter_path, param);
980 while ((var_path = g_variant_iter_next_value(&iter_path))) {
982 uint32_t device_class = 0;
983 gboolean playing = FALSE;
984 gboolean connected = FALSE;
985 char *object_path = NULL;
986 gchar *address = NULL;
988 gchar **uuids = NULL;
989 GVariant *getall_param = NULL;
991 g_variant_get(var_path, "{&o*}", &object_path,
993 g_variant_unref(path_values); /* path_values unused*/
995 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
996 G_DBUS_PROXY_FLAGS_NONE, NULL,
997 BLUEZ_SERVICE_NAME, object_path,
998 BLUEZ_PROPERTIES_INTERFACE, NULL, &error);
1000 BT_ERR("Unable to allocate new proxy \n");
1001 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1003 g_dbus_error_strip_remote_error(error);
1004 ret = __bt_telephony_get_error(error->message);
1005 BT_ERR("Error here %d\n", ret);
1006 g_error_free(error);
1012 getall_param = g_variant_new("s", BLUEZ_DEVICE_INTERFACE);
1013 getall = g_dbus_proxy_call_sync(proxy,
1014 "GetAll", getall_param,
1015 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1016 g_object_unref(proxy);
1019 BT_ERR("Can't get managed objects");
1020 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1022 g_dbus_error_strip_remote_error(error);
1023 ret = __bt_telephony_get_error(error->message);
1024 BT_ERR("Error here %d\n", ret);
1025 g_error_free(error);
1030 g_variant_iter_init(&property_iter, getall);
1032 while (g_variant_iter_loop(&property_iter, "{&sv}", &key, &value)) {
1033 if (!g_strcmp0(key, "Class")) {
1034 device_class = g_variant_get_uint32(value);
1035 BT_DBG("Device Class: %d", device_class);
1036 } else if (!g_strcmp0(key, "UUID")) {
1038 uuids = (gchar **)g_variant_get_strv(value, &len);
1039 BT_DBG_UUID(uuids, len, i);
1040 } else if (!g_strcmp0(key, "Address")) {
1041 address = (gchar *)g_variant_get_string(
1044 BT_DBG("Device Class: %s", address);
1046 g_variant_unref(value);
1048 g_variant_unref(getall);
1050 if (device_class == 0) {
1051 BT_DBG("COD is NULL (maybe paired by nfc)... Checking UUIDs");
1052 if (!__bluetooth_telephony_is_headset_by_uuid(uuids)) {
1053 BT_DBG("UUID checking completed. None HF device");
1056 BT_DBG("UUID checking completed. HF device");
1058 if (!__bluetooth_telephony_is_headset(device_class))
1062 /* this is headset; Check for Connection */
1063 headset_agent_proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1064 G_DBUS_PROXY_FLAGS_NONE, NULL,
1065 HFP_AGENT_SERVICE, object_path,
1066 HFP_AGENT_INTERFACE, NULL, &error);
1067 if (headset_agent_proxy == NULL) {
1068 BT_ERR("Unable to allocate new headset_agent_proxy");
1069 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1071 g_dbus_error_strip_remote_error(error);
1072 ret = __bt_telephony_get_error(error->message);
1073 BT_ERR("Error here %d\n", ret);
1074 g_error_free(error);
1079 isConnectedReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1080 "IsConnected", NULL,
1081 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1084 if (!isConnectedReply) {
1085 BT_ERR("Can't get managed objects");
1086 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1088 g_dbus_error_strip_remote_error(error);
1089 ret = __bt_telephony_get_error(error->message);
1090 BT_ERR("Error here %d\n", ret);
1091 g_error_free(error);
1095 connected = g_variant_get_boolean(isConnectedReply);
1096 g_variant_unref(isConnectedReply);
1099 g_strlcpy(telephony_info.address,
1101 sizeof(telephony_info.address));
1103 isPlayingReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1105 G_DBUS_CALL_FLAGS_NONE,
1107 if (!isPlayingReply) {
1108 BT_ERR("Can't get managed objects");
1109 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1111 g_dbus_error_strip_remote_error(error);
1112 ret = __bt_telephony_get_error(error->message);
1113 BT_ERR("Error here %d\n", ret);
1114 g_error_free(error);
1117 playing = g_variant_get_boolean(isPlayingReply);
1118 g_variant_unref(isPlayingReply);
1121 telephony_info.headset_state =
1122 BLUETOOTH_STATE_PLAYING;
1124 telephony_info.headset_state =
1125 BLUETOOTH_STATE_CONNECTED;
1132 g_object_unref(headset_agent_proxy);
1133 g_variant_unref(var_path);
1135 g_variant_unref(param);
1139 if (headset_agent_proxy)
1140 g_object_unref(headset_agent_proxy);
1142 g_variant_unref(reply);
1144 g_variant_unref(var_path);
1146 g_variant_unref(param);
1151 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void)
1153 GDBusProxy *proxy = NULL;
1154 GError *error = NULL;
1158 if (strlen(telephony_info.address) == 0)
1159 __bluetooth_telephony_get_connected_device();
1161 if (strlen(telephony_info.address) == 0)
1164 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1165 G_DBUS_PROXY_FLAGS_NONE, NULL,
1166 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1167 HFP_AGENT_INTERFACE, NULL, &error);
1168 if (proxy == NULL) {
1169 BT_ERR("Unable to allocate new proxy");
1171 g_dbus_error_strip_remote_error(error);
1172 ret = __bt_telephony_get_error(error->message);
1173 BT_ERR("Error here %d\n", ret);
1174 g_error_free(error);
1183 int __bt_telephony_subscribe_adapter_signal(GDBusConnection *conn,
1189 static int subscribe_adapter_id = -1;
1190 if (subscribe == TRUE) {
1191 if (subscribe_adapter_id == -1) {
1192 subscribe_adapter_id = g_dbus_connection_signal_subscribe(conn,
1193 NULL, "org.freedesktop.DBus.ObjectManager",
1194 "InterfacesAdded", NULL, NULL, 0,
1195 __bt_telephony_adapter_filter,
1198 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1200 if (subscribe_adapter_id != -1) {
1201 g_dbus_connection_signal_unsubscribe(conn,
1202 subscribe_adapter_id);
1203 subscribe_adapter_id = -1;
1205 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1209 int __bt_telephony_event_subscribe_signal(GDBusConnection *conn,
1215 static int subscribe_event1_id = -1;
1216 static int subscribe_event2_id = -1;
1217 static int subscribe_event3_id = -1;
1218 static int subscribe_event4_id = -1;
1219 static int subscribe_event5_id = -1;
1220 static int subscribe_event6_id = -1;
1221 if (subscribe == TRUE) {
1222 if (subscribe_event1_id == -1) {
1223 subscribe_event1_id = g_dbus_connection_signal_subscribe(conn,
1224 NULL, BLUEZ_HEADSET_INTERFACE,
1225 "PropertyChanged", NULL, NULL, 0,
1226 __bluetooth_telephony_event_filter,
1229 if (subscribe_event2_id == -1) {
1230 subscribe_event2_id = g_dbus_connection_signal_subscribe(conn,
1231 NULL, HFP_AGENT_SERVICE,
1232 HFP_NREC_STATUS_CHANGE, NULL, NULL, 0,
1233 __bluetooth_telephony_event_filter,
1237 if (subscribe_event3_id == -1) {
1238 subscribe_event3_id = g_dbus_connection_signal_subscribe(conn,
1239 NULL, HFP_AGENT_SERVICE,
1240 HFP_ANSWER_CALL, NULL, NULL, 0,
1241 __bluetooth_telephony_event_filter,
1244 if (subscribe_event4_id == -1) {
1245 subscribe_event4_id = g_dbus_connection_signal_subscribe(conn,
1246 NULL, HFP_AGENT_SERVICE,
1247 HFP_REJECT_CALL, NULL, NULL, 0,
1248 __bluetooth_telephony_event_filter,
1251 if (subscribe_event5_id == -1) {
1252 subscribe_event5_id = g_dbus_connection_signal_subscribe(conn,
1253 NULL, HFP_AGENT_SERVICE,
1254 HFP_RELEASE_CALL, NULL, NULL, 0,
1255 __bluetooth_telephony_event_filter,
1258 if (subscribe_event6_id == -1) {
1259 subscribe_event6_id = g_dbus_connection_signal_subscribe(conn,
1260 NULL, HFP_AGENT_SERVICE,
1261 HFP_THREEWAY_CALL, NULL, NULL, 0,
1262 __bluetooth_telephony_event_filter,
1266 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1268 if (subscribe_event1_id != -1) {
1269 g_dbus_connection_signal_unsubscribe(conn,
1270 subscribe_event1_id);
1271 subscribe_event1_id = -1;
1273 if (subscribe_event2_id != -1) {
1274 g_dbus_connection_signal_unsubscribe(conn,
1275 subscribe_event2_id);
1276 subscribe_event2_id = -1;
1278 if (subscribe_event3_id != -1) {
1279 g_dbus_connection_signal_unsubscribe(conn,
1280 subscribe_event3_id);
1281 subscribe_event3_id = -1;
1283 if (subscribe_event4_id != -1) {
1284 g_dbus_connection_signal_unsubscribe(conn,
1285 subscribe_event4_id);
1286 subscribe_event4_id = -1;
1288 if (subscribe_event5_id != -1) {
1289 g_dbus_connection_signal_unsubscribe(conn,
1290 subscribe_event5_id);
1291 subscribe_event5_id = -1;
1293 if (subscribe_event6_id != -1) {
1294 g_dbus_connection_signal_unsubscribe(conn,
1295 subscribe_event6_id);
1296 subscribe_event6_id = -1;
1298 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1302 BT_EXPORT_API int bluetooth_telephony_init(bt_telephony_func_ptr cb,
1305 bluetooth_device_address_t loc_address = { {0} };
1306 char src_address[BT_ADDRESS_STRING_SIZE] = { 0 };
1307 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1308 GError *error = NULL;
1312 if (is_initialized == TRUE) {
1313 BT_ERR("Bluetooth telephony already initilized");
1314 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_INITIALIZED;
1317 is_initialized = TRUE;
1319 telephony_dbus_info.conn = _bt_gdbus_init_system_gconn();
1320 if (!telephony_dbus_info.conn) {
1321 is_initialized = FALSE;
1322 BT_ERR("Could not get DBus Connection");
1323 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1327 snprintf(telephony_info.call_path, sizeof(telephony_info.call_path),
1328 CSD_CALL_APP_PATH, getpid());
1329 BT_DBG("Call Path = %s", telephony_info.call_path);
1330 memset(telephony_info.address, 0x00, sizeof(telephony_info.address));
1332 if (__bluetooth_telephony_proxy_init()) {
1333 BT_ERR("__bluetooth_telephony_proxy_init failed\n");
1334 telephony_dbus_info.conn = NULL;
1335 is_initialized = FALSE;
1336 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1339 telephony_dbus_info.manager_proxy = g_dbus_proxy_new_sync(
1340 telephony_dbus_info.conn,
1341 G_DBUS_PROXY_FLAGS_NONE, NULL,
1342 BLUEZ_SERVICE_NAME, "/",
1343 BLUEZ_MANAGER_INTERFACE, NULL, &error);
1344 if (telephony_dbus_info.manager_proxy == NULL) {
1345 BT_ERR("Could not create a manager proxy");
1346 __bluetooth_telephony_proxy_deinit();
1347 telephony_dbus_info.conn = NULL;
1348 is_initialized = FALSE;
1350 g_dbus_error_strip_remote_error(error);
1351 ret = __bt_telephony_get_error(error->message);
1352 BT_ERR("Error here %d\n", ret);
1353 g_error_free(error);
1356 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1359 telephony_dbus_info.dbus_proxy = g_dbus_proxy_new_sync(
1360 telephony_dbus_info.conn,
1361 G_DBUS_PROXY_FLAGS_NONE, NULL,
1362 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1363 DBUS_INTERFACE_DBUS, NULL, &error);
1364 if (NULL == telephony_dbus_info.dbus_proxy) {
1365 __bluetooth_telephony_proxy_deinit();
1366 telephony_dbus_info.conn = NULL;
1367 g_object_unref(telephony_dbus_info.manager_proxy);
1368 telephony_dbus_info.manager_proxy = NULL;
1369 is_initialized = FALSE;
1370 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1373 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, TRUE) != 0) {
1374 BT_ERR("Fail to Subscribe Adapter Signal");
1378 /*Callback and user applicaton data*/
1379 telephony_info.cb = cb;
1380 telephony_info.user_data = user_data;
1381 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1383 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, TRUE) != 0) {
1384 BT_ERR("Fail to Subscribe telephony event Signal");
1388 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED)
1389 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1391 /*Bluetooth is active, therefore set the flag */
1394 ret = bluetooth_get_local_address(&loc_address);
1395 if (ret != BLUETOOTH_ERROR_NONE) {
1396 BT_ERR("Fail to get local address\n");
1397 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1400 _bt_convert_addr_type_to_string(src_address, loc_address.addr);
1401 src_addr = g_strdup(src_address);
1403 ret = __bluetooth_telephony_register();
1404 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1405 BT_ERR("__bluetooth_telephony_register failed\n");
1409 #ifndef TIZEN_PROFILE_WEARABLE
1410 __bluetooth_telephony_init_headset_state();
1416 bluetooth_telephony_deinit();
1420 BT_EXPORT_API int bluetooth_telephony_deinit(void)
1423 BT_TELEPHONY_CHECK_INITIALIZED();
1425 is_initialized = FALSE;
1427 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, FALSE) != 0)
1428 BT_ERR("Fail to UnSubscribe telephony event Signal");
1430 if (bluetooth_check_adapter() != BLUETOOTH_ADAPTER_DISABLED ||
1431 bluetooth_check_adapter_le() != BLUETOOTH_ADAPTER_LE_DISABLED)
1432 __bluetooth_telephony_unregister();
1434 __bluetooth_telephony_proxy_deinit();
1436 telephony_info.cb = NULL;
1437 telephony_info.user_data = NULL;
1438 telephony_info.call_count = 0;
1439 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1441 /* Remove BT enabled signal */
1442 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, FALSE) != 0)
1443 BT_ERR("Fail to UnSubscribe Adapter event Signal");
1448 if (telephony_dbus_info.manager_proxy != NULL) {
1449 g_object_unref(telephony_dbus_info.manager_proxy);
1450 telephony_dbus_info.manager_proxy = NULL;
1453 if (telephony_dbus_info.conn != NULL) {
1454 telephony_dbus_info.conn = NULL;
1457 if (telephony_dbus_info.dbus_proxy != NULL) {
1458 g_object_unref(telephony_dbus_info.dbus_proxy);
1459 telephony_dbus_info.dbus_proxy = NULL;
1463 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1466 BT_EXPORT_API gboolean bluetooth_telephony_is_sco_connected(void)
1470 gboolean status = FALSE;
1474 retv_if(is_initialized == FALSE, FALSE);
1475 retv_if(bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED, FALSE);
1477 reply = __bluetooth_telephony_dbus_method_send(
1478 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1479 "IsPlaying", &err, NULL);
1482 BT_ERR("Error returned in method call\n");
1484 BT_ERR("Error message = %s", err->message);
1489 g_variant_get(reply, "(b)", &status);
1490 g_variant_unref(reply);
1492 #ifdef TIZEN_PROFILE_WEARABLE
1493 if (status == TRUE && telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1494 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
1497 BT_INFO("SCO Connected Status = [%d]", status);
1501 BT_EXPORT_API int bluetooth_telephony_is_nrec_enabled(gboolean *status)
1506 GVariant *param_inner;
1510 BT_TELEPHONY_CHECK_INITIALIZED();
1511 BT_TELEPHONY_CHECK_ENABLED();
1514 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1516 if (telephony_info.headset_state == BLUETOOTH_STATE_DISCONNETED)
1517 return BLUETOOTH_TELEPHONY_ERROR_AUDIO_NOT_CONNECTED;
1519 reply = __bluetooth_telephony_dbus_method_send(
1520 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1521 "GetProperties", &err, NULL);
1524 BT_ERR("Error returned in method call\n");
1526 BT_DBG("Error message = %s", err->message);
1529 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1532 g_variant_iter_init(&iter, reply);
1533 while ((param_inner = g_variant_iter_next_value(&iter))) {
1536 value = g_variant_lookup_value(param_inner,
1537 "nrec", G_VARIANT_TYPE_BOOLEAN);
1539 BT_DBG("Property NREC Found");
1540 *status = g_variant_get_boolean(value);
1541 BT_DBG("NREC status = [%d]", *status);
1542 g_variant_unref(value);
1543 g_variant_unref(param_inner);
1546 g_variant_unref(param_inner);
1548 BT_DBG("NREC status = [%d]", *status);
1549 g_variant_unref(reply);
1552 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1555 BT_EXPORT_API int bluetooth_telephony_is_wbs_mode(gboolean *status)
1561 GVariant *param_inner;
1565 BT_TELEPHONY_CHECK_INITIALIZED();
1566 BT_TELEPHONY_CHECK_ENABLED();
1569 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1573 reply = __bluetooth_telephony_dbus_method_send(
1574 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1575 "GetProperties", &err, NULL);
1578 BT_ERR("Error returned in method call");
1580 BT_ERR("Error message = %s", err->message);
1583 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1586 g_variant_iter_init(&iter, reply);
1587 while ((param_inner = g_variant_iter_next_value(&iter))) {
1590 value = g_variant_lookup_value(param_inner,
1591 "codec", G_VARIANT_TYPE_UINT32);
1593 BT_DBG("Property CODEC Found");
1594 codec = g_variant_get_uint32(value);
1595 g_variant_unref(value);
1596 BT_DBG("Codec = [%d]", codec);
1598 *status = codec == BT_MSBC_CODEC_ID ? TRUE : FALSE;
1599 BT_DBG("NREC status = [%d]", *status);
1600 g_variant_unref(value);
1601 g_variant_unref(param_inner);
1604 g_variant_unref(param_inner);
1607 g_variant_unref(reply);
1608 BT_DBG("MSBC status = [%d]", *status);
1611 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1614 BT_EXPORT_API int bluetooth_telephony_send_vendor_cmd(const char *cmd)
1616 GError *error = NULL;
1617 GVariant *reply, *parameters;
1621 BT_TELEPHONY_CHECK_INITIALIZED();
1622 BT_TELEPHONY_CHECK_ENABLED();
1624 BT_DBG("Send Vendor %s", cmd);
1626 if (telephony_dbus_info.proxy == NULL)
1627 telephony_dbus_info.proxy =
1628 __bluetooth_telephony_get_connected_device_proxy();
1630 if (telephony_dbus_info.proxy == NULL)
1631 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1633 parameters = g_variant_new("s", cmd);
1634 reply = g_dbus_proxy_call_sync(telephony_dbus_info.proxy,
1635 "SendVendorAtCmd", parameters,
1636 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1638 g_variant_unref(reply);
1641 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1644 BT_EXPORT_API int bluetooth_telephony_start_voice_recognition(void)
1650 gboolean state = TRUE;
1654 BT_TELEPHONY_CHECK_INITIALIZED();
1655 BT_TELEPHONY_CHECK_ENABLED();
1657 param = g_variant_new("(b)", &state);
1658 reply = __bluetooth_telephony_dbus_method_send(
1659 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1660 "SetVoiceDial", &err, param);
1663 BT_ERR("Error returned in method call\n");
1665 g_dbus_error_strip_remote_error(err);
1666 ret = __bt_telephony_get_error(err->message);
1670 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1673 g_variant_unref(reply);
1675 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1678 BT_EXPORT_API int bluetooth_telephony_stop_voice_recognition(void)
1684 gboolean state = FALSE;
1688 BT_TELEPHONY_CHECK_INITIALIZED();
1689 BT_TELEPHONY_CHECK_ENABLED();
1691 param = g_variant_new("(b)", &state);
1692 reply = __bluetooth_telephony_dbus_method_send(
1693 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1694 "SetVoiceDial", &err, param);
1697 BT_ERR("Error returned in method call\n");
1699 g_dbus_error_strip_remote_error(err);
1700 ret = __bt_telephony_get_error(err->message);
1704 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1707 g_variant_unref(reply);
1710 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1713 static void __bluetooth_telephony_sco_start_cb(GDBusProxy *proxy,
1714 GAsyncResult *res, gpointer user_data)
1716 GError *error = NULL;
1719 value = g_dbus_proxy_call_finish(proxy, res, &error);
1720 if (value == NULL) {
1721 if (error != NULL) {
1722 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1723 error->code, error->message);
1724 g_clear_error(&error);
1726 BT_ERR("SCo Start Failed");
1730 BT_DBG("sco_start_cb : -");
1731 g_object_unref(proxy);
1732 g_variant_unref(value);
1735 BT_EXPORT_API int bluetooth_telephony_audio_open(void)
1737 GDBusConnection *conn;
1744 BT_TELEPHONY_CHECK_INITIALIZED();
1745 BT_TELEPHONY_CHECK_ENABLED();
1747 /* Because this API is async call, so can't use dbus SMACK */
1748 if (__bt_telephony_check_privilege() ==
1749 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1750 BT_ERR("Don't have a privilege to use this API");
1751 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1754 conn = _bt_gdbus_get_system_gconn();
1756 BT_DBG("No System Bus found\n");
1757 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1760 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING)
1761 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
1763 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1764 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1765 HFP_AGENT_INTERFACE, NULL, &err);
1766 if (proxy == NULL) {
1767 BT_ERR("Unable to allocate new proxy");
1769 g_dbus_error_strip_remote_error(err);
1770 ret = __bt_telephony_get_error(err->message);
1771 BT_ERR("Error here %d\n", ret);
1775 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1778 g_dbus_proxy_call(proxy, "Play", NULL, G_DBUS_CALL_FLAGS_NONE,
1779 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_start_cb, NULL);
1782 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1785 static void __bluetooth_telephony_sco_close_cb(GDBusProxy *proxy,
1786 GAsyncResult *res, gpointer user_data)
1788 GError *error = NULL;
1791 value = g_dbus_proxy_call_finish(proxy, res, &error);
1792 if (value == NULL) {
1793 if (error != NULL) {
1794 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1795 error->code, error->message);
1796 g_clear_error(&error);
1798 BT_ERR("SCo close Failed");
1802 BT_DBG("sco_close_cb : -");
1803 g_object_unref(proxy);
1804 g_variant_unref(value);
1806 BT_EXPORT_API int bluetooth_telephony_audio_close(void)
1808 GDBusConnection *conn;
1815 BT_TELEPHONY_CHECK_INITIALIZED();
1816 BT_TELEPHONY_CHECK_ENABLED();
1818 /* Because this API is async call, so can't use dbus SMACK */
1819 if (__bt_telephony_check_privilege() ==
1820 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1821 BT_ERR("Don't have a privilege to use this API");
1822 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1825 conn = _bt_gdbus_get_system_gconn();
1827 BT_DBG("No System Bus found\n");
1828 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1831 if (telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1832 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
1834 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1835 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1836 HFP_AGENT_INTERFACE, NULL, &err);
1837 if (proxy == NULL) {
1838 BT_ERR("Unable to allocate new proxy");
1840 g_dbus_error_strip_remote_error(err);
1841 ret = __bt_telephony_get_error(err->message);
1842 BT_ERR("Error here %d\n", ret);
1846 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1849 g_dbus_proxy_call(proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE,
1850 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_close_cb, NULL);
1852 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
1855 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1858 BT_EXPORT_API int bluetooth_telephony_call_remote_ringing(unsigned int call_id)
1862 BT_TELEPHONY_CHECK_INITIALIZED();
1863 BT_TELEPHONY_CHECK_ENABLED();
1866 BT_DBG("call_id = [%d]", call_id);
1868 /*Make sure SCO is already connected */
1869 ret = __bluetooth_telephony_send_call_status(
1870 CSD_CALL_STATUS_MO_ALERTING, call_id, NULL);
1871 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1872 BT_ERR("send call status Failed = [%d]", ret);
1873 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1876 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1879 BT_EXPORT_API int bluetooth_telephony_call_answered(unsigned int call_id,
1880 unsigned int bt_audio)
1885 BT_DBG("call_id = [%d]", call_id);
1887 BT_TELEPHONY_CHECK_INITIALIZED();
1888 BT_TELEPHONY_CHECK_ENABLED();
1890 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1892 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1893 BT_ERR("send call status Failed = [%d]", ret);
1898 if (!bluetooth_telephony_is_sco_connected()) {
1899 ret = bluetooth_telephony_audio_open();
1901 BT_ERR("Audio connection call Failed[%d]", ret);
1902 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1911 BT_EXPORT_API int bluetooth_telephony_call_end(unsigned int call_id)
1916 BT_DBG("call_id = [%d]", call_id);
1918 BT_TELEPHONY_CHECK_INITIALIZED();
1919 BT_TELEPHONY_CHECK_ENABLED();
1921 if (telephony_info.call_count > 0)
1922 telephony_info.call_count = telephony_info.call_count - 1;
1924 if (telephony_info.call_count == 0) {
1925 if (bluetooth_telephony_is_sco_connected()) {
1926 ret = bluetooth_telephony_audio_close();
1927 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1928 BT_ERR(" Failed = [%d]", ret);
1932 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_MT_RELEASE,
1934 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1935 BT_ERR("send call status Failed = [%d]", ret);
1943 BT_EXPORT_API int bluetooth_telephony_call_held(unsigned int call_id)
1948 BT_DBG("call_id = [%d]", call_id);
1950 BT_TELEPHONY_CHECK_INITIALIZED();
1951 BT_TELEPHONY_CHECK_ENABLED();
1953 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_HOLD,
1955 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1956 BT_ERR("send call status Failed = [%d]", ret);
1962 BT_EXPORT_API int bluetooth_telephony_call_retrieved(unsigned int call_id)
1967 BT_DBG("call_id = [%d]", call_id);
1969 BT_TELEPHONY_CHECK_INITIALIZED();
1970 BT_TELEPHONY_CHECK_ENABLED();
1972 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1974 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1975 BT_ERR("send call status Failed = [%d]", ret);
1981 BT_EXPORT_API int bluetooth_telephony_call_swapped(void *call_list,
1982 unsigned int call_count)
1986 GList *list = call_list;
1987 bt_telephony_call_status_info_t *call_status;
1991 BT_TELEPHONY_CHECK_INITIALIZED();
1992 BT_TELEPHONY_CHECK_ENABLED();
1995 BT_ERR("call_list is invalid");
1996 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1999 /* Because this API is async call, so can't use dbus SMACK */
2000 if (__bt_telephony_check_privilege() ==
2001 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
2002 BT_ERR("Don't have a privilege to use this API");
2003 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
2006 BT_DBG(" call_count = [%d]", call_count);
2008 for (i = 0; i < call_count; i++) {
2009 call_status = g_list_nth_data(list, i);
2011 if (NULL == call_status)
2014 BT_DBG(" %d : Call id [%d] status[%d]", i,
2015 call_status->call_id,
2016 call_status->call_status);
2018 if (NULL != call_status->phone_number)
2019 DBG_SECURE("Number [%s]", call_status->phone_number);
2021 switch (call_status->call_status) {
2022 case BLUETOOTH_CALL_STATE_HELD:
2023 ret = __bluetooth_telephony_send_call_status(
2024 CSD_CALL_STATUS_HOLD,
2025 call_status->call_id,
2026 call_status->phone_number);
2027 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2028 BT_ERR("Failed = %d", ret);
2033 case BLUETOOTH_CALL_STATE_CONNECTED:
2034 ret = __bluetooth_telephony_send_call_status(
2035 CSD_CALL_STATUS_ACTIVE,
2036 call_status->call_id,
2037 call_status->phone_number);
2038 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2039 BT_ERR("Failed = [%d]", ret);
2045 if ((call_status->call_status <
2046 BLUETOOTH_CALL_STATE_NONE) ||
2047 (call_status->call_status >=
2048 BLUETOOTH_CALL_STATE_ERROR)) {
2049 BT_ERR("Unknown Call state");
2050 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
2056 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2059 BT_EXPORT_API int bluetooth_telephony_set_call_status(void *call_list,
2060 unsigned int call_count)
2066 ret = bluetooth_telephony_call_swapped(call_list, call_count);
2068 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2069 BT_ERR("Failed = [%d]", ret);
2073 telephony_info.call_count = call_count;
2076 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2079 BT_EXPORT_API int bluetooth_telephony_indicate_outgoing_call(
2080 const char *ph_number, unsigned int call_id,
2081 unsigned int bt_audio)
2086 const char *path = telephony_info.call_path;
2091 BT_TELEPHONY_CHECK_INITIALIZED();
2092 BT_TELEPHONY_CHECK_ENABLED();
2094 if (NULL == ph_number)
2095 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2097 param = g_variant_new("(ssi)", path, ph_number, call_id);
2098 reply = __bluetooth_telephony_dbus_method_send(
2099 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2100 "OutgoingCall", &err, param);
2103 BT_ERR("Error returned in method call\n");
2105 g_dbus_error_strip_remote_error(err);
2106 ret = __bt_telephony_get_error(err->message);
2110 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2113 g_variant_unref(reply);
2115 telephony_info.call_count++;
2116 BT_DBG(" ag_info.ag_call_count = [%d]", telephony_info.call_count);
2119 if (!bluetooth_telephony_is_sco_connected()) {
2120 ret = bluetooth_telephony_audio_open();
2122 BT_ERR(" Audio connection Failed = %d", ret);
2123 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2129 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2132 BT_EXPORT_API int bluetooth_telephony_indicate_incoming_call(
2133 const char *ph_number, unsigned int call_id)
2138 const char *path = telephony_info.call_path;
2143 BT_TELEPHONY_CHECK_INITIALIZED();
2144 BT_TELEPHONY_CHECK_ENABLED();
2146 if (NULL == ph_number)
2147 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2149 param = g_variant_new("(ssi)", path, ph_number, call_id);
2150 reply = __bluetooth_telephony_dbus_method_send(
2151 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2152 "IncomingCall", &err, param);
2155 BT_ERR("Error returned in method call\n");
2157 g_dbus_error_strip_remote_error(err);
2158 ret = __bt_telephony_get_error(err->message);
2162 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2165 g_variant_unref(reply);
2166 telephony_info.call_count++;
2167 BT_DBG("telephony_info.call_count = [%d]", telephony_info.call_count);
2169 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2172 BT_EXPORT_API int bluetooth_telephony_set_speaker_gain(
2173 unsigned short speaker_gain)
2182 BT_TELEPHONY_CHECK_INITIALIZED();
2183 BT_TELEPHONY_CHECK_ENABLED();
2185 BT_DBG("set speaker_gain= [%d]", speaker_gain);
2187 param = g_variant_new("(q)", speaker_gain);
2188 reply = __bluetooth_telephony_dbus_method_send(
2189 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2190 "SetSpeakerGain", &err, param);
2193 BT_ERR("Error returned in method call\n");
2195 g_dbus_error_strip_remote_error(err);
2196 ret = __bt_telephony_get_error(err->message);
2200 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2203 g_variant_unref(reply);
2205 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2208 BT_EXPORT_API int bluetooth_telephony_get_headset_volume(
2209 unsigned int *speaker_gain)
2218 BT_TELEPHONY_CHECK_INITIALIZED();
2219 BT_TELEPHONY_CHECK_ENABLED();
2221 reply = __bluetooth_telephony_dbus_method_send(
2222 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2223 "GetSpeakerGain", &err, NULL);
2226 BT_ERR("Error returned in method call\n");
2228 g_dbus_error_strip_remote_error(err);
2229 ret = __bt_telephony_get_error(err->message);
2233 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2235 g_variant_get(reply, "(q)", &gain);
2236 *speaker_gain = gain;
2237 BT_DBG("Get speaker_gain= [%d]", *speaker_gain);
2239 g_variant_unref(reply);
2242 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2245 BT_EXPORT_API int bluetooth_telephony_is_connected(gboolean *ag_connected)
2250 gboolean ag_connected_from_bt_agent;
2252 BT_CHECK_ENABLED(return);
2254 reply = __bluetooth_telephony_dbus_method_send(
2255 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2256 "IsConnected", &err, NULL);
2259 BT_ERR("Error returned in method call\n");
2261 g_dbus_error_strip_remote_error(err);
2262 ret = __bt_telephony_get_error(err->message);
2266 return BLUETOOTH_ERROR_INTERNAL;
2268 g_variant_get(reply, "(b)", &ag_connected_from_bt_agent);
2269 *ag_connected = ag_connected_from_bt_agent;
2271 BT_DBG("Conn Status: %s", *ag_connected ? "Connected" : "Disconnected");
2273 g_variant_unref(reply);
2275 return BLUETOOTH_ERROR_NONE;
2278 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
2279 const gchar *sender_name,
2280 const gchar *object_path,
2281 const gchar *interface_name,
2282 const gchar *signal_name,
2283 GVariant *parameters,
2290 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
2291 GVariant *optional_param = NULL;
2293 g_variant_get(parameters, "(&o@a{sa{sv}})",
2294 &path, &optional_param);
2297 BT_ERR("Invalid adapter path");
2301 BT_INFO("Adapter Path = [%s]", path);
2302 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
2303 if (__bt_telephony_get_src_addr(optional_param))
2304 BT_ERR("Fail to get the local adapter address");
2306 ret = __bluetooth_telephony_register();
2307 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
2308 BT_ERR("__bluetooth_telephony_register failed");
2315 static int __bt_telephony_get_src_addr(GVariant *value)
2318 GVariant *param = NULL;
2321 /* signature a{sa{sv}} */
2322 g_variant_iter_init(&iter, value);
2323 while ((param = g_variant_iter_next_value(&iter))) {
2324 char *interface_name;
2325 GVariant *interface_var = NULL;
2326 GVariant *param_inner = NULL;
2328 g_variant_get(param, "{&s*}", &interface_name, &interface_var);
2329 g_variant_unref(param);
2331 BT_DBG("interface_name: %s", interface_name);
2332 /* format of interface_var: a{sv}*/
2333 if (strcasecmp(interface_name, BLUEZ_ADAPTER_INTERFACE) == 0) {
2334 GVariantIter iter_inner;
2336 g_variant_iter_init(&iter_inner, interface_var);
2337 while ((param_inner = g_variant_iter_next_value(&iter_inner))) {
2338 char *property_name;
2339 GVariant *property_var;
2341 g_variant_get(param_inner, "{&sv}",
2344 g_variant_unref(param_inner);
2346 if (strcasecmp(property_name, "Address") == 0) {
2347 const gchar *bd_addr;
2349 bd_addr = g_variant_get_string(
2352 src_addr = g_strdup(bd_addr);
2353 BT_DBG("Address: %s", src_addr);
2355 g_variant_unref(interface_var);
2356 g_variant_unref(property_var);
2359 g_variant_unref(property_var);
2362 g_variant_unref(interface_var);
2366 return BLUETOOTH_ERROR_NONE;