4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Jaganath K <jaganath.k@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
27 #include <dbus/dbus.h>
28 #include <dbus/dbus-glib-bindings.h>
31 #include <vconf-keys.h>
33 #include "bt-common.h"
34 #include "bluetooth-telephony-api.h"
37 #define BT_SCO_TIMEOUT 3000
39 #define BT_CVSD_CODEC_ID 1
40 #define BT_MSBC_CODEC_ID 2
43 GDBusConnection *conn;
45 GDBusProxy *dbus_proxy;
46 GDBusProxy *manager_proxy;
47 } telephony_dbus_info_t;
50 bt_telephony_func_ptr cb;
51 unsigned int call_count;
53 char address[BT_ADDRESS_STR_LEN];
54 char call_path[BT_AUDIO_CALL_PATH_LEN];
55 bluetooth_headset_state_t headset_state;
57 } bt_telephony_info_t;
60 char *src_addr = NULL;
63 #define BLUETOOTH_TELEPHONY_ERROR (__bluetooth_telephony_error_quark())
65 #define BLUEZ_SERVICE_NAME "org.bluez"
66 #define BLUEZ_HEADSET_INTERFACE "org.bluez.Headset"
68 #define BLUEZ_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
69 #define BLUEZ_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
70 #define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
71 #define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
72 #define HFP_AGENT_SERVICE "org.bluez.ag_agent"
75 #define HFP_AGENT_PATH "/org/bluez/hfp_agent"
76 #define HFP_AGENT_INTERFACE "Org.Hfp.App.Interface"
78 #define TELEPHONY_APP_INTERFACE "org.tizen.csd.Call.Instance"
79 #define CSD_CALL_APP_PATH "/org/tizen/csd/%d"
80 #define HFP_NREC_STATUS_CHANGE "NrecStatusChanged"
81 #define HFP_ANSWER_CALL "Answer"
82 #define HFP_REJECT_CALL "Reject"
83 #define HFP_RELEASE_CALL "Release"
84 #define HFP_THREEWAY_CALL "Threeway"
86 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
88 /*Below Inrospection data is exposed to bluez from agent*/
89 static const gchar bt_telephony_introspection_xml[] =
91 " <interface name='org.tizen.csd.Call.Instance'>"
92 " <method name='SendDtmf'>"
93 " <arg type='s' name='dtmf' direction='in'/>"
95 " <method name='VendorCmd'>"
96 " <arg type='s' name='vendor' direction='in'/>"
101 #define BT_TELEPHONY_CHECK_ENABLED() \
103 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED) \
105 BT_ERR("BT is not enabled"); \
106 return BLUETOOTH_TELEPHONY_ERROR_NOT_ENABLED; \
110 static gboolean is_initialized = FALSE;
111 #define BT_TELEPHONY_CHECK_INITIALIZED() \
113 if (is_initialized == FALSE) \
115 BT_ERR("Bluetooth telephony not initilized"); \
116 return BLUETOOTH_TELEPHONY_ERROR_NOT_INITIALIZED; \
120 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
121 const gchar *sender_name,
122 const gchar *object_path,
123 const gchar *interface_name,
124 const gchar *signal_name,
125 GVariant *parameters,
128 static int __bt_telephony_get_src_addr(GVariant *value);
130 static bt_telephony_info_t telephony_info;
131 static telephony_dbus_info_t telephony_dbus_info;
132 static gboolean is_active = FALSE;
134 /*Function Declaration*/
135 static int __bt_telephony_get_error(const char *error_message);
136 static void __bt_telephony_event_cb(int event, int result, void *param_data);
137 static GQuark __bluetooth_telephony_error_quark(void);
138 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
139 const char *interface, const char *method,
140 GError **err, GVariant *parameters);
141 static int __bluetooth_telephony_send_call_status(
142 bt_telephony_call_status_t call_status,
143 unsigned int call_id, const char *ph_number);
144 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
145 bluetooth_telephony_error_t error, const char *err_msg);
147 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
148 const gchar *sender_name,
149 const gchar *object_path,
150 const gchar *interface_name,
151 const gchar *signal_name,
152 GVariant *parameters,
155 static int __bluetooth_telephony_proxy_init(void);
156 static void __bluetooth_telephony_proxy_deinit(void);
157 static int __bluetooth_telephony_register(void);
158 static int __bluetooth_telephony_unregister(void);
160 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class);
161 static int __bluetooth_telephony_get_connected_device(void);
162 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void);
164 /*Function Definition*/
165 static void __bt_telephony_method(GDBusConnection *connection,
167 const gchar *object_path,
168 const gchar *interface_name,
169 const gchar *method_name,
170 GVariant *parameters,
171 GDBusMethodInvocation *invocation,
176 BT_INFO("method %s", method_name);
177 BT_INFO("object_path %s", object_path);
179 if (g_strcmp0(method_name, "SendDtmf") == 0) {
181 telephony_event_dtmf_t call_data = { 0, };
183 g_variant_get(parameters, "(&s)", &dtmf);
186 BT_ERR("Number dial failed");
187 __bluetooth_telephony_error(invocation,
188 BLUETOOTH_TELEPHONY_ERROR_INVALID_DTMF,
191 DBG_SECURE("Dtmf = %s", dtmf);
193 call_data.dtmf = g_strdup(dtmf);
194 __bt_telephony_event_cb(
195 BLUETOOTH_EVENT_TELEPHONY_SEND_DTMF,
196 BLUETOOTH_TELEPHONY_ERROR_NONE,
199 g_free(call_data.dtmf);
201 g_dbus_method_invocation_return_value(invocation, NULL);
203 } else if (g_strcmp0(method_name, "VendorCmd") == 0) {
206 g_variant_get(parameters, "(&s)", &at_cmd);
207 BT_INFO("Vendor %s", at_cmd);
208 if (at_cmd == NULL) {
209 BT_ERR("Vendor command is NULL\n");
210 __bluetooth_telephony_error(invocation,
211 BLUETOOTH_TELEPHONY_ERROR_APPLICATION,
212 "Invalid at vendor cmd");
214 DBG_SECURE("Vendor AT cmd = %s", at_cmd);
216 __bt_telephony_event_cb(
217 BLUETOOTH_EVENT_TELEPHONY_VENDOR_AT_CMD,
218 BLUETOOTH_TELEPHONY_ERROR_NONE,
221 g_dbus_method_invocation_return_value(invocation, NULL);
228 static const GDBusInterfaceVTable method_table = {
229 __bt_telephony_method,
234 static int __bt_telephony_get_error(const char *error_message)
236 if (error_message == NULL) {
237 BT_ERR("Error message NULL");
238 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
241 BT_ERR("Error message = %s", error_message);
242 if (g_strcmp0(error_message, "NotAvailable") == 0)
243 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
244 else if (g_strcmp0(error_message, "NotConnected") == 0)
245 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
246 else if (g_strcmp0(error_message, "InProgress") == 0)
247 return BLUETOOTH_TELEPHONY_ERROR_BUSY;
248 else if (g_strcmp0(error_message, "InvalidArguments") == 0)
249 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
250 else if (g_strcmp0(error_message, "AlreadyExists") == 0)
251 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_EXSIST;
252 else if (g_strcmp0(error_message, "Already Connected") == 0)
253 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
254 else if (g_strcmp0(error_message, "No memory") == 0)
255 return BLUETOOTH_TELEPHONY_ERROR_NO_MEMORY;
256 else if (g_strcmp0(error_message, "I/O error") == 0)
257 return BLUETOOTH_TELEPHONY_ERROR_I_O_ERROR;
258 else if (g_strcmp0(error_message,
259 "Operation currently not available") == 0)
260 return BLUETOOTH_TELEPHONY_ERROR_OPERATION_NOT_AVAILABLE;
261 else if (g_strrstr(error_message, BT_ACCESS_DENIED_MSG))
262 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
264 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
267 static int __bt_telephony_check_privilege(void)
274 reply = __bluetooth_telephony_dbus_method_send(
275 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
276 "CheckPrivilege", &err, NULL);
279 BT_ERR("Error returned in method call");
281 ret = __bt_telephony_get_error(err->message);
285 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
287 g_variant_unref(reply);
290 return BLUETOOTH_TELEPHONY_ERROR_NONE;
293 static void __bt_telephony_event_cb(int event, int result, void *param_data)
295 telephony_event_param_t bt_event = { 0, };
297 bt_event.event = event;
298 bt_event.result = result;
299 bt_event.param_data = param_data;
301 ret_if(telephony_info.cb == NULL);
302 telephony_info.cb(bt_event.event, &bt_event, telephony_info.user_data);
306 static GQuark __bluetooth_telephony_error_quark(void)
308 static GQuark quark = 0;
310 quark = g_quark_from_static_string("telephony");
315 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
316 const char *interface, const char *method,
317 GError **err, GVariant *parameters)
319 #ifdef TIZEN_WEARABLE
326 GDBusConnection *conn;
330 conn = telephony_dbus_info.conn;
331 retv_if(conn == NULL, NULL);
333 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
334 NULL, HFP_AGENT_SERVICE, path, interface, NULL, err);
336 BT_ERR("Unable to allocate new proxy");
340 reply = g_dbus_proxy_call_sync(proxy, method, parameters,
341 G_DBUS_CALL_FLAGS_NONE, timeout, NULL, err);
343 g_object_unref(proxy);
348 static int __bluetooth_telephony_send_call_status(
349 bt_telephony_call_status_t call_status,
350 unsigned int call_id, const char *ph_number)
355 char *path = g_strdup(telephony_info.call_path);
361 if (NULL == ph_number)
362 phone_number = g_strdup("");
364 phone_number = g_strdup(ph_number);
366 param = g_variant_new("(ssii)", path, phone_number,
367 call_status, call_id);
368 reply = __bluetooth_telephony_dbus_method_send(
369 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
370 "ChangeCallStatus", &err, param);
373 g_free(phone_number);
376 BT_ERR("Error returned in method call");
378 ret = __bt_telephony_get_error(err->message);
382 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
385 g_variant_unref(reply);
387 return BLUETOOTH_TELEPHONY_ERROR_NONE;
390 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
391 bluetooth_telephony_error_t error, const char *err_msg)
393 g_dbus_method_invocation_return_error(invocation,
394 BLUETOOTH_TELEPHONY_ERROR, error,
398 static void __bluetooth_telephony_answer_call(GVariant *var)
400 telephony_event_callid_t call_data = { 0, };
405 g_variant_get(var, "(u)", &callid);
406 BT_DBG("call_id = [%d]", callid);
407 call_data.callid = callid;
409 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_ANSWER_CALL,
410 BLUETOOTH_TELEPHONY_ERROR_NONE,
415 static void __bluetooth_telephony_release_call(GVariant *var)
417 telephony_event_callid_t call_data = { 0, };
422 g_variant_get(var, "(u)", &callid);
423 BT_DBG("call_id = [%d]", callid);
424 call_data.callid = callid;
426 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_RELEASE_CALL,
427 BLUETOOTH_TELEPHONY_ERROR_NONE,
432 static void __bluetooth_telephony_reject_call(GVariant *var)
434 telephony_event_callid_t call_data = { 0, };
439 g_variant_get(var, "(u)", &callid);
440 BT_DBG("call_id = [%d]", callid);
441 call_data.callid = callid;
443 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_REJECT_CALL,
444 BLUETOOTH_TELEPHONY_ERROR_NONE,
449 static void __bluetooth_telephony_threeway_call(GVariant *var)
452 unsigned int chld_value;
456 g_variant_get(var, "(u)", &chld_value);
457 BT_DBG("chld value = [%d]", chld_value);
459 switch (chld_value) {
461 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_0_RELEASE_ALL_HELD_CALL;
464 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_1_RELEASE_ALL_ACTIVE_CALL;
467 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_2_ACTIVE_HELD_CALL;
470 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_3_MERGE_CALL;
473 BT_ERR("Invalid CHLD command");
477 __bt_telephony_event_cb(event,
478 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
482 static void __bluetooth_handle_nrec_status_change(GVariant *var)
484 gboolean status = FALSE;
486 g_variant_get(var, "(b)", &status);
487 BT_INFO("NREC status = %d", status);
489 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_NREC_CHANGED,
490 BLUETOOTH_TELEPHONY_ERROR_NONE, (void *)&status);
494 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
495 const gchar *sender_name,
496 const gchar *object_path,
497 const gchar *interface_name,
498 const gchar *signal_name,
499 GVariant *parameters,
504 if (strcasecmp(interface_name, HFP_AGENT_SERVICE) == 0) {
505 if (strcasecmp(signal_name, HFP_NREC_STATUS_CHANGE) == 0)
506 __bluetooth_handle_nrec_status_change(parameters);
507 else if (strcasecmp(signal_name, HFP_ANSWER_CALL) == 0)
508 __bluetooth_telephony_answer_call(parameters);
509 else if (strcasecmp(signal_name, HFP_REJECT_CALL) == 0)
510 __bluetooth_telephony_reject_call(parameters);
511 else if (strcasecmp(signal_name, HFP_RELEASE_CALL) == 0)
512 __bluetooth_telephony_release_call(parameters);
513 else if (strcasecmp(signal_name, HFP_THREEWAY_CALL) == 0)
514 __bluetooth_telephony_threeway_call(parameters);
515 } else if (strcasecmp(interface_name, BLUEZ_HEADSET_INTERFACE) == 0) {
516 if (strcasecmp(signal_name, "PropertyChanged") == 0) {
520 g_variant_get(parameters, "(&sv)", &property, &values);
521 BT_DBG("Property: %s", property);
523 if (strcasecmp(property, "State") == 0) {
525 state = (gchar *)g_variant_get_string(values, NULL);
528 BT_ERR("State is null");
531 BT_DBG("state: %s", state);
532 if (g_strcmp0(state, "connected") == 0) {
533 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
534 } else if (g_strcmp0(state, "playing") == 0) {
535 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
536 } else if (g_strcmp0(state, "disconnected") == 0) {
537 /* Headset state: playing -> disconnected */
538 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING) {
539 __bt_telephony_event_cb(
540 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
541 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
544 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
546 } else if (strcasecmp(property, "Connected") == 0) {
547 gboolean connected = FALSE;
548 char *dev_addr = NULL;
549 connected = g_variant_get_boolean(values);
550 BT_INFO("connected %d", connected);
552 /*Get device address*/
553 if (object_path != NULL)
554 dev_addr = strstr(object_path, "dev_");
556 if (dev_addr != NULL) {
558 g_strlcpy(telephony_info.address,
560 sizeof(telephony_info.address));
561 g_strdelimit(telephony_info.address, "_", ':');
562 BT_DBG("address is %s",
563 telephony_info.address);
565 telephony_info.headset_state =
566 BLUETOOTH_STATE_CONNECTED;
568 if (telephony_dbus_info.proxy != NULL) {
569 g_object_unref(telephony_dbus_info.proxy);
570 telephony_dbus_info.proxy = NULL;
573 telephony_dbus_info.proxy =
574 __bluetooth_telephony_get_connected_device_proxy();
576 BT_INFO("Headset Connected");
578 __bt_telephony_event_cb(
579 BLUETOOTH_EVENT_TELEPHONY_HFP_CONNECTED,
580 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
582 } else { /*Device disconnected*/
583 memset(telephony_info.address, 0x00,
584 sizeof(telephony_info.address));
585 telephony_info.headset_state =
586 BLUETOOTH_STATE_DISCONNETED;
588 if (telephony_dbus_info.proxy != NULL) {
589 g_object_unref(telephony_dbus_info.proxy);
590 telephony_dbus_info.proxy = NULL;
593 BT_INFO("Headset Disconnected");
595 __bt_telephony_event_cb(
596 BLUETOOTH_EVENT_TELEPHONY_HFP_DISCONNECTED,
597 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
599 } else if (strcasecmp(property, "SpeakerGain") == 0) {
600 unsigned int spkr_gain;
601 guint16 gain = g_variant_get_uint16(values);
603 spkr_gain = (unsigned int)gain;
604 BT_DBG("spk_gain[%d]", spkr_gain);
606 __bt_telephony_event_cb(
607 BLUETOOTH_EVENT_TELEPHONY_SET_SPEAKER_GAIN,
608 BLUETOOTH_TELEPHONY_ERROR_NONE,
610 } else if (strcasecmp(property, "MicrophoneGain") == 0) {
611 unsigned int mic_gain;
612 guint16 gain = g_variant_get_uint16(values);
614 mic_gain = (unsigned int)gain;
615 BT_DBG("mic_gain[%d]", mic_gain);
617 __bt_telephony_event_cb(
618 BLUETOOTH_EVENT_TELEPHONY_SET_MIC_GAIN,
619 BLUETOOTH_TELEPHONY_ERROR_NONE,
621 } else if (strcasecmp(property, "Playing") == 0) {
622 gboolean audio_sink_playing;
624 audio_sink_playing = g_variant_get_boolean(values);
625 if (audio_sink_playing) {
626 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
627 __bt_telephony_event_cb(
628 BLUETOOTH_EVENT_TELEPHONY_AUDIO_CONNECTED,
629 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
631 telephony_info.headset_state =
632 BLUETOOTH_STATE_CONNECTED;
633 __bt_telephony_event_cb(
634 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
635 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
639 g_variant_unref(values);
645 static GDBusNodeInfo *__bt_telephony_create_method_node_info
646 (const gchar *introspection_data)
649 GDBusNodeInfo *node_info = NULL;
651 if (introspection_data == NULL)
654 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
657 BT_ERR("Unable to create node: %s", err->message);
664 int __bluetooth_telephony_register_object(int reg, GDBusNodeInfo *node_info)
666 static guint bt_tel_id = 0;
667 GError *error = NULL;
671 if (node_info == NULL)
672 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
674 path = g_strdup(telephony_info.call_path);
675 BT_DBG("path is [%s]", path);
677 bt_tel_id = g_dbus_connection_register_object(telephony_dbus_info.conn,
678 path, node_info->interfaces[0],
683 if (bt_tel_id == 0) {
684 BT_ERR("Failed to register: %s", error->message);
686 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
690 g_dbus_connection_unregister_object(telephony_dbus_info.conn,
696 return BLUETOOTH_TELEPHONY_ERROR_NONE;
699 static int __bluetooth_telephony_proxy_init(void)
703 GDBusNodeInfo *node_info;
705 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
706 TELEPHONY_APP_INTERFACE,
707 G_BUS_NAME_OWNER_FLAGS_NONE,
710 BT_DBG("owner_id is [%d]", owner_id);
712 node_info = __bt_telephony_create_method_node_info(
713 bt_telephony_introspection_xml);
715 if (node_info == NULL) {
716 BT_ERR("node_info NULL");
717 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
719 if (__bluetooth_telephony_register_object(TRUE, node_info) !=
720 BLUETOOTH_TELEPHONY_ERROR_NONE) {
721 BT_ERR("Registation of Method Failed");
722 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
726 return BLUETOOTH_TELEPHONY_ERROR_NONE;
729 static void __bluetooth_telephony_proxy_deinit(void)
733 __bluetooth_telephony_register_object(FALSE, NULL);
739 static int __bluetooth_telephony_register(void)
744 char *path = g_strdup(telephony_info.call_path);
749 param = g_variant_new("(ss)", path, src_addr);
750 BT_DBG("Path[%s] Src_Address[%s]", path, src_addr);
752 reply = __bluetooth_telephony_dbus_method_send(
753 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
754 "RegisterApplication", &err, param);
759 BT_ERR("Error returned in method call");
761 ret = __bt_telephony_get_error(err->message);
762 BT_ERR("Error here %d\n", ret);
766 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
769 g_variant_unref(reply);
770 BT_DBG("__bluetooth_telephony_register completed");
772 return BLUETOOTH_TELEPHONY_ERROR_NONE;
775 static int __bluetooth_telephony_unregister(void)
780 char *path = g_strdup(telephony_info.call_path);
785 param = g_variant_new("(s)", path);
786 reply = __bluetooth_telephony_dbus_method_send(
787 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
788 "UnregisterApplication", &err, param);
793 BT_ERR("Error returned in method call");
795 ret = __bt_telephony_get_error(err->message);
799 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
802 g_variant_unref(reply);
803 BT_DBG("__bluetooth_telephony_unregister completed");
805 return BLUETOOTH_TELEPHONY_ERROR_NONE;
808 #ifndef TIZEN_WEARABLE
809 static void __bluetooth_telephony_init_headset_state(void)
813 gboolean status = FALSE;
817 if (telephony_dbus_info.conn == NULL) {
818 BT_ERR("Bluetooth telephony not initilized");
822 reply = __bluetooth_telephony_dbus_method_send(
823 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
824 "IsConnected", &err, NULL);
826 BT_ERR("Error returned in method call\n");
828 __bt_telephony_get_error(err->message);
834 g_variant_get(reply, "(b)", &status);
835 g_variant_unref(reply);
837 BT_INFO("Headset Connected Status = [%d]", status);
839 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
843 if (bluetooth_telephony_is_sco_connected())
844 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
850 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class)
852 gboolean flag = FALSE;
855 switch ((device_class & 0x1f00) >> 8) {
857 switch ((device_class & 0xfc) >> 2) {
875 /* Tizen Wearable device */
877 switch ((device_class & 0xfc) >> 2) {
878 case 0x01: /* Wrist Watch */
886 BT_DBG("[%d]", flag);
891 static gboolean __bluetooth_telephony_is_headset_by_uuid(gchar **uuids)
895 unsigned int service = 0;
899 retv_if(uuids == NULL, FALSE);
901 for (i = 0; uuids[i] != NULL; i++) {
902 parts = g_strsplit(uuids[i], "-", -1);
904 if (parts == NULL || parts[0] == NULL) {
909 service = g_ascii_strtoull(parts[0], NULL, 16);
912 if (service == BLUETOOTH_HS_PROFILE_UUID ||
913 service == BLUETOOTH_HF_PROFILE_UUID)
922 static int __bluetooth_telephony_get_connected_device(void)
924 GDBusConnection *conn;
925 GDBusProxy *headset_agent_proxy = NULL;
926 GDBusProxy *manager_proxy = NULL;
927 GDBusProxy *proxy = NULL;
928 GVariant *reply = NULL;
929 GVariant *getall = NULL;
930 GVariant *isPlayingReply = NULL;
931 GVariant *isConnectedReply = NULL;
932 GVariant *param = NULL;
933 GVariant *var_path = NULL;
934 GVariant *path_values = NULL;
935 GVariant *value = NULL;
936 GError *error = NULL;
938 GVariantIter iter_path;
939 GVariantIter property_iter;
940 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
943 conn = _bt_gdbus_get_system_gconn();
944 retv_if(conn == NULL, BLUETOOTH_TELEPHONY_ERROR_INTERNAL);
946 manager_proxy = g_dbus_proxy_new_sync(
947 conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
948 BLUEZ_SERVICE_NAME, "/",
949 BLUEZ_MANAGER_INTERFACE, NULL, &error);
950 if (manager_proxy == NULL) {
951 BT_ERR("Unable to allocate new proxy \n");
952 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
954 ret = __bt_telephony_get_error(error->message);
955 BT_ERR("Error here %d\n", ret);
961 /* Synchronous call */
962 reply = g_dbus_proxy_call_sync(manager_proxy, "GetManagedObjects", NULL,
963 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
964 g_object_unref(manager_proxy);
967 BT_ERR("Can't get managed objects");
968 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
970 ret = __bt_telephony_get_error(error->message);
971 BT_ERR("Error here %d\n", ret);
977 /* signature of GetManagedObjects: a{oa{sa{sv}}} */
978 g_variant_iter_init(&iter, reply);
980 while ((param = g_variant_iter_next_value(&iter))) {
981 g_variant_iter_init(&iter_path, param);
983 while ((var_path = g_variant_iter_next_value(&iter_path))) {
985 uint32_t device_class = 0;
986 gboolean playing = FALSE;
987 gboolean connected = FALSE;
988 char *object_path = NULL;
989 gchar *address = NULL;
991 gchar **uuids = NULL;
992 GVariant *getall_param = NULL;
994 g_variant_get(var_path, "{&o*}", &object_path,
996 g_variant_unref(path_values); /* path_values unused*/
998 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
999 G_DBUS_PROXY_FLAGS_NONE, NULL,
1000 BLUEZ_SERVICE_NAME, object_path,
1001 BLUEZ_PROPERTIES_INTERFACE, NULL, &error);
1002 if (proxy == NULL) {
1003 BT_ERR("Unable to allocate new proxy \n");
1004 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
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 ret = __bt_telephony_get_error(error->message);
1025 BT_ERR("Error here %d\n", ret);
1026 g_error_free(error);
1031 g_variant_iter_init(&property_iter, getall);
1033 while (g_variant_iter_loop(&property_iter, "{&sv}", &key, &value)) {
1034 if (!g_strcmp0(key, "Class")) {
1035 device_class = g_variant_get_uint32(value);
1036 BT_DBG("Device Class: %d", device_class);
1037 } else if (!g_strcmp0(key, "UUID")) {
1039 uuids = (gchar **)g_variant_get_strv(value, &len);
1040 BT_DBG_UUID(uuids, len, i);
1041 } else if (!g_strcmp0(key, "Address")) {
1042 address = (gchar *)g_variant_get_string(
1045 BT_DBG("Device Class: %s", address);
1047 g_variant_unref(value);
1049 g_variant_unref(getall);
1051 if (device_class == 0) {
1052 BT_DBG("COD is NULL (maybe paired by nfc)... Checking UUIDs");
1053 if (!__bluetooth_telephony_is_headset_by_uuid(uuids)) {
1054 BT_DBG("UUID checking completed. None HF device");
1057 BT_DBG("UUID checking completed. HF device");
1059 if (!__bluetooth_telephony_is_headset(device_class))
1063 /* this is headset; Check for Connection */
1064 headset_agent_proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1065 G_DBUS_PROXY_FLAGS_NONE, NULL,
1066 HFP_AGENT_SERVICE, object_path,
1067 HFP_AGENT_INTERFACE, NULL, &error);
1068 if (headset_agent_proxy == NULL) {
1069 BT_ERR("Unable to allocate new headset_agent_proxy");
1070 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
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 ret = __bt_telephony_get_error(error->message);
1089 BT_ERR("Error here %d\n", ret);
1090 g_error_free(error);
1094 connected = g_variant_get_boolean(isConnectedReply);
1095 g_variant_unref(isConnectedReply);
1098 g_strlcpy(telephony_info.address,
1100 sizeof(telephony_info.address));
1102 isPlayingReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1104 G_DBUS_CALL_FLAGS_NONE,
1106 if (!isPlayingReply) {
1107 BT_ERR("Can't get managed objects");
1108 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1110 ret = __bt_telephony_get_error(error->message);
1111 BT_ERR("Error here %d\n", ret);
1112 g_error_free(error);
1115 playing = g_variant_get_boolean(isPlayingReply);
1116 g_variant_unref(isPlayingReply);
1119 telephony_info.headset_state =
1120 BLUETOOTH_STATE_PLAYING;
1122 telephony_info.headset_state =
1123 BLUETOOTH_STATE_CONNECTED;
1130 g_object_unref(headset_agent_proxy);
1131 g_variant_unref(var_path);
1133 g_variant_unref(param);
1137 if (headset_agent_proxy)
1138 g_object_unref(headset_agent_proxy);
1140 g_variant_unref(reply);
1142 g_variant_unref(var_path);
1144 g_variant_unref(param);
1149 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void)
1151 GDBusProxy *proxy = NULL;
1152 GError *error = NULL;
1156 if (strlen(telephony_info.address) == 0)
1157 __bluetooth_telephony_get_connected_device();
1159 if (strlen(telephony_info.address) == 0)
1162 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1163 G_DBUS_PROXY_FLAGS_NONE, NULL,
1164 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1165 HFP_AGENT_INTERFACE, NULL, &error);
1166 if (proxy == NULL) {
1167 BT_ERR("Unable to allocate new proxy");
1169 ret = __bt_telephony_get_error(error->message);
1170 BT_ERR("Error here %d\n", ret);
1171 g_error_free(error);
1180 int __bt_telephony_subscribe_adapter_signal(GDBusConnection *conn,
1186 static int subscribe_adapter_id = -1;
1187 if (subscribe == TRUE) {
1188 if (subscribe_adapter_id == -1) {
1189 subscribe_adapter_id = g_dbus_connection_signal_subscribe(conn,
1190 NULL, "org.freedesktop.DBus.ObjectManager",
1191 "InterfacesAdded", NULL, NULL, 0,
1192 __bt_telephony_adapter_filter,
1195 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1197 if (subscribe_adapter_id != -1) {
1198 g_dbus_connection_signal_unsubscribe(conn,
1199 subscribe_adapter_id);
1200 subscribe_adapter_id = -1;
1202 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1206 int __bt_telephony_event_subscribe_signal(GDBusConnection *conn,
1212 static int subscribe_event1_id = -1;
1213 static int subscribe_event2_id = -1;
1214 static int subscribe_event3_id = -1;
1215 static int subscribe_event4_id = -1;
1216 static int subscribe_event5_id = -1;
1217 static int subscribe_event6_id = -1;
1218 if (subscribe == TRUE) {
1219 if (subscribe_event1_id == -1) {
1220 subscribe_event1_id = g_dbus_connection_signal_subscribe(conn,
1221 NULL, BLUEZ_HEADSET_INTERFACE,
1222 "PropertyChanged", NULL, NULL, 0,
1223 __bluetooth_telephony_event_filter,
1226 if (subscribe_event2_id == -1) {
1227 subscribe_event2_id = g_dbus_connection_signal_subscribe(conn,
1228 NULL, HFP_AGENT_SERVICE,
1229 HFP_NREC_STATUS_CHANGE, NULL, NULL, 0,
1230 __bluetooth_telephony_event_filter,
1234 if (subscribe_event3_id == -1) {
1235 subscribe_event3_id = g_dbus_connection_signal_subscribe(conn,
1236 NULL, HFP_AGENT_SERVICE,
1237 HFP_ANSWER_CALL, NULL, NULL, 0,
1238 __bluetooth_telephony_event_filter,
1241 if (subscribe_event4_id == -1) {
1242 subscribe_event4_id = g_dbus_connection_signal_subscribe(conn,
1243 NULL, HFP_AGENT_SERVICE,
1244 HFP_REJECT_CALL, NULL, NULL, 0,
1245 __bluetooth_telephony_event_filter,
1248 if (subscribe_event5_id == -1) {
1249 subscribe_event5_id = g_dbus_connection_signal_subscribe(conn,
1250 NULL, HFP_AGENT_SERVICE,
1251 HFP_RELEASE_CALL, NULL, NULL, 0,
1252 __bluetooth_telephony_event_filter,
1255 if (subscribe_event6_id == -1) {
1256 subscribe_event6_id = g_dbus_connection_signal_subscribe(conn,
1257 NULL, HFP_AGENT_SERVICE,
1258 HFP_THREEWAY_CALL, NULL, NULL, 0,
1259 __bluetooth_telephony_event_filter,
1263 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1265 if (subscribe_event1_id != -1) {
1266 g_dbus_connection_signal_unsubscribe(conn,
1267 subscribe_event1_id);
1268 subscribe_event1_id = -1;
1270 if (subscribe_event2_id != -1) {
1271 g_dbus_connection_signal_unsubscribe(conn,
1272 subscribe_event2_id);
1273 subscribe_event2_id = -1;
1275 if (subscribe_event3_id != -1) {
1276 g_dbus_connection_signal_unsubscribe(conn,
1277 subscribe_event3_id);
1278 subscribe_event3_id = -1;
1280 if (subscribe_event4_id != -1) {
1281 g_dbus_connection_signal_unsubscribe(conn,
1282 subscribe_event4_id);
1283 subscribe_event4_id = -1;
1285 if (subscribe_event5_id != -1) {
1286 g_dbus_connection_signal_unsubscribe(conn,
1287 subscribe_event5_id);
1288 subscribe_event5_id = -1;
1290 if (subscribe_event6_id != -1) {
1291 g_dbus_connection_signal_unsubscribe(conn,
1292 subscribe_event6_id);
1293 subscribe_event6_id = -1;
1295 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1299 BT_EXPORT_API int bluetooth_telephony_init(bt_telephony_func_ptr cb,
1302 bluetooth_device_address_t loc_address = { {0} };
1303 char src_address[BT_ADDRESS_STRING_SIZE] = { 0 };
1304 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1305 GError *error = NULL;
1309 if (is_initialized == TRUE) {
1310 BT_ERR("Bluetooth telephony already initilized");
1311 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_INITIALIZED;
1314 is_initialized = TRUE;
1316 telephony_dbus_info.conn = _bt_gdbus_init_system_gconn();
1317 if (!telephony_dbus_info.conn) {
1318 is_initialized = FALSE;
1319 BT_ERR("Could not get DBus Connection");
1320 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1324 snprintf(telephony_info.call_path, sizeof(telephony_info.call_path),
1325 CSD_CALL_APP_PATH, getpid());
1326 BT_DBG("Call Path = %s", telephony_info.call_path);
1327 memset(telephony_info.address, 0x00, sizeof(telephony_info.address));
1329 if (__bluetooth_telephony_proxy_init()) {
1330 BT_ERR("__bluetooth_telephony_proxy_init failed\n");
1331 telephony_dbus_info.conn = NULL;
1332 is_initialized = FALSE;
1333 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1336 telephony_dbus_info.manager_proxy = g_dbus_proxy_new_sync(
1337 telephony_dbus_info.conn,
1338 G_DBUS_PROXY_FLAGS_NONE, NULL,
1339 BLUEZ_SERVICE_NAME, "/",
1340 BLUEZ_MANAGER_INTERFACE, NULL, &error);
1341 if (telephony_dbus_info.manager_proxy == NULL) {
1342 BT_ERR("Could not create a manager proxy");
1343 __bluetooth_telephony_proxy_deinit();
1344 telephony_dbus_info.conn = NULL;
1345 is_initialized = FALSE;
1347 ret = __bt_telephony_get_error(error->message);
1348 BT_ERR("Error here %d\n", ret);
1349 g_error_free(error);
1352 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1355 telephony_dbus_info.dbus_proxy = g_dbus_proxy_new_sync(
1356 telephony_dbus_info.conn,
1357 G_DBUS_PROXY_FLAGS_NONE, NULL,
1358 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1359 DBUS_INTERFACE_DBUS, NULL, &error);
1360 if (NULL == telephony_dbus_info.dbus_proxy) {
1361 __bluetooth_telephony_proxy_deinit();
1362 telephony_dbus_info.conn = NULL;
1363 g_object_unref(telephony_dbus_info.manager_proxy);
1364 telephony_dbus_info.manager_proxy = NULL;
1365 is_initialized = FALSE;
1366 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1369 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, TRUE) != 0) {
1370 BT_ERR("Fail to Subscribe Adapter Signal");
1374 /*Callback and user applicaton data*/
1375 telephony_info.cb = cb;
1376 telephony_info.user_data = user_data;
1377 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1379 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, TRUE) != 0) {
1380 BT_ERR("Fail to Subscribe telephony event Signal");
1384 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED)
1385 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1387 /*Bluetooth is active, therefore set the flag */
1390 ret = bluetooth_get_local_address(&loc_address);
1391 if (ret != BLUETOOTH_ERROR_NONE) {
1392 BT_ERR("Fail to get local address\n");
1393 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1396 _bt_convert_addr_type_to_string(src_address, loc_address.addr);
1397 src_addr = g_strdup(src_address);
1399 ret = __bluetooth_telephony_register();
1400 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1401 BT_ERR("__bluetooth_telephony_register failed\n");
1405 #ifndef TIZEN_WEARABLE
1406 __bluetooth_telephony_init_headset_state();
1412 bluetooth_telephony_deinit();
1416 BT_EXPORT_API int bluetooth_telephony_deinit(void)
1419 BT_TELEPHONY_CHECK_INITIALIZED();
1421 is_initialized = FALSE;
1423 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, FALSE) != 0)
1424 BT_ERR("Fail to UnSubscribe telephony event Signal");
1426 if (bluetooth_check_adapter() != BLUETOOTH_ADAPTER_DISABLED ||
1427 bluetooth_check_adapter_le() != BLUETOOTH_ADAPTER_LE_DISABLED)
1428 __bluetooth_telephony_unregister();
1430 __bluetooth_telephony_proxy_deinit();
1432 telephony_info.cb = NULL;
1433 telephony_info.user_data = NULL;
1434 telephony_info.call_count = 0;
1435 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1437 /* Remove BT enabled signal */
1438 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, FALSE) != 0)
1439 BT_ERR("Fail to UnSubscribe Adapter event Signal");
1444 if (telephony_dbus_info.manager_proxy != NULL) {
1445 g_object_unref(telephony_dbus_info.manager_proxy);
1446 telephony_dbus_info.manager_proxy = NULL;
1449 if (telephony_dbus_info.conn != NULL) {
1450 telephony_dbus_info.conn = NULL;
1453 if (telephony_dbus_info.dbus_proxy != NULL) {
1454 g_object_unref(telephony_dbus_info.dbus_proxy);
1455 telephony_dbus_info.dbus_proxy = NULL;
1459 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1462 BT_EXPORT_API gboolean bluetooth_telephony_is_sco_connected(void)
1466 gboolean status = FALSE;
1470 retv_if(is_initialized == FALSE, FALSE);
1471 retv_if(bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED, FALSE);
1473 reply = __bluetooth_telephony_dbus_method_send(
1474 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1475 "IsPlaying", &err, NULL);
1478 BT_ERR("Error returned in method call\n");
1480 __bt_telephony_get_error(err->message);
1485 g_variant_get(reply, "(b)", &status);
1486 g_variant_unref(reply);
1488 #ifdef TIZEN_WEARABLE
1489 if (status == TRUE && telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1490 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
1493 BT_INFO("SCO Connected Status = [%d]", status);
1497 BT_EXPORT_API int bluetooth_telephony_is_nrec_enabled(gboolean *status)
1502 GVariant *param_inner;
1506 BT_TELEPHONY_CHECK_INITIALIZED();
1507 BT_TELEPHONY_CHECK_ENABLED();
1510 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1512 if (telephony_info.headset_state == BLUETOOTH_STATE_DISCONNETED)
1513 return BLUETOOTH_TELEPHONY_ERROR_AUDIO_NOT_CONNECTED;
1515 reply = __bluetooth_telephony_dbus_method_send(
1516 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1517 "GetProperties", &err, NULL);
1520 BT_ERR("Error returned in method call\n");
1522 BT_DBG("Error message = %s", err->message);
1525 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1528 g_variant_iter_init(&iter, reply);
1529 while ((param_inner = g_variant_iter_next_value(&iter))) {
1532 value = g_variant_lookup_value(param_inner,
1533 "nrec", G_VARIANT_TYPE_BOOLEAN);
1535 BT_DBG("Property NREC Found");
1536 *status = g_variant_get_boolean(value);
1537 BT_DBG("NREC status = [%d]", *status);
1538 g_variant_unref(value);
1539 g_variant_unref(param_inner);
1542 g_variant_unref(param_inner);
1544 BT_DBG("NREC status = [%d]", *status);
1545 g_variant_unref(reply);
1548 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1551 BT_EXPORT_API int bluetooth_telephony_is_wbs_mode(gboolean *status)
1557 GVariant *param_inner;
1561 BT_TELEPHONY_CHECK_INITIALIZED();
1562 BT_TELEPHONY_CHECK_ENABLED();
1565 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1569 reply = __bluetooth_telephony_dbus_method_send(
1570 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1571 "GetProperties", &err, NULL);
1574 BT_ERR("Error returned in method call");
1576 BT_ERR("Error message = %s", err->message);
1579 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1582 g_variant_iter_init(&iter, reply);
1583 while ((param_inner = g_variant_iter_next_value(&iter))) {
1586 value = g_variant_lookup_value(param_inner,
1587 "codec", G_VARIANT_TYPE_UINT32);
1589 BT_DBG("Property CODEC Found");
1590 codec = g_variant_get_uint32(value);
1591 g_variant_unref(value);
1592 BT_DBG("Codec = [%d]", codec);
1594 *status = codec == BT_MSBC_CODEC_ID ? TRUE : FALSE;
1595 BT_DBG("NREC status = [%d]", *status);
1596 g_variant_unref(value);
1597 g_variant_unref(param_inner);
1600 g_variant_unref(param_inner);
1603 g_variant_unref(reply);
1604 BT_DBG("MSBC status = [%d]", *status);
1607 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1610 BT_EXPORT_API int bluetooth_telephony_send_vendor_cmd(const char *cmd)
1612 GError *error = NULL;
1613 GVariant *reply, *parameters;
1617 BT_TELEPHONY_CHECK_INITIALIZED();
1618 BT_TELEPHONY_CHECK_ENABLED();
1620 BT_DBG("Send Vendor %s", cmd);
1622 if (telephony_dbus_info.proxy == NULL)
1623 telephony_dbus_info.proxy =
1624 __bluetooth_telephony_get_connected_device_proxy();
1626 if (telephony_dbus_info.proxy == NULL)
1627 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1629 parameters = g_variant_new("s", cmd);
1630 reply = g_dbus_proxy_call_sync(telephony_dbus_info.proxy,
1631 "SendVendorAtCmd", parameters,
1632 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1634 g_variant_unref(reply);
1637 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1640 BT_EXPORT_API int bluetooth_telephony_start_voice_recognition(void)
1646 gboolean state = TRUE;
1650 BT_TELEPHONY_CHECK_INITIALIZED();
1651 BT_TELEPHONY_CHECK_ENABLED();
1653 param = g_variant_new("(b)", &state);
1654 reply = __bluetooth_telephony_dbus_method_send(
1655 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1656 "SetVoiceDial", &err, param);
1659 BT_ERR("Error returned in method call\n");
1661 ret = __bt_telephony_get_error(err->message);
1665 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1668 g_variant_unref(reply);
1670 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1673 BT_EXPORT_API int bluetooth_telephony_stop_voice_recognition(void)
1679 gboolean state = FALSE;
1683 BT_TELEPHONY_CHECK_INITIALIZED();
1684 BT_TELEPHONY_CHECK_ENABLED();
1686 param = g_variant_new("(b)", &state);
1687 reply = __bluetooth_telephony_dbus_method_send(
1688 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1689 "SetVoiceDial", &err, param);
1692 BT_ERR("Error returned in method call\n");
1694 ret = __bt_telephony_get_error(err->message);
1698 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1701 g_variant_unref(reply);
1704 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1707 static void __bluetooth_telephony_sco_start_cb(GDBusProxy *proxy,
1708 GAsyncResult *res, gpointer user_data)
1710 GError *error = NULL;
1713 value = g_dbus_proxy_call_finish(proxy, res, &error);
1714 if (value == NULL) {
1715 if (error != NULL) {
1716 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1717 error->code, error->message);
1718 g_clear_error(&error);
1720 BT_ERR("SCo Start Failed");
1724 BT_DBG("sco_start_cb : -");
1725 g_object_unref(proxy);
1726 g_variant_unref(value);
1729 BT_EXPORT_API int bluetooth_telephony_audio_open(void)
1731 GDBusConnection *conn;
1738 BT_TELEPHONY_CHECK_INITIALIZED();
1739 BT_TELEPHONY_CHECK_ENABLED();
1741 /* Because this API is async call, so can't use dbus SMACK */
1742 if (__bt_telephony_check_privilege() ==
1743 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1744 BT_ERR("Don't have a privilege to use this API");
1745 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1748 conn = _bt_gdbus_get_system_gconn();
1750 BT_DBG("No System Bus found\n");
1751 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1754 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING)
1755 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
1757 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1758 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1759 HFP_AGENT_INTERFACE, NULL, &err);
1760 if (proxy == NULL) {
1761 BT_ERR("Unable to allocate new proxy");
1763 ret = __bt_telephony_get_error(err->message);
1764 BT_ERR("Error here %d\n", ret);
1768 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1771 g_dbus_proxy_call(proxy, "Play", NULL, G_DBUS_CALL_FLAGS_NONE,
1772 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_start_cb, NULL);
1775 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1778 static void __bluetooth_telephony_sco_close_cb(GDBusProxy *proxy,
1779 GAsyncResult *res, gpointer user_data)
1781 GError *error = NULL;
1784 value = g_dbus_proxy_call_finish(proxy, res, &error);
1785 if (value == NULL) {
1786 if (error != NULL) {
1787 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1788 error->code, error->message);
1789 g_clear_error(&error);
1791 BT_ERR("SCo close Failed");
1795 BT_DBG("sco_close_cb : -");
1796 g_object_unref(proxy);
1797 g_variant_unref(value);
1799 BT_EXPORT_API int bluetooth_telephony_audio_close(void)
1801 GDBusConnection *conn;
1808 BT_TELEPHONY_CHECK_INITIALIZED();
1809 BT_TELEPHONY_CHECK_ENABLED();
1811 /* Because this API is async call, so can't use dbus SMACK */
1812 if (__bt_telephony_check_privilege() ==
1813 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1814 BT_ERR("Don't have a privilege to use this API");
1815 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1818 conn = _bt_gdbus_get_system_gconn();
1820 BT_DBG("No System Bus found\n");
1821 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1824 if (telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1825 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
1827 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1828 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1829 HFP_AGENT_INTERFACE, NULL, &err);
1830 if (proxy == NULL) {
1831 BT_ERR("Unable to allocate new proxy");
1833 ret = __bt_telephony_get_error(err->message);
1834 BT_ERR("Error here %d\n", ret);
1838 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1841 g_dbus_proxy_call(proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE,
1842 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_close_cb, NULL);
1844 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
1847 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1850 BT_EXPORT_API int bluetooth_telephony_call_remote_ringing(unsigned int call_id)
1854 BT_TELEPHONY_CHECK_INITIALIZED();
1855 BT_TELEPHONY_CHECK_ENABLED();
1858 BT_DBG("call_id = [%d]", call_id);
1860 /*Make sure SCO is already connected */
1861 ret = __bluetooth_telephony_send_call_status(
1862 CSD_CALL_STATUS_MO_ALERTING, call_id, NULL);
1863 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1864 BT_ERR("send call status Failed = [%d]", ret);
1865 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1868 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1871 BT_EXPORT_API int bluetooth_telephony_call_answered(unsigned int call_id,
1872 unsigned int bt_audio)
1877 BT_DBG("call_id = [%d]", call_id);
1879 BT_TELEPHONY_CHECK_INITIALIZED();
1880 BT_TELEPHONY_CHECK_ENABLED();
1882 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1884 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1885 BT_ERR("send call status Failed = [%d]", ret);
1890 if (!bluetooth_telephony_is_sco_connected()) {
1891 ret = bluetooth_telephony_audio_open();
1893 BT_ERR("Audio connection call Failed[%d]", ret);
1894 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1903 BT_EXPORT_API int bluetooth_telephony_call_end(unsigned int call_id)
1908 BT_DBG("call_id = [%d]", call_id);
1910 BT_TELEPHONY_CHECK_INITIALIZED();
1911 BT_TELEPHONY_CHECK_ENABLED();
1913 if (telephony_info.call_count > 0)
1914 telephony_info.call_count = telephony_info.call_count - 1;
1916 if (telephony_info.call_count == 0) {
1917 if (bluetooth_telephony_is_sco_connected()) {
1918 ret = bluetooth_telephony_audio_close();
1919 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1920 BT_ERR(" Failed = [%d]", ret);
1924 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_MT_RELEASE,
1926 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1927 BT_ERR("send call status Failed = [%d]", ret);
1935 BT_EXPORT_API int bluetooth_telephony_call_held(unsigned int call_id)
1940 BT_DBG("call_id = [%d]", call_id);
1942 BT_TELEPHONY_CHECK_INITIALIZED();
1943 BT_TELEPHONY_CHECK_ENABLED();
1945 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_HOLD,
1947 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1948 BT_ERR("send call status Failed = [%d]", ret);
1954 BT_EXPORT_API int bluetooth_telephony_call_retrieved(unsigned int call_id)
1959 BT_DBG("call_id = [%d]", call_id);
1961 BT_TELEPHONY_CHECK_INITIALIZED();
1962 BT_TELEPHONY_CHECK_ENABLED();
1964 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1966 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1967 BT_ERR("send call status Failed = [%d]", ret);
1973 BT_EXPORT_API int bluetooth_telephony_call_swapped(void *call_list,
1974 unsigned int call_count)
1978 GList *list = call_list;
1979 bt_telephony_call_status_info_t *call_status;
1983 BT_TELEPHONY_CHECK_INITIALIZED();
1984 BT_TELEPHONY_CHECK_ENABLED();
1987 BT_ERR("call_list is invalid");
1988 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1991 /* Because this API is async call, so can't use dbus SMACK */
1992 if (__bt_telephony_check_privilege() ==
1993 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1994 BT_ERR("Don't have a privilege to use this API");
1995 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1998 BT_DBG(" call_count = [%d]", call_count);
2000 for (i = 0; i < call_count; i++) {
2001 call_status = g_list_nth_data(list, i);
2003 if (NULL == call_status)
2006 BT_DBG(" %d : Call id [%d] status[%d]", i,
2007 call_status->call_id,
2008 call_status->call_status);
2010 if (NULL != call_status->phone_number)
2011 DBG_SECURE("Number [%s]", call_status->phone_number);
2013 switch (call_status->call_status) {
2014 case BLUETOOTH_CALL_STATE_HELD:
2015 ret = __bluetooth_telephony_send_call_status(
2016 CSD_CALL_STATUS_HOLD,
2017 call_status->call_id,
2018 call_status->phone_number);
2019 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2020 BT_ERR("Failed = %d", ret);
2025 case BLUETOOTH_CALL_STATE_CONNECTED:
2026 ret = __bluetooth_telephony_send_call_status(
2027 CSD_CALL_STATUS_ACTIVE,
2028 call_status->call_id,
2029 call_status->phone_number);
2030 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2031 BT_ERR("Failed = [%d]", ret);
2037 if ((call_status->call_status <
2038 BLUETOOTH_CALL_STATE_NONE) ||
2039 (call_status->call_status >=
2040 BLUETOOTH_CALL_STATE_ERROR)) {
2041 BT_ERR("Unknown Call state");
2042 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
2048 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2051 BT_EXPORT_API int bluetooth_telephony_set_call_status(void *call_list,
2052 unsigned int call_count)
2058 ret = bluetooth_telephony_call_swapped(call_list, call_count);
2060 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2061 BT_ERR("Failed = [%d]", ret);
2065 telephony_info.call_count = call_count;
2068 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2071 BT_EXPORT_API int bluetooth_telephony_indicate_outgoing_call(
2072 const char *ph_number, unsigned int call_id,
2073 unsigned int bt_audio)
2078 const char *path = telephony_info.call_path;
2083 BT_TELEPHONY_CHECK_INITIALIZED();
2084 BT_TELEPHONY_CHECK_ENABLED();
2086 if (NULL == ph_number)
2087 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2089 param = g_variant_new("(ssi)", path, ph_number, call_id);
2090 reply = __bluetooth_telephony_dbus_method_send(
2091 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2092 "OutgoingCall", &err, param);
2095 BT_ERR("Error returned in method call\n");
2097 ret = __bt_telephony_get_error(err->message);
2101 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2104 g_variant_unref(reply);
2106 telephony_info.call_count++;
2107 BT_DBG(" ag_info.ag_call_count = [%d]", telephony_info.call_count);
2110 if (!bluetooth_telephony_is_sco_connected()) {
2111 ret = bluetooth_telephony_audio_open();
2113 BT_ERR(" Audio connection Failed = %d", ret);
2114 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2120 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2123 BT_EXPORT_API int bluetooth_telephony_indicate_incoming_call(
2124 const char *ph_number, unsigned int call_id)
2129 const char *path = telephony_info.call_path;
2134 BT_TELEPHONY_CHECK_INITIALIZED();
2135 BT_TELEPHONY_CHECK_ENABLED();
2137 if (NULL == ph_number)
2138 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2140 param = g_variant_new("(ssi)", path, ph_number, call_id);
2141 reply = __bluetooth_telephony_dbus_method_send(
2142 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2143 "IncomingCall", &err, param);
2146 BT_ERR("Error returned in method call\n");
2148 ret = __bt_telephony_get_error(err->message);
2152 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2155 g_variant_unref(reply);
2156 telephony_info.call_count++;
2157 BT_DBG("telephony_info.call_count = [%d]", telephony_info.call_count);
2159 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2162 BT_EXPORT_API int bluetooth_telephony_set_speaker_gain(
2163 unsigned short speaker_gain)
2172 BT_TELEPHONY_CHECK_INITIALIZED();
2173 BT_TELEPHONY_CHECK_ENABLED();
2175 BT_DBG("set speaker_gain= [%d]", speaker_gain);
2177 param = g_variant_new("(q)", speaker_gain);
2178 reply = __bluetooth_telephony_dbus_method_send(
2179 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2180 "SetSpeakerGain", &err, param);
2183 BT_ERR("Error returned in method call\n");
2185 ret = __bt_telephony_get_error(err->message);
2189 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2192 g_variant_unref(reply);
2194 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2197 BT_EXPORT_API int bluetooth_telephony_get_headset_volume(
2198 unsigned int *speaker_gain)
2207 BT_TELEPHONY_CHECK_INITIALIZED();
2208 BT_TELEPHONY_CHECK_ENABLED();
2210 reply = __bluetooth_telephony_dbus_method_send(
2211 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2212 "GetSpeakerGain", &err, NULL);
2215 BT_ERR("Error returned in method call\n");
2217 ret = __bt_telephony_get_error(err->message);
2221 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2223 g_variant_get(reply, "(q)", &gain);
2224 *speaker_gain = gain;
2225 BT_DBG("Get speaker_gain= [%d]", *speaker_gain);
2227 g_variant_unref(reply);
2230 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2233 BT_EXPORT_API int bluetooth_telephony_is_connected(gboolean *ag_connected)
2238 gboolean ag_connected_from_bt_agent;
2240 BT_CHECK_ENABLED(return);
2242 reply = __bluetooth_telephony_dbus_method_send(
2243 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2244 "IsConnected", &err, NULL);
2247 BT_ERR("Error returned in method call\n");
2249 ret = __bt_telephony_get_error(err->message);
2253 return BLUETOOTH_ERROR_INTERNAL;
2255 g_variant_get(reply, "(b)", &ag_connected_from_bt_agent);
2256 *ag_connected = ag_connected_from_bt_agent;
2258 BT_DBG("Conn Status: %s", *ag_connected ? "Connected" : "Disconnected");
2260 g_variant_unref(reply);
2262 return BLUETOOTH_ERROR_NONE;
2265 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
2266 const gchar *sender_name,
2267 const gchar *object_path,
2268 const gchar *interface_name,
2269 const gchar *signal_name,
2270 GVariant *parameters,
2277 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
2278 GVariant *optional_param = NULL;
2280 g_variant_get(parameters, "(&o@a{sa{sv}})",
2281 &path, &optional_param);
2284 BT_ERR("Invalid adapter path");
2288 BT_INFO("Adapter Path = [%s]", path);
2289 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
2290 if (__bt_telephony_get_src_addr(optional_param))
2291 BT_ERR("Fail to get the local adapter address");
2293 ret = __bluetooth_telephony_register();
2294 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
2295 BT_ERR("__bluetooth_telephony_register failed");
2302 static int __bt_telephony_get_src_addr(GVariant *value)
2305 GVariant *param = NULL;
2308 /* signature a{sa{sv}} */
2309 g_variant_iter_init(&iter, value);
2310 while ((param = g_variant_iter_next_value(&iter))) {
2311 char *interface_name;
2312 GVariant *interface_var = NULL;
2313 GVariant *param_inner = NULL;
2315 g_variant_get(param, "{&s*}", &interface_name, &interface_var);
2316 g_variant_unref(param);
2318 BT_DBG("interface_name: %s", interface_name);
2319 /* format of interface_var: a{sv}*/
2320 if (strcasecmp(interface_name, BLUEZ_ADAPTER_INTERFACE) == 0) {
2321 GVariantIter iter_inner;
2323 g_variant_iter_init(&iter_inner, interface_var);
2324 while ((param_inner = g_variant_iter_next_value(&iter_inner))) {
2325 char *property_name;
2326 GVariant *property_var;
2328 g_variant_get(param_inner, "{&sv}",
2331 g_variant_unref(param_inner);
2333 if (strcasecmp(property_name, "Address") == 0) {
2334 const gchar *bd_addr;
2336 bd_addr = g_variant_get_string(
2339 src_addr = g_strdup(bd_addr);
2340 BT_DBG("Address: %s", src_addr);
2342 g_variant_unref(interface_var);
2343 g_variant_unref(property_var);
2346 g_variant_unref(property_var);
2349 g_variant_unref(interface_var);
2353 return BLUETOOTH_ERROR_NONE;