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.
23 #include <vconf-keys.h>
25 #include "bt-common.h"
26 #include "bluetooth-telephony-api.h"
27 #include "bt-internal-types.h"
29 #define BT_SCO_TIMEOUT 3000
31 #define BT_CVSD_CODEC_ID 1
32 #define BT_MSBC_CODEC_ID 2
35 GDBusConnection *conn;
37 GDBusProxy *dbus_proxy;
38 GDBusProxy *manager_proxy;
39 } telephony_dbus_info_t;
42 bt_telephony_func_ptr cb;
43 unsigned int call_count;
45 char address[BT_ADDRESS_STR_LEN];
46 char call_path[BT_AUDIO_CALL_PATH_LEN];
47 bluetooth_headset_state_t headset_state;
49 } bt_telephony_info_t;
52 static char *src_addr = NULL;
53 static guint owner_id = 0;
55 #define BLUETOOTH_TELEPHONY_ERROR (__bluetooth_telephony_error_quark())
57 #define BLUEZ_SERVICE_NAME "org.bluez"
58 #define BLUEZ_HEADSET_INTERFACE "org.bluez.Headset"
60 #define BLUEZ_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
61 #define BLUEZ_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
62 #define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
63 #define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
64 #define HFP_AGENT_SERVICE "org.bluez.ag_agent"
67 #define HFP_AGENT_PATH "/org/bluez/hfp_agent"
68 #define HFP_AGENT_INTERFACE "Org.Hfp.App.Interface"
70 #define CSD_CALL_APP_PATH "/org/tizen/csd/%d"
71 #define HFP_NREC_STATUS_CHANGE "NrecStatusChanged"
72 #define HFP_ANSWER_CALL "Answer"
73 #define HFP_REJECT_CALL "Reject"
74 #define HFP_RELEASE_CALL "Release"
75 #define HFP_THREEWAY_CALL "Threeway"
76 #define HFP_HF_BATTERY_LEVEL_CHANGE "HfBatteryLevelChanged"
78 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
80 /*Below Inrospection data is exposed to bluez from agent*/
81 static const gchar bt_telephony_introspection_xml[] =
83 " <interface name='org.tizen.csd.Call.Instance'>"
84 " <method name='SendDtmf'>"
85 " <arg type='s' name='dtmf' direction='in'/>"
87 " <method name='VendorCmd'>"
88 " <arg type='s' name='vendor' direction='in'/>"
93 #define BT_TELEPHONY_CHECK_ENABLED() \
95 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED) { \
96 BT_ERR("BT is not enabled"); \
97 return BLUETOOTH_TELEPHONY_ERROR_NOT_ENABLED; \
101 static gboolean is_initialized = FALSE;
102 #define BT_TELEPHONY_CHECK_INITIALIZED() \
104 if (is_initialized == FALSE) { \
105 BT_ERR("Bluetooth telephony not initilized"); \
106 return BLUETOOTH_TELEPHONY_ERROR_NOT_INITIALIZED; \
110 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
111 const gchar *sender_name,
112 const gchar *object_path,
113 const gchar *interface_name,
114 const gchar *signal_name,
115 GVariant *parameters,
118 static int __bt_telephony_get_src_addr(GVariant *value);
120 static bt_telephony_info_t telephony_info;
121 static telephony_dbus_info_t telephony_dbus_info;
122 static gboolean is_active = FALSE;
124 /*Function Declaration*/
125 static int __bt_telephony_get_error(const char *error_message);
126 static void __bt_telephony_event_cb(int event, int result, void *param_data);
127 static GQuark __bluetooth_telephony_error_quark(void);
128 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
129 const char *interface, const char *method,
130 GError **err, GVariant *parameters);
131 static int __bluetooth_telephony_send_call_status(
132 bt_telephony_call_status_t call_status,
133 unsigned int call_id, const char *ph_number);
134 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
135 bluetooth_telephony_error_t error, const char *err_msg);
137 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
138 const gchar *sender_name,
139 const gchar *object_path,
140 const gchar *interface_name,
141 const gchar *signal_name,
142 GVariant *parameters,
145 static int __bluetooth_telephony_register(void);
146 static int __bluetooth_telephony_unregister(void);
148 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class);
149 static int __bluetooth_telephony_get_connected_device(void);
150 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void);
152 /*Function Definition*/
153 static void __bt_telephony_method(GDBusConnection *connection,
155 const gchar *object_path,
156 const gchar *interface_name,
157 const gchar *method_name,
158 GVariant *parameters,
159 GDBusMethodInvocation *invocation,
164 BT_INFO("method %s", method_name);
165 BT_INFO("object_path %s", object_path);
167 if (g_strcmp0(method_name, "SendDtmf") == 0) {
169 telephony_event_dtmf_t call_data = { 0, };
171 g_variant_get(parameters, "(&s)", &dtmf);
174 BT_ERR("Number dial failed");
175 __bluetooth_telephony_error(invocation,
176 BLUETOOTH_TELEPHONY_ERROR_INVALID_DTMF,
179 DBG_SECURE("Dtmf = %s", dtmf);
181 call_data.dtmf = g_strdup(dtmf);
182 __bt_telephony_event_cb(
183 BLUETOOTH_EVENT_TELEPHONY_SEND_DTMF,
184 BLUETOOTH_TELEPHONY_ERROR_NONE,
187 g_free(call_data.dtmf);
189 g_dbus_method_invocation_return_value(invocation, NULL);
191 } else if (g_strcmp0(method_name, "VendorCmd") == 0) {
194 g_variant_get(parameters, "(&s)", &at_cmd);
195 BT_INFO("Vendor %s", at_cmd);
196 if (at_cmd == NULL) {
197 BT_ERR("Vendor command is NULL\n");
198 __bluetooth_telephony_error(invocation,
199 BLUETOOTH_TELEPHONY_ERROR_APPLICATION,
200 "Invalid at vendor cmd");
202 DBG_SECURE("Vendor AT cmd = %s", at_cmd);
204 __bt_telephony_event_cb(
205 BLUETOOTH_EVENT_TELEPHONY_VENDOR_AT_CMD,
206 BLUETOOTH_TELEPHONY_ERROR_NONE,
209 g_dbus_method_invocation_return_value(invocation, NULL);
216 static const GDBusInterfaceVTable method_table = {
217 __bt_telephony_method,
222 static int __bt_telephony_get_error(const char *error_message)
224 if (error_message == NULL) {
225 BT_ERR("Error message NULL");
226 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
229 BT_ERR("Error message = %s", error_message);
230 if (g_strcmp0(error_message, "NotAvailable") == 0)
231 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
232 else if (g_strcmp0(error_message, "NotConnected") == 0)
233 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
234 else if (g_strcmp0(error_message, "InProgress") == 0)
235 return BLUETOOTH_TELEPHONY_ERROR_BUSY;
236 else if (g_strcmp0(error_message, "InvalidArguments") == 0)
237 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
238 else if (g_strcmp0(error_message, "AlreadyExists") == 0)
239 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_EXSIST;
240 else if (g_strcmp0(error_message, "Already Connected") == 0)
241 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
242 else if (g_strcmp0(error_message, "No memory") == 0)
243 return BLUETOOTH_TELEPHONY_ERROR_NO_MEMORY;
244 else if (g_strcmp0(error_message, "I/O error") == 0)
245 return BLUETOOTH_TELEPHONY_ERROR_I_O_ERROR;
246 else if (g_strcmp0(error_message,
247 "Operation currently not available") == 0)
248 return BLUETOOTH_TELEPHONY_ERROR_OPERATION_NOT_AVAILABLE;
249 else if (g_strrstr(error_message, BT_ACCESS_DENIED_MSG))
250 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
252 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
255 static int __bt_telephony_check_privilege(void)
262 reply = __bluetooth_telephony_dbus_method_send(
263 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
264 "CheckPrivilege", &err, NULL);
267 BT_ERR("Error returned in method call");
269 g_dbus_error_strip_remote_error(err);
270 ret = __bt_telephony_get_error(err->message);
274 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
276 g_variant_unref(reply);
279 return BLUETOOTH_TELEPHONY_ERROR_NONE;
282 static void __bt_telephony_event_cb(int event, int result, void *param_data)
284 telephony_event_param_t bt_event = { 0, };
286 bt_event.event = event;
287 bt_event.result = result;
288 bt_event.param_data = param_data;
290 ret_if(telephony_info.cb == NULL);
291 telephony_info.cb(bt_event.event, &bt_event, telephony_info.user_data);
295 static GQuark __bluetooth_telephony_error_quark(void)
297 static GQuark quark = 0;
299 quark = g_quark_from_static_string("telephony");
304 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
305 const char *interface, const char *method,
306 GError **err, GVariant *parameters)
310 if (TIZEN_PROFILE_WEARABLE || TIZEN_PROFILE_IVI)
315 GDBusConnection *conn;
319 conn = telephony_dbus_info.conn;
320 retv_if(conn == NULL, NULL);
322 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
323 NULL, HFP_AGENT_SERVICE, path, interface, NULL, err);
325 BT_ERR("Unable to allocate new proxy");
329 reply = g_dbus_proxy_call_sync(proxy, method, parameters,
330 G_DBUS_CALL_FLAGS_NONE, timeout, NULL, err);
332 g_object_unref(proxy);
337 static int __bluetooth_telephony_send_call_status(
338 bt_telephony_call_status_t call_status,
339 unsigned int call_id, const char *ph_number)
344 char *path = g_strdup(telephony_info.call_path);
350 if (NULL == ph_number)
351 phone_number = g_strdup("");
353 phone_number = g_strdup(ph_number);
355 param = g_variant_new("(ssii)", path, phone_number,
356 call_status, call_id);
357 reply = __bluetooth_telephony_dbus_method_send(
358 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
359 "ChangeCallStatus", &err, param);
362 g_free(phone_number);
365 BT_ERR("Error returned in method call");
367 g_dbus_error_strip_remote_error(err);
368 ret = __bt_telephony_get_error(err->message);
372 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
375 g_variant_unref(reply);
377 return BLUETOOTH_TELEPHONY_ERROR_NONE;
380 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
381 bluetooth_telephony_error_t error, const char *err_msg)
383 g_dbus_method_invocation_return_error(invocation,
384 BLUETOOTH_TELEPHONY_ERROR, error,
388 static void __bluetooth_telephony_answer_call(GVariant *var)
390 telephony_event_callid_t call_data = { 0, };
395 g_variant_get(var, "(u)", &callid);
396 BT_DBG("call_id = [%d]", callid);
397 call_data.callid = callid;
399 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_ANSWER_CALL,
400 BLUETOOTH_TELEPHONY_ERROR_NONE,
405 static void __bluetooth_telephony_release_call(GVariant *var)
407 telephony_event_callid_t call_data = { 0, };
412 g_variant_get(var, "(u)", &callid);
413 BT_DBG("call_id = [%d]", callid);
414 call_data.callid = callid;
416 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_RELEASE_CALL,
417 BLUETOOTH_TELEPHONY_ERROR_NONE,
422 static void __bluetooth_telephony_reject_call(GVariant *var)
424 telephony_event_callid_t call_data = { 0, };
429 g_variant_get(var, "(u)", &callid);
430 BT_DBG("call_id = [%d]", callid);
431 call_data.callid = callid;
433 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_REJECT_CALL,
434 BLUETOOTH_TELEPHONY_ERROR_NONE,
439 static void __bluetooth_telephony_threeway_call(GVariant *var)
442 unsigned int chld_value;
446 g_variant_get(var, "(u)", &chld_value);
447 BT_DBG("chld value = [%d]", chld_value);
449 switch (chld_value) {
451 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_0_RELEASE_ALL_HELD_CALL;
454 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_1_RELEASE_ALL_ACTIVE_CALL;
457 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_2_ACTIVE_HELD_CALL;
460 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_3_MERGE_CALL;
463 BT_ERR("Invalid CHLD command");
467 __bt_telephony_event_cb(event,
468 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
472 static void __bluetooth_handle_nrec_status_change(GVariant *var)
474 gboolean status = FALSE;
476 g_variant_get(var, "(b)", &status);
477 BT_INFO("NREC status = %d", status);
479 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_NREC_CHANGED,
480 BLUETOOTH_TELEPHONY_ERROR_NONE, (void *)&status);
484 static void __bluetooth_telephony_hf_battery_level_change(GVariant *var)
486 telephony_event_hf_battery_level_t param;
487 char secure_address[BT_ADDRESS_STRING_SIZE] = { 0 };
489 g_variant_get(var, "(&su)", ¶m.remote_address, ¶m.battery_level);
491 _bt_convert_addr_string_to_secure_string(secure_address, param.remote_address);
492 BT_INFO("address(%s) battery level(%u)", secure_address, param.battery_level);
494 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_HF_BATTERY_LEVEL_CHANGED,
495 BLUETOOTH_TELEPHONY_ERROR_NONE, (void *)¶m);
498 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
499 const gchar *sender_name,
500 const gchar *object_path,
501 const gchar *interface_name,
502 const gchar *signal_name,
503 GVariant *parameters,
508 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);
633 } else if (strcasecmp(signal_name, HFP_NREC_STATUS_CHANGE) == 0)
634 __bluetooth_handle_nrec_status_change(parameters);
635 else if (strcasecmp(signal_name, HFP_ANSWER_CALL) == 0)
636 __bluetooth_telephony_answer_call(parameters);
637 else if (strcasecmp(signal_name, HFP_REJECT_CALL) == 0)
638 __bluetooth_telephony_reject_call(parameters);
639 else if (strcasecmp(signal_name, HFP_RELEASE_CALL) == 0)
640 __bluetooth_telephony_release_call(parameters);
641 else if (strcasecmp(signal_name, HFP_THREEWAY_CALL) == 0)
642 __bluetooth_telephony_threeway_call(parameters);
643 else if (strcasecmp(signal_name, HFP_HF_BATTERY_LEVEL_CHANGE) == 0)
644 __bluetooth_telephony_hf_battery_level_change(parameters);
649 static GDBusNodeInfo *__bt_telephony_create_method_node_info
650 (const gchar *introspection_data)
653 GDBusNodeInfo *node_info = NULL;
655 if (introspection_data == NULL)
658 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
661 BT_ERR("Unable to create node: %s", err->message);
668 int __bluetooth_telephony_register_object(int reg, GDBusNodeInfo *node_info)
670 static guint bt_tel_id = 0;
671 GError *error = NULL;
675 if (node_info == NULL)
676 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
678 path = g_strdup(telephony_info.call_path);
680 bt_tel_id = g_dbus_connection_register_object(telephony_dbus_info.conn,
681 path, node_info->interfaces[0],
686 if (bt_tel_id == 0) {
687 BT_ERR("Failed to register: %s", error->message);
689 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
693 g_dbus_connection_unregister_object(telephony_dbus_info.conn,
699 return BLUETOOTH_TELEPHONY_ERROR_NONE;
702 static int __bluetooth_telephony_proxy_init(void)
705 GDBusNodeInfo *node_info;
708 name = g_strdup_printf("org.tizen.csd.Call.Instance.p%d", getpid());
710 owner_id = g_bus_own_name_on_connection(telephony_dbus_info.conn,
711 name, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL);
712 BT_DBG("well-known name: %s, owner_id: %d", name, owner_id);
715 node_info = __bt_telephony_create_method_node_info(
716 bt_telephony_introspection_xml);
717 if (node_info == NULL) {
718 BT_ERR("node_info NULL");
719 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
721 if (__bluetooth_telephony_register_object(TRUE, node_info) !=
722 BLUETOOTH_TELEPHONY_ERROR_NONE) {
723 BT_ERR("Registation of Method Failed");
724 g_dbus_node_info_unref(node_info);
725 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
729 g_dbus_node_info_unref(node_info);
730 return BLUETOOTH_TELEPHONY_ERROR_NONE;
733 static void __bluetooth_telephony_proxy_deinit(void)
737 __bluetooth_telephony_register_object(FALSE, NULL);
738 g_bus_unown_name(owner_id);
743 static int __bluetooth_telephony_register(void)
748 char *path = g_strdup(telephony_info.call_path);
753 param = g_variant_new("(ss)", path, src_addr);
754 BT_DBG("Path[%s] Src_Address[%s]", path, src_addr);
756 reply = __bluetooth_telephony_dbus_method_send(
757 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
758 "RegisterApplication", &err, param);
763 BT_ERR("Error returned in method call");
765 g_dbus_error_strip_remote_error(err);
766 ret = __bt_telephony_get_error(err->message);
767 BT_ERR("Error here %d\n", ret);
771 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
774 g_variant_unref(reply);
775 BT_DBG("__bluetooth_telephony_register completed");
777 return BLUETOOTH_TELEPHONY_ERROR_NONE;
780 static int __bluetooth_telephony_unregister(void)
785 char *path = g_strdup(telephony_info.call_path);
790 param = g_variant_new("(s)", path);
791 reply = __bluetooth_telephony_dbus_method_send(
792 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
793 "UnregisterApplication", &err, param);
798 BT_ERR("Error returned in method call");
800 g_dbus_error_strip_remote_error(err);
801 ret = __bt_telephony_get_error(err->message);
805 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
808 g_variant_unref(reply);
809 BT_DBG("__bluetooth_telephony_unregister completed");
811 return BLUETOOTH_TELEPHONY_ERROR_NONE;
814 static void __bluetooth_telephony_init_headset_state(void)
818 gboolean status = FALSE;
822 if (telephony_dbus_info.conn == NULL) {
823 BT_ERR("Bluetooth telephony not initilized");
827 reply = __bluetooth_telephony_dbus_method_send(
828 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
829 "IsConnected", &err, NULL);
831 BT_ERR("Error returned in method call\n");
833 BT_ERR("Error message = %s", err->message);
839 g_variant_get(reply, "(b)", &status);
840 g_variant_unref(reply);
842 BT_INFO("Headset Connected Status = [%d]", status);
844 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
848 if (bluetooth_telephony_is_sco_connected())
849 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
854 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class)
856 gboolean flag = FALSE;
859 switch ((device_class & 0x1f00) >> 8) {
861 switch ((device_class & 0xfc) >> 2) {
879 /* Tizen Wearable device */
881 switch ((device_class & 0xfc) >> 2) {
882 case 0x01: /* Wrist Watch */
890 BT_DBG("[%d]", flag);
895 static gboolean __bluetooth_telephony_is_headset_by_uuid(gchar **uuids)
899 unsigned int service = 0;
903 retv_if(uuids == NULL, FALSE);
905 for (i = 0; uuids[i] != NULL; i++) {
906 parts = g_strsplit(uuids[i], "-", -1);
908 if (parts == NULL || parts[0] == NULL) {
913 service = g_ascii_strtoull(parts[0], NULL, 16);
916 if (service == BLUETOOTH_HS_PROFILE_UUID ||
917 service == BLUETOOTH_HF_PROFILE_UUID)
926 static int __bluetooth_telephony_get_connected_device(void)
928 GDBusConnection *conn;
929 GDBusProxy *headset_agent_proxy = NULL;
930 GDBusProxy *manager_proxy = NULL;
931 GDBusProxy *proxy = NULL;
932 GVariant *reply = NULL;
933 GVariant *getall = NULL;
934 GVariant *isPlayingReply = NULL;
935 GVariant *isConnectedReply = NULL;
936 GVariant *param = NULL;
937 GVariant *var_path = NULL;
938 GVariant *path_values = NULL;
939 GVariant *value = NULL;
940 GError *error = NULL;
942 GVariantIter iter_path;
943 GVariantIter property_iter;
944 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
947 conn = _bt_get_system_private_conn();
948 retv_if(conn == NULL, BLUETOOTH_TELEPHONY_ERROR_INTERNAL);
950 manager_proxy = g_dbus_proxy_new_sync(
951 conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
952 BLUEZ_SERVICE_NAME, "/",
953 BLUEZ_MANAGER_INTERFACE, NULL, &error);
954 if (manager_proxy == NULL) {
955 BT_ERR("Unable to allocate new proxy \n");
956 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
958 g_dbus_error_strip_remote_error(error);
959 ret = __bt_telephony_get_error(error->message);
960 BT_ERR("Error here %d\n", ret);
966 /* Synchronous call */
967 reply = g_dbus_proxy_call_sync(manager_proxy, "GetManagedObjects", NULL,
968 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
969 g_object_unref(manager_proxy);
972 BT_ERR("Can't get managed objects");
973 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
975 g_dbus_error_strip_remote_error(error);
976 ret = __bt_telephony_get_error(error->message);
977 BT_ERR("Error here %d\n", ret);
983 /* signature of GetManagedObjects: a{oa{sa{sv}}} */
984 g_variant_iter_init(&iter, reply);
986 while ((param = g_variant_iter_next_value(&iter))) {
987 g_variant_iter_init(&iter_path, param);
989 while ((var_path = g_variant_iter_next_value(&iter_path))) {
991 uint32_t device_class = 0;
992 gboolean playing = FALSE;
993 gboolean connected = FALSE;
994 char *object_path = NULL;
995 gchar *address = NULL;
997 gchar **uuids = NULL;
998 GVariant *getall_param = NULL;
1000 g_variant_get(var_path, "{&o*}", &object_path,
1002 g_variant_unref(path_values); /* path_values unused*/
1004 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1005 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1006 BLUEZ_SERVICE_NAME, object_path,
1007 BLUEZ_PROPERTIES_INTERFACE, NULL, &error);
1008 if (proxy == NULL) {
1009 BT_ERR("Unable to allocate new proxy \n");
1010 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1012 g_dbus_error_strip_remote_error(error);
1013 ret = __bt_telephony_get_error(error->message);
1014 BT_ERR("Error here %d\n", ret);
1015 g_error_free(error);
1021 getall_param = g_variant_new("s", BLUEZ_DEVICE_INTERFACE);
1022 getall = g_dbus_proxy_call_sync(proxy,
1023 "GetAll", getall_param,
1024 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1025 g_object_unref(proxy);
1028 BT_ERR("Can't get managed objects");
1029 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1031 g_dbus_error_strip_remote_error(error);
1032 ret = __bt_telephony_get_error(error->message);
1033 BT_ERR("Error here %d\n", ret);
1034 g_error_free(error);
1039 g_variant_iter_init(&property_iter, getall);
1041 while (g_variant_iter_loop(&property_iter, "{&sv}", &key, &value)) {
1042 if (!g_strcmp0(key, "Class")) {
1043 device_class = g_variant_get_uint32(value);
1044 BT_DBG("Device Class: %d", device_class);
1045 } else if (!g_strcmp0(key, "UUID")) {
1047 uuids = (gchar **)g_variant_get_strv(value, &len);
1048 BT_DBG_UUID(uuids, len, i);
1049 } else if (!g_strcmp0(key, "Address")) {
1050 address = (gchar *)g_variant_get_string(
1053 BT_DBG("Device Class: %s", address);
1055 g_variant_unref(value);
1057 g_variant_unref(getall);
1059 if (device_class == 0) {
1060 BT_DBG("COD is NULL (maybe paired by nfc)... Checking UUIDs");
1061 if (!__bluetooth_telephony_is_headset_by_uuid(uuids)) {
1062 BT_DBG("UUID checking completed. None HF device");
1065 BT_DBG("UUID checking completed. HF device");
1067 if (!__bluetooth_telephony_is_headset(device_class))
1071 /* this is headset; Check for Connection */
1072 headset_agent_proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1073 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1074 HFP_AGENT_SERVICE, object_path,
1075 HFP_AGENT_INTERFACE, NULL, &error);
1076 if (headset_agent_proxy == NULL) {
1077 BT_ERR("Unable to allocate new headset_agent_proxy");
1078 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1080 g_dbus_error_strip_remote_error(error);
1081 ret = __bt_telephony_get_error(error->message);
1082 BT_ERR("Error here %d\n", ret);
1083 g_error_free(error);
1088 isConnectedReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1089 "IsConnected", NULL,
1090 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1093 if (!isConnectedReply) {
1094 BT_ERR("Can't get managed objects");
1095 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1097 g_dbus_error_strip_remote_error(error);
1098 ret = __bt_telephony_get_error(error->message);
1099 BT_ERR("Error here %d\n", ret);
1100 g_error_free(error);
1104 connected = g_variant_get_boolean(isConnectedReply);
1105 g_variant_unref(isConnectedReply);
1108 g_strlcpy(telephony_info.address,
1110 sizeof(telephony_info.address));
1112 isPlayingReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1114 G_DBUS_CALL_FLAGS_NONE,
1116 if (!isPlayingReply) {
1117 BT_ERR("Can't get managed objects");
1118 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1120 g_dbus_error_strip_remote_error(error);
1121 ret = __bt_telephony_get_error(error->message);
1122 BT_ERR("Error here %d\n", ret);
1123 g_error_free(error);
1126 playing = g_variant_get_boolean(isPlayingReply);
1127 g_variant_unref(isPlayingReply);
1130 telephony_info.headset_state =
1131 BLUETOOTH_STATE_PLAYING;
1133 telephony_info.headset_state =
1134 BLUETOOTH_STATE_CONNECTED;
1141 g_object_unref(headset_agent_proxy);
1142 g_variant_unref(var_path);
1144 g_variant_unref(param);
1148 if (headset_agent_proxy)
1149 g_object_unref(headset_agent_proxy);
1151 g_variant_unref(reply);
1153 g_variant_unref(var_path);
1155 g_variant_unref(param);
1160 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void)
1162 GDBusProxy *proxy = NULL;
1163 GError *error = NULL;
1167 if (strlen(telephony_info.address) == 0)
1168 __bluetooth_telephony_get_connected_device();
1170 if (strlen(telephony_info.address) == 0)
1173 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1174 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1175 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1176 HFP_AGENT_INTERFACE, NULL, &error);
1177 if (proxy == NULL) {
1178 BT_ERR("Unable to allocate new proxy");
1180 g_dbus_error_strip_remote_error(error);
1181 ret = __bt_telephony_get_error(error->message);
1182 BT_ERR("Error here %d\n", ret);
1183 g_error_free(error);
1192 int __bt_telephony_subscribe_adapter_signal(GDBusConnection *conn,
1198 static guint subscribe_adapter_id = 0;
1200 if (subscribe == TRUE) {
1201 if (subscribe_adapter_id == 0) {
1202 subscribe_adapter_id = g_dbus_connection_signal_subscribe(conn,
1203 NULL, "org.freedesktop.DBus.ObjectManager",
1204 "InterfacesAdded", NULL, NULL, 0,
1205 __bt_telephony_adapter_filter,
1208 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1210 if (subscribe_adapter_id > 0) {
1211 g_dbus_connection_signal_unsubscribe(conn,
1212 subscribe_adapter_id);
1213 subscribe_adapter_id = 0;
1215 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1219 int __bt_telephony_event_subscribe_signal(GDBusConnection *conn,
1225 static guint event_id = 0;
1227 if (subscribe == TRUE) {
1228 if (event_id == 0) {
1229 event_id = g_dbus_connection_signal_subscribe(conn,
1230 NULL, BLUEZ_HEADSET_INTERFACE,
1231 NULL, NULL, NULL, 0,
1232 __bluetooth_telephony_event_filter,
1235 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1238 g_dbus_connection_signal_unsubscribe(conn,
1242 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1246 BT_EXPORT_API int bluetooth_telephony_init(bt_telephony_func_ptr cb,
1249 bluetooth_device_address_t loc_address = { {0} };
1250 char src_address[BT_ADDRESS_STRING_SIZE] = { 0 };
1251 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1252 GError *error = NULL;
1256 if (is_initialized == TRUE) {
1257 BT_ERR("Bluetooth telephony already initilized");
1258 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1261 is_initialized = TRUE;
1263 /* As a result of discussion with system team, private connection is not
1264 * suitable in here. It is better to use shared connection. */
1265 //telephony_dbus_info.conn = _bt_gdbus_init_system_gconn();
1266 telephony_dbus_info.conn = _bt_get_system_shared_conn();
1267 if (!telephony_dbus_info.conn) {
1268 is_initialized = FALSE;
1269 BT_ERR("Could not get DBus Connection");
1270 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1274 snprintf(telephony_info.call_path, sizeof(telephony_info.call_path),
1275 CSD_CALL_APP_PATH, getpid());
1276 BT_INFO("Call Path = %s", telephony_info.call_path);
1277 memset(telephony_info.address, 0x00, sizeof(telephony_info.address));
1279 if (__bluetooth_telephony_proxy_init()) {
1280 BT_ERR("__bluetooth_telephony_proxy_init failed\n");
1281 telephony_dbus_info.conn = NULL;
1282 is_initialized = FALSE;
1283 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1286 telephony_dbus_info.manager_proxy = g_dbus_proxy_new_sync(
1287 telephony_dbus_info.conn,
1288 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1289 BLUEZ_SERVICE_NAME, "/",
1290 BLUEZ_MANAGER_INTERFACE, NULL, &error);
1291 if (telephony_dbus_info.manager_proxy == NULL) {
1292 BT_ERR("Could not create a manager proxy");
1293 __bluetooth_telephony_proxy_deinit();
1294 telephony_dbus_info.conn = NULL;
1295 is_initialized = FALSE;
1297 g_dbus_error_strip_remote_error(error);
1298 ret = __bt_telephony_get_error(error->message);
1299 BT_ERR("Error here %d\n", ret);
1300 g_error_free(error);
1303 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1306 telephony_dbus_info.dbus_proxy = g_dbus_proxy_new_sync(
1307 telephony_dbus_info.conn,
1308 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1309 BT_EVENT_FREEDESKTOP, BT_FREEDESKTOP_PATH,
1310 BT_EVENT_FREEDESKTOP, NULL, &error);
1311 if (NULL == telephony_dbus_info.dbus_proxy) {
1312 __bluetooth_telephony_proxy_deinit();
1313 telephony_dbus_info.conn = NULL;
1314 g_object_unref(telephony_dbus_info.manager_proxy);
1315 telephony_dbus_info.manager_proxy = NULL;
1316 is_initialized = FALSE;
1317 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1320 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, TRUE) != 0) {
1321 BT_ERR("Fail to Subscribe Adapter Signal");
1325 /*Callback and user applicaton data*/
1326 telephony_info.cb = cb;
1327 telephony_info.user_data = user_data;
1328 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1330 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, TRUE) != 0) {
1331 BT_ERR("Fail to Subscribe telephony event Signal");
1335 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED)
1336 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1338 /*Bluetooth is active, therefore set the flag */
1341 ret = bluetooth_get_local_address(&loc_address);
1342 if (ret != BLUETOOTH_ERROR_NONE) {
1343 BT_ERR("Fail to get local address\n");
1344 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1347 _bt_convert_addr_type_to_string(src_address, loc_address.addr);
1348 src_addr = g_strdup(src_address);
1350 ret = __bluetooth_telephony_register();
1351 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1352 BT_ERR("__bluetooth_telephony_register failed\n");
1356 if (TIZEN_PROFILE_WEARABLE || TIZEN_PROFILE_IVI)
1357 __bluetooth_telephony_init_headset_state();
1362 bluetooth_telephony_deinit();
1366 BT_EXPORT_API int bluetooth_telephony_deinit(void)
1369 BT_TELEPHONY_CHECK_INITIALIZED();
1371 is_initialized = FALSE;
1373 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, FALSE) != 0)
1374 BT_ERR("Fail to UnSubscribe telephony event Signal");
1376 if (bluetooth_check_adapter() != BLUETOOTH_ADAPTER_DISABLED ||
1377 bluetooth_check_adapter_le() != BLUETOOTH_ADAPTER_LE_DISABLED)
1378 __bluetooth_telephony_unregister();
1380 __bluetooth_telephony_proxy_deinit();
1382 telephony_info.cb = NULL;
1383 telephony_info.user_data = NULL;
1384 telephony_info.call_count = 0;
1385 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1387 /* Remove BT enabled signal */
1388 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, FALSE) != 0)
1389 BT_ERR("Fail to UnSubscribe Adapter event Signal");
1394 if (telephony_dbus_info.manager_proxy != NULL) {
1395 g_object_unref(telephony_dbus_info.manager_proxy);
1396 telephony_dbus_info.manager_proxy = NULL;
1399 if (telephony_dbus_info.conn != NULL)
1400 telephony_dbus_info.conn = NULL;
1402 if (telephony_dbus_info.dbus_proxy != NULL) {
1403 g_object_unref(telephony_dbus_info.dbus_proxy);
1404 telephony_dbus_info.dbus_proxy = NULL;
1408 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1411 BT_EXPORT_API gboolean bluetooth_telephony_is_sco_connected(void)
1415 gboolean status = FALSE;
1419 retv_if(is_initialized == FALSE, FALSE);
1420 retv_if(bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED, FALSE);
1422 reply = __bluetooth_telephony_dbus_method_send(
1423 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1424 "IsPlaying", &err, NULL);
1427 BT_ERR("Error returned in method call\n");
1429 BT_ERR("Error message = %s", err->message);
1434 g_variant_get(reply, "(b)", &status);
1435 g_variant_unref(reply);
1437 if (TIZEN_PROFILE_WEARABLE || TIZEN_PROFILE_IVI)
1438 if (status == TRUE && telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1439 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
1441 BT_INFO("SCO Connected Status = [%d]", status);
1445 BT_EXPORT_API int bluetooth_telephony_is_nrec_enabled(gboolean *status)
1450 GVariant *param_inner;
1454 BT_TELEPHONY_CHECK_INITIALIZED();
1455 BT_TELEPHONY_CHECK_ENABLED();
1458 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1460 if (telephony_info.headset_state == BLUETOOTH_STATE_DISCONNETED)
1461 return BLUETOOTH_TELEPHONY_ERROR_AUDIO_NOT_CONNECTED;
1463 reply = __bluetooth_telephony_dbus_method_send(
1464 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1465 "GetProperties", &err, NULL);
1468 BT_ERR("Error returned in method call\n");
1470 BT_DBG("Error message = %s", err->message);
1473 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1476 g_variant_iter_init(&iter, reply);
1477 while ((param_inner = g_variant_iter_next_value(&iter))) {
1480 value = g_variant_lookup_value(param_inner,
1481 "nrec", G_VARIANT_TYPE_BOOLEAN);
1483 BT_DBG("Property NREC Found");
1484 *status = g_variant_get_boolean(value);
1485 BT_DBG("NREC status = [%d]", *status);
1486 g_variant_unref(value);
1487 g_variant_unref(param_inner);
1490 g_variant_unref(param_inner);
1492 BT_DBG("NREC status = [%d]", *status);
1493 g_variant_unref(reply);
1496 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1499 BT_EXPORT_API int bluetooth_telephony_is_wbs_mode(gboolean *status)
1505 GVariant *param_inner;
1509 BT_TELEPHONY_CHECK_INITIALIZED();
1510 BT_TELEPHONY_CHECK_ENABLED();
1513 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1517 reply = __bluetooth_telephony_dbus_method_send(
1518 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1519 "GetProperties", &err, NULL);
1522 BT_ERR("Error returned in method call");
1524 BT_ERR("Error message = %s", err->message);
1527 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1530 g_variant_iter_init(&iter, reply);
1531 while ((param_inner = g_variant_iter_next_value(&iter))) {
1534 value = g_variant_lookup_value(param_inner,
1535 "codec", G_VARIANT_TYPE_UINT32);
1537 BT_DBG("Property CODEC Found");
1538 codec = g_variant_get_uint32(value);
1539 g_variant_unref(value);
1540 BT_DBG("Codec = [%d]", codec);
1542 *status = codec == BT_MSBC_CODEC_ID ? TRUE : FALSE;
1543 BT_DBG("NREC status = [%d]", *status);
1544 g_variant_unref(value);
1545 g_variant_unref(param_inner);
1548 g_variant_unref(param_inner);
1551 g_variant_unref(reply);
1552 BT_DBG("MSBC status = [%d]", *status);
1555 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1558 BT_EXPORT_API int bluetooth_telephony_send_vendor_cmd(const char *cmd)
1560 GError *error = NULL;
1561 GVariant *reply, *parameters;
1562 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1566 BT_TELEPHONY_CHECK_INITIALIZED();
1567 BT_TELEPHONY_CHECK_ENABLED();
1569 BT_DBG("Send Vendor %s", cmd);
1571 if (telephony_dbus_info.proxy == NULL)
1572 telephony_dbus_info.proxy =
1573 __bluetooth_telephony_get_connected_device_proxy();
1575 if (telephony_dbus_info.proxy == NULL)
1576 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1578 parameters = g_variant_new("s", cmd);
1579 reply = g_dbus_proxy_call_sync(telephony_dbus_info.proxy,
1580 "SendVendorAtCmd", parameters,
1581 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1583 g_variant_unref(reply);
1586 g_dbus_error_strip_remote_error(error);
1587 ret = __bt_telephony_get_error(error->message);
1588 BT_ERR("Error here %d\n", ret);
1589 g_error_free(error);
1596 BT_EXPORT_API int bluetooth_telephony_start_voice_recognition(void)
1602 gboolean state = TRUE;
1606 BT_TELEPHONY_CHECK_INITIALIZED();
1607 BT_TELEPHONY_CHECK_ENABLED();
1609 param = g_variant_new("(b)", &state);
1610 reply = __bluetooth_telephony_dbus_method_send(
1611 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1612 "SetVoiceDial", &err, param);
1615 BT_ERR("Error returned in method call\n");
1617 g_dbus_error_strip_remote_error(err);
1618 ret = __bt_telephony_get_error(err->message);
1622 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1625 g_variant_unref(reply);
1627 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1630 BT_EXPORT_API int bluetooth_telephony_stop_voice_recognition(void)
1636 gboolean state = FALSE;
1640 BT_TELEPHONY_CHECK_INITIALIZED();
1641 BT_TELEPHONY_CHECK_ENABLED();
1643 param = g_variant_new("(b)", &state);
1644 reply = __bluetooth_telephony_dbus_method_send(
1645 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1646 "SetVoiceDial", &err, param);
1649 BT_ERR("Error returned in method call\n");
1651 g_dbus_error_strip_remote_error(err);
1652 ret = __bt_telephony_get_error(err->message);
1656 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1659 g_variant_unref(reply);
1662 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1665 static void __bluetooth_telephony_sco_start_cb(GDBusProxy *proxy,
1666 GAsyncResult *res, gpointer user_data)
1668 GError *error = NULL;
1669 GVariant *value = NULL;
1671 value = g_dbus_proxy_call_finish(proxy, res, &error);
1672 if (value == NULL) {
1673 if (error != NULL) {
1674 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1675 error->code, error->message);
1676 g_clear_error(&error);
1678 BT_ERR("SCo Start Failed");
1680 g_object_unref(proxy);
1684 BT_DBG("sco_start_cb : -");
1685 g_object_unref(proxy);
1686 g_variant_unref(value);
1689 BT_EXPORT_API int bluetooth_telephony_audio_open(void)
1691 GDBusConnection *conn;
1698 BT_TELEPHONY_CHECK_INITIALIZED();
1699 BT_TELEPHONY_CHECK_ENABLED();
1701 /* Because this API is async call, so can't use dbus SMACK */
1702 if (__bt_telephony_check_privilege() ==
1703 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1704 BT_ERR("Don't have a privilege to use this API");
1705 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1708 conn = _bt_get_system_private_conn();
1710 BT_DBG("No System Bus found\n");
1711 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1714 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING)
1715 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
1717 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1718 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1719 HFP_AGENT_INTERFACE, NULL, &err);
1720 if (proxy == NULL) {
1721 BT_ERR("Unable to allocate new proxy");
1723 g_dbus_error_strip_remote_error(err);
1724 ret = __bt_telephony_get_error(err->message);
1725 BT_ERR("Error here %d\n", ret);
1729 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1732 g_dbus_proxy_call(proxy, "Play", NULL, G_DBUS_CALL_FLAGS_NONE,
1733 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_start_cb, NULL);
1736 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1739 static void __bluetooth_telephony_sco_close_cb(GDBusProxy *proxy,
1740 GAsyncResult *res, gpointer user_data)
1742 GError *error = NULL;
1743 GVariant *value = NULL;
1745 value = g_dbus_proxy_call_finish(proxy, res, &error);
1746 if (value == NULL) {
1747 if (error != NULL) {
1748 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1749 error->code, error->message);
1750 g_clear_error(&error);
1752 BT_ERR("SCo close Failed");
1754 g_object_unref(proxy);
1758 BT_DBG("sco_close_cb : -");
1759 g_object_unref(proxy);
1760 g_variant_unref(value);
1762 BT_EXPORT_API int bluetooth_telephony_audio_close(void)
1764 GDBusConnection *conn;
1771 BT_TELEPHONY_CHECK_INITIALIZED();
1772 BT_TELEPHONY_CHECK_ENABLED();
1774 /* Because this API is async call, so can't use dbus SMACK */
1775 if (__bt_telephony_check_privilege() ==
1776 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1777 BT_ERR("Don't have a privilege to use this API");
1778 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1781 conn = _bt_get_system_private_conn();
1783 BT_DBG("No System Bus found\n");
1784 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1787 if (telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1788 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
1790 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
1791 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1792 HFP_AGENT_INTERFACE, NULL, &err);
1793 if (proxy == NULL) {
1794 BT_ERR("Unable to allocate new proxy");
1796 g_dbus_error_strip_remote_error(err);
1797 ret = __bt_telephony_get_error(err->message);
1798 BT_ERR("Error here %d\n", ret);
1802 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1805 g_dbus_proxy_call(proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE,
1806 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_close_cb, NULL);
1808 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
1811 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1814 BT_EXPORT_API int bluetooth_telephony_call_remote_ringing(unsigned int call_id)
1818 BT_TELEPHONY_CHECK_INITIALIZED();
1819 BT_TELEPHONY_CHECK_ENABLED();
1822 BT_DBG("call_id = [%d]", call_id);
1824 /*Make sure SCO is already connected */
1825 ret = __bluetooth_telephony_send_call_status(
1826 CSD_CALL_STATUS_MO_ALERTING, call_id, NULL);
1828 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1829 BT_ERR("send call status Failed = [%d]", ret);
1835 BT_EXPORT_API int bluetooth_telephony_call_answered(unsigned int call_id,
1836 unsigned int bt_audio)
1841 BT_DBG("call_id = [%d]", call_id);
1843 BT_TELEPHONY_CHECK_INITIALIZED();
1844 BT_TELEPHONY_CHECK_ENABLED();
1846 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1848 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1849 BT_ERR("send call status Failed = [%d]", ret);
1854 if (!bluetooth_telephony_is_sco_connected()) {
1855 ret = bluetooth_telephony_audio_open();
1856 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1857 BT_ERR("Audio connection call Failed[%d]", ret);
1865 BT_EXPORT_API int bluetooth_telephony_call_end(unsigned int call_id)
1870 BT_DBG("call_id = [%d]", call_id);
1872 BT_TELEPHONY_CHECK_INITIALIZED();
1873 BT_TELEPHONY_CHECK_ENABLED();
1875 if (telephony_info.call_count > 0)
1876 telephony_info.call_count = telephony_info.call_count - 1;
1878 if (telephony_info.call_count == 0) {
1879 if (bluetooth_telephony_is_sco_connected()) {
1880 ret = bluetooth_telephony_audio_close();
1881 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1882 BT_ERR(" Failed = [%d]", ret);
1886 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_MT_RELEASE,
1888 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1889 BT_ERR("send call status Failed = [%d]", ret);
1895 BT_EXPORT_API int bluetooth_telephony_call_held(unsigned int call_id)
1900 BT_DBG("call_id = [%d]", call_id);
1902 BT_TELEPHONY_CHECK_INITIALIZED();
1903 BT_TELEPHONY_CHECK_ENABLED();
1905 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_HOLD,
1907 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1908 BT_ERR("send call status Failed = [%d]", ret);
1914 BT_EXPORT_API int bluetooth_telephony_call_retrieved(unsigned int call_id)
1919 BT_DBG("call_id = [%d]", call_id);
1921 BT_TELEPHONY_CHECK_INITIALIZED();
1922 BT_TELEPHONY_CHECK_ENABLED();
1924 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1926 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1927 BT_ERR("send call status Failed = [%d]", ret);
1933 BT_EXPORT_API int bluetooth_telephony_call_swapped(void *call_list,
1934 unsigned int call_count)
1938 GList *list = call_list;
1939 bt_telephony_call_status_info_t *call_status;
1943 BT_TELEPHONY_CHECK_INITIALIZED();
1944 BT_TELEPHONY_CHECK_ENABLED();
1947 BT_ERR("call_list is invalid");
1948 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1951 /* Because this API is async call, so can't use dbus SMACK */
1952 if (__bt_telephony_check_privilege() ==
1953 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1954 BT_ERR("Don't have a privilege to use this API");
1955 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1958 BT_DBG(" call_count = [%d]", call_count);
1960 for (i = 0; i < call_count; i++) {
1961 call_status = g_list_nth_data(list, i);
1963 if (NULL == call_status)
1966 BT_DBG(" %d : Call id [%d] status[%d]", i,
1967 call_status->call_id,
1968 call_status->call_status);
1970 if (NULL != call_status->phone_number)
1971 DBG_SECURE("Number [%s]", call_status->phone_number);
1973 switch (call_status->call_status) {
1974 case BLUETOOTH_CALL_STATE_HELD:
1975 ret = __bluetooth_telephony_send_call_status(
1976 CSD_CALL_STATUS_HOLD,
1977 call_status->call_id,
1978 call_status->phone_number);
1979 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1980 BT_ERR("Failed = %d", ret);
1985 case BLUETOOTH_CALL_STATE_CONNECTED:
1986 ret = __bluetooth_telephony_send_call_status(
1987 CSD_CALL_STATUS_ACTIVE,
1988 call_status->call_id,
1989 call_status->phone_number);
1990 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1991 BT_ERR("Failed = [%d]", ret);
1997 if ((call_status->call_status <
1998 BLUETOOTH_CALL_STATE_NONE) ||
1999 (call_status->call_status >=
2000 BLUETOOTH_CALL_STATE_ERROR)) {
2001 BT_ERR("Unknown Call state");
2002 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
2008 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2011 BT_EXPORT_API int bluetooth_telephony_set_call_status(void *call_list,
2012 unsigned int call_count)
2018 ret = bluetooth_telephony_call_swapped(call_list, call_count);
2020 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2021 BT_ERR("Failed = [%d]", ret);
2025 telephony_info.call_count = call_count;
2028 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2031 BT_EXPORT_API int bluetooth_telephony_indicate_outgoing_call(
2032 const char *ph_number, unsigned int call_id,
2033 unsigned int bt_audio)
2038 const char *path = telephony_info.call_path;
2039 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
2043 BT_TELEPHONY_CHECK_INITIALIZED();
2044 BT_TELEPHONY_CHECK_ENABLED();
2046 if (NULL == ph_number)
2047 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2049 param = g_variant_new("(ssi)", path, ph_number, call_id);
2050 reply = __bluetooth_telephony_dbus_method_send(
2051 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2052 "OutgoingCall", &err, param);
2055 BT_ERR("Error returned in method call\n");
2057 g_dbus_error_strip_remote_error(err);
2058 ret = __bt_telephony_get_error(err->message);
2062 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2065 g_variant_unref(reply);
2067 telephony_info.call_count++;
2068 BT_DBG(" ag_info.ag_call_count = [%d]", telephony_info.call_count);
2071 if (!bluetooth_telephony_is_sco_connected()) {
2072 ret = bluetooth_telephony_audio_open();
2074 BT_ERR(" Audio connection Failed = %d", ret);
2082 BT_EXPORT_API int bluetooth_telephony_indicate_incoming_call(
2083 const char *ph_number, unsigned int call_id)
2088 const char *path = telephony_info.call_path;
2093 BT_TELEPHONY_CHECK_INITIALIZED();
2094 BT_TELEPHONY_CHECK_ENABLED();
2096 if (NULL == ph_number)
2097 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2099 param = g_variant_new("(ssi)", path, ph_number, call_id);
2100 reply = __bluetooth_telephony_dbus_method_send(
2101 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2102 "IncomingCall", &err, param);
2105 BT_ERR("Error returned in method call\n");
2107 g_dbus_error_strip_remote_error(err);
2108 ret = __bt_telephony_get_error(err->message);
2112 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2115 g_variant_unref(reply);
2116 telephony_info.call_count++;
2117 BT_DBG("telephony_info.call_count = [%d]", telephony_info.call_count);
2119 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2122 BT_EXPORT_API int bluetooth_telephony_set_speaker_gain(
2123 unsigned short speaker_gain)
2132 BT_TELEPHONY_CHECK_INITIALIZED();
2133 BT_TELEPHONY_CHECK_ENABLED();
2135 BT_DBG("set speaker_gain= [%d]", speaker_gain);
2137 param = g_variant_new("(q)", speaker_gain);
2138 reply = __bluetooth_telephony_dbus_method_send(
2139 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2140 "SetSpeakerGain", &err, param);
2143 BT_ERR("Error returned in method call\n");
2145 g_dbus_error_strip_remote_error(err);
2146 ret = __bt_telephony_get_error(err->message);
2150 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2153 g_variant_unref(reply);
2155 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2158 BT_EXPORT_API int bluetooth_telephony_get_headset_volume(
2159 unsigned int *speaker_gain)
2168 BT_TELEPHONY_CHECK_INITIALIZED();
2169 BT_TELEPHONY_CHECK_ENABLED();
2171 reply = __bluetooth_telephony_dbus_method_send(
2172 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2173 "GetSpeakerGain", &err, NULL);
2176 BT_ERR("Error returned in method call\n");
2178 g_dbus_error_strip_remote_error(err);
2179 ret = __bt_telephony_get_error(err->message);
2183 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2185 g_variant_get(reply, "(q)", &gain);
2186 *speaker_gain = gain;
2187 BT_DBG("Get speaker_gain= [%d]", *speaker_gain);
2189 g_variant_unref(reply);
2192 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2195 BT_EXPORT_API int bluetooth_telephony_get_battery_level(
2196 const char *remote_address, unsigned int *level)
2200 GVariant *param = NULL;
2205 BT_TELEPHONY_CHECK_INITIALIZED();
2206 BT_TELEPHONY_CHECK_ENABLED();
2208 param = g_variant_new("(s)", remote_address);
2210 reply = __bluetooth_telephony_dbus_method_send(
2211 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2212 "GetHfBatteryLevel", &err, param);
2215 BT_ERR("Error returned in method call\n");
2217 g_dbus_error_strip_remote_error(err);
2218 ret = __bt_telephony_get_error(err->message);
2222 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2225 g_variant_get(reply, "(u)", level);
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 g_dbus_error_strip_remote_error(err);
2250 ret = __bt_telephony_get_error(err->message);
2254 return BLUETOOTH_ERROR_INTERNAL;
2256 g_variant_get(reply, "(b)", &ag_connected_from_bt_agent);
2257 *ag_connected = ag_connected_from_bt_agent;
2259 BT_DBG("Conn Status: %s", *ag_connected ? "Connected" : "Disconnected");
2261 g_variant_unref(reply);
2263 return BLUETOOTH_ERROR_NONE;
2266 BT_EXPORT_API int bluetooth_telephony_set_active_headset(const char *remote_addr)
2273 BT_CHECK_ENABLED(return);
2275 if (NULL == remote_addr)
2276 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2278 param = g_variant_new("(s)", remote_addr);
2279 reply = __bluetooth_telephony_dbus_method_send(
2280 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2281 "SwapHeadset", &err, param);
2284 BT_ERR("Error returned in method call\n");
2286 g_dbus_error_strip_remote_error(err);
2287 ret = __bt_telephony_get_error(err->message);
2291 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2294 g_variant_unref(reply);
2295 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2298 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
2299 const gchar *sender_name,
2300 const gchar *object_path,
2301 const gchar *interface_name,
2302 const gchar *signal_name,
2303 GVariant *parameters,
2310 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
2311 GVariant *optional_param = NULL;
2313 g_variant_get(parameters, "(&o@a{sa{sv}})",
2314 &path, &optional_param);
2317 BT_ERR("Invalid adapter path");
2321 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
2322 if (__bt_telephony_get_src_addr(optional_param))
2323 BT_ERR("Fail to get the local adapter address");
2325 ret = __bluetooth_telephony_register();
2326 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
2327 BT_ERR("__bluetooth_telephony_register failed");
2330 g_variant_unref(optional_param);
2336 static int __bt_telephony_get_src_addr(GVariant *value)
2339 GVariant *param = NULL;
2342 /* signature a{sa{sv}} */
2343 g_variant_iter_init(&iter, value);
2344 while ((param = g_variant_iter_next_value(&iter))) {
2345 char *interface_name;
2346 GVariant *interface_var = NULL;
2347 GVariant *param_inner = NULL;
2349 g_variant_get(param, "{&s*}", &interface_name, &interface_var);
2350 g_variant_unref(param);
2352 BT_DBG("interface_name: %s", interface_name);
2353 /* format of interface_var: a{sv}*/
2354 if (strcasecmp(interface_name, BLUEZ_ADAPTER_INTERFACE) == 0) {
2355 GVariantIter iter_inner;
2357 g_variant_iter_init(&iter_inner, interface_var);
2358 while ((param_inner = g_variant_iter_next_value(&iter_inner))) {
2359 char *property_name;
2360 GVariant *property_var;
2362 g_variant_get(param_inner, "{&sv}",
2365 g_variant_unref(param_inner);
2367 if (strcasecmp(property_name, "Address") == 0) {
2368 const gchar *bd_addr;
2370 bd_addr = g_variant_get_string(
2373 src_addr = g_strdup(bd_addr);
2374 BT_DBG("Address: %s", src_addr);
2376 g_variant_unref(interface_var);
2377 g_variant_unref(property_var);
2380 g_variant_unref(property_var);
2383 g_variant_unref(interface_var);
2387 return BLUETOOTH_ERROR_NONE;