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 char *src_addr = NULL;
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"
77 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
79 /*Below Inrospection data is exposed to bluez from agent*/
80 static const gchar bt_telephony_introspection_xml[] =
82 " <interface name='org.tizen.csd.Call.Instance'>"
83 " <method name='SendDtmf'>"
84 " <arg type='s' name='dtmf' direction='in'/>"
86 " <method name='VendorCmd'>"
87 " <arg type='s' name='vendor' direction='in'/>"
92 #define BT_TELEPHONY_CHECK_ENABLED() \
94 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED) { \
95 BT_ERR("BT is not enabled"); \
96 return BLUETOOTH_TELEPHONY_ERROR_NOT_ENABLED; \
100 static gboolean is_initialized = FALSE;
101 #define BT_TELEPHONY_CHECK_INITIALIZED() \
103 if (is_initialized == FALSE) { \
104 BT_ERR("Bluetooth telephony not initilized"); \
105 return BLUETOOTH_TELEPHONY_ERROR_NOT_INITIALIZED; \
109 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
110 const gchar *sender_name,
111 const gchar *object_path,
112 const gchar *interface_name,
113 const gchar *signal_name,
114 GVariant *parameters,
117 static int __bt_telephony_get_src_addr(GVariant *value);
119 static bt_telephony_info_t telephony_info;
120 static telephony_dbus_info_t telephony_dbus_info;
121 static gboolean is_active = FALSE;
123 /*Function Declaration*/
124 static int __bt_telephony_get_error(const char *error_message);
125 static void __bt_telephony_event_cb(int event, int result, void *param_data);
126 static GQuark __bluetooth_telephony_error_quark(void);
127 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
128 const char *interface, const char *method,
129 GError **err, GVariant *parameters);
130 static int __bluetooth_telephony_send_call_status(
131 bt_telephony_call_status_t call_status,
132 unsigned int call_id, const char *ph_number);
133 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
134 bluetooth_telephony_error_t error, const char *err_msg);
136 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
137 const gchar *sender_name,
138 const gchar *object_path,
139 const gchar *interface_name,
140 const gchar *signal_name,
141 GVariant *parameters,
144 static int __bluetooth_telephony_proxy_init(void);
145 static void __bluetooth_telephony_proxy_deinit(void);
146 static int __bluetooth_telephony_register(void);
147 static int __bluetooth_telephony_unregister(void);
149 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class);
150 static int __bluetooth_telephony_get_connected_device(void);
151 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void);
153 /*Function Definition*/
154 static void __bt_telephony_method(GDBusConnection *connection,
156 const gchar *object_path,
157 const gchar *interface_name,
158 const gchar *method_name,
159 GVariant *parameters,
160 GDBusMethodInvocation *invocation,
165 BT_INFO("method %s", method_name);
166 BT_INFO("object_path %s", object_path);
168 if (g_strcmp0(method_name, "SendDtmf") == 0) {
170 telephony_event_dtmf_t call_data = { 0, };
172 g_variant_get(parameters, "(&s)", &dtmf);
175 BT_ERR("Number dial failed");
176 __bluetooth_telephony_error(invocation,
177 BLUETOOTH_TELEPHONY_ERROR_INVALID_DTMF,
180 DBG_SECURE("Dtmf = %s", dtmf);
182 call_data.dtmf = g_strdup(dtmf);
183 __bt_telephony_event_cb(
184 BLUETOOTH_EVENT_TELEPHONY_SEND_DTMF,
185 BLUETOOTH_TELEPHONY_ERROR_NONE,
188 g_free(call_data.dtmf);
190 g_dbus_method_invocation_return_value(invocation, NULL);
192 } else if (g_strcmp0(method_name, "VendorCmd") == 0) {
195 g_variant_get(parameters, "(&s)", &at_cmd);
196 BT_INFO("Vendor %s", at_cmd);
197 if (at_cmd == NULL) {
198 BT_ERR("Vendor command is NULL\n");
199 __bluetooth_telephony_error(invocation,
200 BLUETOOTH_TELEPHONY_ERROR_APPLICATION,
201 "Invalid at vendor cmd");
203 DBG_SECURE("Vendor AT cmd = %s", at_cmd);
205 __bt_telephony_event_cb(
206 BLUETOOTH_EVENT_TELEPHONY_VENDOR_AT_CMD,
207 BLUETOOTH_TELEPHONY_ERROR_NONE,
210 g_dbus_method_invocation_return_value(invocation, NULL);
217 static const GDBusInterfaceVTable method_table = {
218 __bt_telephony_method,
223 static int __bt_telephony_get_error(const char *error_message)
225 if (error_message == NULL) {
226 BT_ERR("Error message NULL");
227 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
230 BT_ERR("Error message = %s", error_message);
231 if (g_strcmp0(error_message, "NotAvailable") == 0)
232 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
233 else if (g_strcmp0(error_message, "NotConnected") == 0)
234 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
235 else if (g_strcmp0(error_message, "InProgress") == 0)
236 return BLUETOOTH_TELEPHONY_ERROR_BUSY;
237 else if (g_strcmp0(error_message, "InvalidArguments") == 0)
238 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
239 else if (g_strcmp0(error_message, "AlreadyExists") == 0)
240 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_EXSIST;
241 else if (g_strcmp0(error_message, "Already Connected") == 0)
242 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
243 else if (g_strcmp0(error_message, "No memory") == 0)
244 return BLUETOOTH_TELEPHONY_ERROR_NO_MEMORY;
245 else if (g_strcmp0(error_message, "I/O error") == 0)
246 return BLUETOOTH_TELEPHONY_ERROR_I_O_ERROR;
247 else if (g_strcmp0(error_message,
248 "Operation currently not available") == 0)
249 return BLUETOOTH_TELEPHONY_ERROR_OPERATION_NOT_AVAILABLE;
250 else if (g_strrstr(error_message, BT_ACCESS_DENIED_MSG))
251 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
253 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
256 static int __bt_telephony_check_privilege(void)
263 reply = __bluetooth_telephony_dbus_method_send(
264 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
265 "CheckPrivilege", &err, NULL);
268 BT_ERR("Error returned in method call");
270 g_dbus_error_strip_remote_error(err);
271 ret = __bt_telephony_get_error(err->message);
275 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
277 g_variant_unref(reply);
280 return BLUETOOTH_TELEPHONY_ERROR_NONE;
283 static void __bt_telephony_event_cb(int event, int result, void *param_data)
285 telephony_event_param_t bt_event = { 0, };
287 bt_event.event = event;
288 bt_event.result = result;
289 bt_event.param_data = param_data;
291 ret_if(telephony_info.cb == NULL);
292 telephony_info.cb(bt_event.event, &bt_event, telephony_info.user_data);
296 static GQuark __bluetooth_telephony_error_quark(void)
298 static GQuark quark = 0;
300 quark = g_quark_from_static_string("telephony");
305 static GVariant *__bluetooth_telephony_dbus_method_send(const char *path,
306 const char *interface, const char *method,
307 GError **err, GVariant *parameters)
311 if (TIZEN_PROFILE_WEARABLE || TIZEN_PROFILE_IVI)
316 GDBusConnection *conn;
320 conn = telephony_dbus_info.conn;
321 retv_if(conn == NULL, NULL);
323 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
324 NULL, HFP_AGENT_SERVICE, path, interface, NULL, err);
326 BT_ERR("Unable to allocate new proxy");
330 reply = g_dbus_proxy_call_sync(proxy, method, parameters,
331 G_DBUS_CALL_FLAGS_NONE, timeout, NULL, err);
333 g_object_unref(proxy);
338 static int __bluetooth_telephony_send_call_status(
339 bt_telephony_call_status_t call_status,
340 unsigned int call_id, const char *ph_number)
345 char *path = g_strdup(telephony_info.call_path);
351 if (NULL == ph_number)
352 phone_number = g_strdup("");
354 phone_number = g_strdup(ph_number);
356 param = g_variant_new("(ssii)", path, phone_number,
357 call_status, call_id);
358 reply = __bluetooth_telephony_dbus_method_send(
359 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
360 "ChangeCallStatus", &err, param);
363 g_free(phone_number);
366 BT_ERR("Error returned in method call");
368 g_dbus_error_strip_remote_error(err);
369 ret = __bt_telephony_get_error(err->message);
373 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
376 g_variant_unref(reply);
378 return BLUETOOTH_TELEPHONY_ERROR_NONE;
381 static void __bluetooth_telephony_error(GDBusMethodInvocation *invocation,
382 bluetooth_telephony_error_t error, const char *err_msg)
384 g_dbus_method_invocation_return_error(invocation,
385 BLUETOOTH_TELEPHONY_ERROR, error,
389 static void __bluetooth_telephony_answer_call(GVariant *var)
391 telephony_event_callid_t call_data = { 0, };
396 g_variant_get(var, "(u)", &callid);
397 BT_DBG("call_id = [%d]", callid);
398 call_data.callid = callid;
400 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_ANSWER_CALL,
401 BLUETOOTH_TELEPHONY_ERROR_NONE,
406 static void __bluetooth_telephony_release_call(GVariant *var)
408 telephony_event_callid_t call_data = { 0, };
413 g_variant_get(var, "(u)", &callid);
414 BT_DBG("call_id = [%d]", callid);
415 call_data.callid = callid;
417 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_RELEASE_CALL,
418 BLUETOOTH_TELEPHONY_ERROR_NONE,
423 static void __bluetooth_telephony_reject_call(GVariant *var)
425 telephony_event_callid_t call_data = { 0, };
430 g_variant_get(var, "(u)", &callid);
431 BT_DBG("call_id = [%d]", callid);
432 call_data.callid = callid;
434 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_REJECT_CALL,
435 BLUETOOTH_TELEPHONY_ERROR_NONE,
440 static void __bluetooth_telephony_threeway_call(GVariant *var)
443 unsigned int chld_value;
447 g_variant_get(var, "(u)", &chld_value);
448 BT_DBG("chld value = [%d]", chld_value);
450 switch (chld_value) {
452 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_0_RELEASE_ALL_HELD_CALL;
455 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_1_RELEASE_ALL_ACTIVE_CALL;
458 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_2_ACTIVE_HELD_CALL;
461 event = BLUETOOTH_EVENT_TELEPHONY_CHLD_3_MERGE_CALL;
464 BT_ERR("Invalid CHLD command");
468 __bt_telephony_event_cb(event,
469 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
473 static void __bluetooth_handle_nrec_status_change(GVariant *var)
475 gboolean status = FALSE;
477 g_variant_get(var, "(b)", &status);
478 BT_INFO("NREC status = %d", status);
480 __bt_telephony_event_cb(BLUETOOTH_EVENT_TELEPHONY_NREC_CHANGED,
481 BLUETOOTH_TELEPHONY_ERROR_NONE, (void *)&status);
485 static void __bluetooth_telephony_event_filter(GDBusConnection *connection,
486 const gchar *sender_name,
487 const gchar *object_path,
488 const gchar *interface_name,
489 const gchar *signal_name,
490 GVariant *parameters,
495 if (strcasecmp(interface_name, HFP_AGENT_SERVICE) == 0) {
496 if (strcasecmp(signal_name, HFP_NREC_STATUS_CHANGE) == 0)
497 __bluetooth_handle_nrec_status_change(parameters);
498 else if (strcasecmp(signal_name, HFP_ANSWER_CALL) == 0)
499 __bluetooth_telephony_answer_call(parameters);
500 else if (strcasecmp(signal_name, HFP_REJECT_CALL) == 0)
501 __bluetooth_telephony_reject_call(parameters);
502 else if (strcasecmp(signal_name, HFP_RELEASE_CALL) == 0)
503 __bluetooth_telephony_release_call(parameters);
504 else if (strcasecmp(signal_name, HFP_THREEWAY_CALL) == 0)
505 __bluetooth_telephony_threeway_call(parameters);
506 } else if (strcasecmp(interface_name, BLUEZ_HEADSET_INTERFACE) == 0) {
507 if (strcasecmp(signal_name, "PropertyChanged") == 0) {
511 g_variant_get(parameters, "(&sv)", &property, &values);
512 BT_DBG("Property: %s", property);
514 if (strcasecmp(property, "State") == 0) {
516 state = (gchar *)g_variant_get_string(values, NULL);
519 BT_ERR("State is null");
522 BT_DBG("state: %s", state);
523 if (g_strcmp0(state, "connected") == 0) {
524 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
525 } else if (g_strcmp0(state, "playing") == 0) {
526 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
527 } else if (g_strcmp0(state, "disconnected") == 0) {
528 /* Headset state: playing -> disconnected */
529 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING) {
530 __bt_telephony_event_cb(
531 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
532 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
535 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
537 } else if (strcasecmp(property, "Connected") == 0) {
538 gboolean connected = FALSE;
539 char *dev_addr = NULL;
540 connected = g_variant_get_boolean(values);
541 BT_INFO("connected %d", connected);
543 /*Get device address*/
544 if (object_path != NULL)
545 dev_addr = strstr(object_path, "dev_");
547 if (dev_addr != NULL) {
549 g_strlcpy(telephony_info.address,
551 sizeof(telephony_info.address));
552 g_strdelimit(telephony_info.address, "_", ':');
553 BT_DBG("address is %s",
554 telephony_info.address);
556 telephony_info.headset_state =
557 BLUETOOTH_STATE_CONNECTED;
559 if (telephony_dbus_info.proxy != NULL) {
560 g_object_unref(telephony_dbus_info.proxy);
561 telephony_dbus_info.proxy = NULL;
564 telephony_dbus_info.proxy =
565 __bluetooth_telephony_get_connected_device_proxy();
567 BT_INFO("Headset Connected");
569 __bt_telephony_event_cb(
570 BLUETOOTH_EVENT_TELEPHONY_HFP_CONNECTED,
571 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
573 } else { /*Device disconnected*/
574 memset(telephony_info.address, 0x00,
575 sizeof(telephony_info.address));
576 telephony_info.headset_state =
577 BLUETOOTH_STATE_DISCONNETED;
579 if (telephony_dbus_info.proxy != NULL) {
580 g_object_unref(telephony_dbus_info.proxy);
581 telephony_dbus_info.proxy = NULL;
584 BT_INFO("Headset Disconnected");
586 __bt_telephony_event_cb(
587 BLUETOOTH_EVENT_TELEPHONY_HFP_DISCONNECTED,
588 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
590 } else if (strcasecmp(property, "SpeakerGain") == 0) {
591 unsigned int spkr_gain;
592 guint16 gain = g_variant_get_uint16(values);
594 spkr_gain = (unsigned int)gain;
595 BT_DBG("spk_gain[%d]", spkr_gain);
597 __bt_telephony_event_cb(
598 BLUETOOTH_EVENT_TELEPHONY_SET_SPEAKER_GAIN,
599 BLUETOOTH_TELEPHONY_ERROR_NONE,
601 } else if (strcasecmp(property, "MicrophoneGain") == 0) {
602 unsigned int mic_gain;
603 guint16 gain = g_variant_get_uint16(values);
605 mic_gain = (unsigned int)gain;
606 BT_DBG("mic_gain[%d]", mic_gain);
608 __bt_telephony_event_cb(
609 BLUETOOTH_EVENT_TELEPHONY_SET_MIC_GAIN,
610 BLUETOOTH_TELEPHONY_ERROR_NONE,
612 } else if (strcasecmp(property, "Playing") == 0) {
613 gboolean audio_sink_playing;
615 audio_sink_playing = g_variant_get_boolean(values);
616 if (audio_sink_playing) {
617 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
618 __bt_telephony_event_cb(
619 BLUETOOTH_EVENT_TELEPHONY_AUDIO_CONNECTED,
620 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
622 telephony_info.headset_state =
623 BLUETOOTH_STATE_CONNECTED;
624 __bt_telephony_event_cb(
625 BLUETOOTH_EVENT_TELEPHONY_AUDIO_DISCONNECTED,
626 BLUETOOTH_TELEPHONY_ERROR_NONE, NULL);
630 g_variant_unref(values);
636 static GDBusNodeInfo *__bt_telephony_create_method_node_info
637 (const gchar *introspection_data)
640 GDBusNodeInfo *node_info = NULL;
642 if (introspection_data == NULL)
645 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
648 BT_ERR("Unable to create node: %s", err->message);
655 int __bluetooth_telephony_register_object(int reg, GDBusNodeInfo *node_info)
657 static guint bt_tel_id = 0;
658 GError *error = NULL;
662 if (node_info == NULL)
663 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
665 path = g_strdup(telephony_info.call_path);
666 BT_DBG("path is [%s]", path);
668 bt_tel_id = g_dbus_connection_register_object(telephony_dbus_info.conn,
669 path, node_info->interfaces[0],
674 if (bt_tel_id == 0) {
675 BT_ERR("Failed to register: %s", error->message);
677 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
681 g_dbus_connection_unregister_object(telephony_dbus_info.conn,
687 return BLUETOOTH_TELEPHONY_ERROR_NONE;
690 static int __bluetooth_telephony_proxy_init(void)
693 GDBusNodeInfo *node_info;
695 node_info = __bt_telephony_create_method_node_info(
696 bt_telephony_introspection_xml);
697 if (node_info == NULL) {
698 BT_ERR("node_info NULL");
699 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
701 if (__bluetooth_telephony_register_object(TRUE, node_info) !=
702 BLUETOOTH_TELEPHONY_ERROR_NONE) {
703 BT_ERR("Registation of Method Failed");
704 g_dbus_node_info_unref(node_info);
705 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
709 g_dbus_node_info_unref(node_info);
710 return BLUETOOTH_TELEPHONY_ERROR_NONE;
713 static void __bluetooth_telephony_proxy_deinit(void)
717 __bluetooth_telephony_register_object(FALSE, NULL);
723 static int __bluetooth_telephony_register(void)
728 char *path = g_strdup(telephony_info.call_path);
733 param = g_variant_new("(ss)", path, src_addr);
734 BT_DBG("Path[%s] Src_Address[%s]", path, src_addr);
736 reply = __bluetooth_telephony_dbus_method_send(
737 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
738 "RegisterApplication", &err, param);
743 BT_ERR("Error returned in method call");
745 g_dbus_error_strip_remote_error(err);
746 ret = __bt_telephony_get_error(err->message);
747 BT_ERR("Error here %d\n", ret);
751 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
754 g_variant_unref(reply);
755 BT_DBG("__bluetooth_telephony_register completed");
757 return BLUETOOTH_TELEPHONY_ERROR_NONE;
760 static int __bluetooth_telephony_unregister(void)
765 char *path = g_strdup(telephony_info.call_path);
770 param = g_variant_new("(s)", path);
771 reply = __bluetooth_telephony_dbus_method_send(
772 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
773 "UnregisterApplication", &err, param);
778 BT_ERR("Error returned in method call");
780 g_dbus_error_strip_remote_error(err);
781 ret = __bt_telephony_get_error(err->message);
785 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
788 g_variant_unref(reply);
789 BT_DBG("__bluetooth_telephony_unregister completed");
791 return BLUETOOTH_TELEPHONY_ERROR_NONE;
794 static void __bluetooth_telephony_init_headset_state(void)
798 gboolean status = FALSE;
802 if (telephony_dbus_info.conn == NULL) {
803 BT_ERR("Bluetooth telephony not initilized");
807 reply = __bluetooth_telephony_dbus_method_send(
808 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
809 "IsConnected", &err, NULL);
811 BT_ERR("Error returned in method call\n");
813 BT_ERR("Error message = %s", err->message);
819 g_variant_get(reply, "(b)", &status);
820 g_variant_unref(reply);
822 BT_INFO("Headset Connected Status = [%d]", status);
824 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
828 if (bluetooth_telephony_is_sco_connected())
829 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
834 static gboolean __bluetooth_telephony_is_headset(uint32_t device_class)
836 gboolean flag = FALSE;
839 switch ((device_class & 0x1f00) >> 8) {
841 switch ((device_class & 0xfc) >> 2) {
859 /* Tizen Wearable device */
861 switch ((device_class & 0xfc) >> 2) {
862 case 0x01: /* Wrist Watch */
870 BT_DBG("[%d]", flag);
875 static gboolean __bluetooth_telephony_is_headset_by_uuid(gchar **uuids)
879 unsigned int service = 0;
883 retv_if(uuids == NULL, FALSE);
885 for (i = 0; uuids[i] != NULL; i++) {
886 parts = g_strsplit(uuids[i], "-", -1);
888 if (parts == NULL || parts[0] == NULL) {
893 service = g_ascii_strtoull(parts[0], NULL, 16);
896 if (service == BLUETOOTH_HS_PROFILE_UUID ||
897 service == BLUETOOTH_HF_PROFILE_UUID)
906 static int __bluetooth_telephony_get_connected_device(void)
908 GDBusConnection *conn;
909 GDBusProxy *headset_agent_proxy = NULL;
910 GDBusProxy *manager_proxy = NULL;
911 GDBusProxy *proxy = NULL;
912 GVariant *reply = NULL;
913 GVariant *getall = NULL;
914 GVariant *isPlayingReply = NULL;
915 GVariant *isConnectedReply = NULL;
916 GVariant *param = NULL;
917 GVariant *var_path = NULL;
918 GVariant *path_values = NULL;
919 GVariant *value = NULL;
920 GError *error = NULL;
922 GVariantIter iter_path;
923 GVariantIter property_iter;
924 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
927 conn = _bt_gdbus_get_system_gconn();
928 retv_if(conn == NULL, BLUETOOTH_TELEPHONY_ERROR_INTERNAL);
930 manager_proxy = g_dbus_proxy_new_sync(
931 conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
932 BLUEZ_SERVICE_NAME, "/",
933 BLUEZ_MANAGER_INTERFACE, NULL, &error);
934 if (manager_proxy == NULL) {
935 BT_ERR("Unable to allocate new proxy \n");
936 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
938 g_dbus_error_strip_remote_error(error);
939 ret = __bt_telephony_get_error(error->message);
940 BT_ERR("Error here %d\n", ret);
946 /* Synchronous call */
947 reply = g_dbus_proxy_call_sync(manager_proxy, "GetManagedObjects", NULL,
948 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
949 g_object_unref(manager_proxy);
952 BT_ERR("Can't get managed objects");
953 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
955 g_dbus_error_strip_remote_error(error);
956 ret = __bt_telephony_get_error(error->message);
957 BT_ERR("Error here %d\n", ret);
963 /* signature of GetManagedObjects: a{oa{sa{sv}}} */
964 g_variant_iter_init(&iter, reply);
966 while ((param = g_variant_iter_next_value(&iter))) {
967 g_variant_iter_init(&iter_path, param);
969 while ((var_path = g_variant_iter_next_value(&iter_path))) {
971 uint32_t device_class = 0;
972 gboolean playing = FALSE;
973 gboolean connected = FALSE;
974 char *object_path = NULL;
975 gchar *address = NULL;
977 gchar **uuids = NULL;
978 GVariant *getall_param = NULL;
980 g_variant_get(var_path, "{&o*}", &object_path,
982 g_variant_unref(path_values); /* path_values unused*/
984 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
985 G_DBUS_PROXY_FLAGS_NONE, NULL,
986 BLUEZ_SERVICE_NAME, object_path,
987 BLUEZ_PROPERTIES_INTERFACE, NULL, &error);
989 BT_ERR("Unable to allocate new proxy \n");
990 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
992 g_dbus_error_strip_remote_error(error);
993 ret = __bt_telephony_get_error(error->message);
994 BT_ERR("Error here %d\n", ret);
1001 getall_param = g_variant_new("s", BLUEZ_DEVICE_INTERFACE);
1002 getall = g_dbus_proxy_call_sync(proxy,
1003 "GetAll", getall_param,
1004 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1005 g_object_unref(proxy);
1008 BT_ERR("Can't get managed objects");
1009 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1011 g_dbus_error_strip_remote_error(error);
1012 ret = __bt_telephony_get_error(error->message);
1013 BT_ERR("Error here %d\n", ret);
1014 g_error_free(error);
1019 g_variant_iter_init(&property_iter, getall);
1021 while (g_variant_iter_loop(&property_iter, "{&sv}", &key, &value)) {
1022 if (!g_strcmp0(key, "Class")) {
1023 device_class = g_variant_get_uint32(value);
1024 BT_DBG("Device Class: %d", device_class);
1025 } else if (!g_strcmp0(key, "UUID")) {
1027 uuids = (gchar **)g_variant_get_strv(value, &len);
1028 BT_DBG_UUID(uuids, len, i);
1029 } else if (!g_strcmp0(key, "Address")) {
1030 address = (gchar *)g_variant_get_string(
1033 BT_DBG("Device Class: %s", address);
1035 g_variant_unref(value);
1037 g_variant_unref(getall);
1039 if (device_class == 0) {
1040 BT_DBG("COD is NULL (maybe paired by nfc)... Checking UUIDs");
1041 if (!__bluetooth_telephony_is_headset_by_uuid(uuids)) {
1042 BT_DBG("UUID checking completed. None HF device");
1045 BT_DBG("UUID checking completed. HF device");
1047 if (!__bluetooth_telephony_is_headset(device_class))
1051 /* this is headset; Check for Connection */
1052 headset_agent_proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1053 G_DBUS_PROXY_FLAGS_NONE, NULL,
1054 HFP_AGENT_SERVICE, object_path,
1055 HFP_AGENT_INTERFACE, NULL, &error);
1056 if (headset_agent_proxy == NULL) {
1057 BT_ERR("Unable to allocate new headset_agent_proxy");
1058 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1060 g_dbus_error_strip_remote_error(error);
1061 ret = __bt_telephony_get_error(error->message);
1062 BT_ERR("Error here %d\n", ret);
1063 g_error_free(error);
1068 isConnectedReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1069 "IsConnected", NULL,
1070 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1073 if (!isConnectedReply) {
1074 BT_ERR("Can't get managed objects");
1075 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1077 g_dbus_error_strip_remote_error(error);
1078 ret = __bt_telephony_get_error(error->message);
1079 BT_ERR("Error here %d\n", ret);
1080 g_error_free(error);
1084 connected = g_variant_get_boolean(isConnectedReply);
1085 g_variant_unref(isConnectedReply);
1088 g_strlcpy(telephony_info.address,
1090 sizeof(telephony_info.address));
1092 isPlayingReply = g_dbus_proxy_call_sync(headset_agent_proxy,
1094 G_DBUS_CALL_FLAGS_NONE,
1096 if (!isPlayingReply) {
1097 BT_ERR("Can't get managed objects");
1098 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1100 g_dbus_error_strip_remote_error(error);
1101 ret = __bt_telephony_get_error(error->message);
1102 BT_ERR("Error here %d\n", ret);
1103 g_error_free(error);
1106 playing = g_variant_get_boolean(isPlayingReply);
1107 g_variant_unref(isPlayingReply);
1110 telephony_info.headset_state =
1111 BLUETOOTH_STATE_PLAYING;
1113 telephony_info.headset_state =
1114 BLUETOOTH_STATE_CONNECTED;
1121 g_object_unref(headset_agent_proxy);
1122 g_variant_unref(var_path);
1124 g_variant_unref(param);
1128 if (headset_agent_proxy)
1129 g_object_unref(headset_agent_proxy);
1131 g_variant_unref(reply);
1133 g_variant_unref(var_path);
1135 g_variant_unref(param);
1140 static GDBusProxy *__bluetooth_telephony_get_connected_device_proxy(void)
1142 GDBusProxy *proxy = NULL;
1143 GError *error = NULL;
1147 if (strlen(telephony_info.address) == 0)
1148 __bluetooth_telephony_get_connected_device();
1150 if (strlen(telephony_info.address) == 0)
1153 proxy = g_dbus_proxy_new_sync(telephony_dbus_info.conn,
1154 G_DBUS_PROXY_FLAGS_NONE, NULL,
1155 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1156 HFP_AGENT_INTERFACE, NULL, &error);
1157 if (proxy == NULL) {
1158 BT_ERR("Unable to allocate new proxy");
1160 g_dbus_error_strip_remote_error(error);
1161 ret = __bt_telephony_get_error(error->message);
1162 BT_ERR("Error here %d\n", ret);
1163 g_error_free(error);
1172 int __bt_telephony_subscribe_adapter_signal(GDBusConnection *conn,
1178 static guint subscribe_adapter_id = 0;
1180 if (subscribe == TRUE) {
1181 if (subscribe_adapter_id == 0) {
1182 subscribe_adapter_id = g_dbus_connection_signal_subscribe(conn,
1183 NULL, "org.freedesktop.DBus.ObjectManager",
1184 "InterfacesAdded", NULL, NULL, 0,
1185 __bt_telephony_adapter_filter,
1188 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1190 if (subscribe_adapter_id > 0) {
1191 g_dbus_connection_signal_unsubscribe(conn,
1192 subscribe_adapter_id);
1193 subscribe_adapter_id = 0;
1195 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1199 int __bt_telephony_event_subscribe_signal(GDBusConnection *conn,
1205 static guint subscribe_event1_id = 0;
1206 static guint subscribe_event2_id = 0;
1207 static guint subscribe_event3_id = 0;
1208 static guint subscribe_event4_id = 0;
1209 static guint subscribe_event5_id = 0;
1210 static guint subscribe_event6_id = 0;
1212 if (subscribe == TRUE) {
1213 if (subscribe_event1_id == 0) {
1214 subscribe_event1_id = g_dbus_connection_signal_subscribe(conn,
1215 NULL, BLUEZ_HEADSET_INTERFACE,
1216 "PropertyChanged", NULL, NULL, 0,
1217 __bluetooth_telephony_event_filter,
1220 if (subscribe_event2_id == 0) {
1221 subscribe_event2_id = g_dbus_connection_signal_subscribe(conn,
1222 NULL, HFP_AGENT_SERVICE,
1223 HFP_NREC_STATUS_CHANGE, NULL, NULL, 0,
1224 __bluetooth_telephony_event_filter,
1228 if (subscribe_event3_id == 0) {
1229 subscribe_event3_id = g_dbus_connection_signal_subscribe(conn,
1230 NULL, HFP_AGENT_SERVICE,
1231 HFP_ANSWER_CALL, NULL, NULL, 0,
1232 __bluetooth_telephony_event_filter,
1235 if (subscribe_event4_id == 0) {
1236 subscribe_event4_id = g_dbus_connection_signal_subscribe(conn,
1237 NULL, HFP_AGENT_SERVICE,
1238 HFP_REJECT_CALL, NULL, NULL, 0,
1239 __bluetooth_telephony_event_filter,
1242 if (subscribe_event5_id == 0) {
1243 subscribe_event5_id = g_dbus_connection_signal_subscribe(conn,
1244 NULL, HFP_AGENT_SERVICE,
1245 HFP_RELEASE_CALL, NULL, NULL, 0,
1246 __bluetooth_telephony_event_filter,
1249 if (subscribe_event6_id == 0) {
1250 subscribe_event6_id = g_dbus_connection_signal_subscribe(conn,
1251 NULL, HFP_AGENT_SERVICE,
1252 HFP_THREEWAY_CALL, NULL, NULL, 0,
1253 __bluetooth_telephony_event_filter,
1257 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1259 if (subscribe_event1_id > 0) {
1260 g_dbus_connection_signal_unsubscribe(conn,
1261 subscribe_event1_id);
1262 subscribe_event1_id = 0;
1264 if (subscribe_event2_id > 0) {
1265 g_dbus_connection_signal_unsubscribe(conn,
1266 subscribe_event2_id);
1267 subscribe_event2_id = 0;
1269 if (subscribe_event3_id > 0) {
1270 g_dbus_connection_signal_unsubscribe(conn,
1271 subscribe_event3_id);
1272 subscribe_event3_id = 0;
1274 if (subscribe_event4_id > 0) {
1275 g_dbus_connection_signal_unsubscribe(conn,
1276 subscribe_event4_id);
1277 subscribe_event4_id = 0;
1279 if (subscribe_event5_id > 0) {
1280 g_dbus_connection_signal_unsubscribe(conn,
1281 subscribe_event5_id);
1282 subscribe_event5_id = 0;
1284 if (subscribe_event6_id > 0) {
1285 g_dbus_connection_signal_unsubscribe(conn,
1286 subscribe_event6_id);
1287 subscribe_event6_id = 0;
1289 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1293 BT_EXPORT_API int bluetooth_telephony_init(bt_telephony_func_ptr cb,
1296 bluetooth_device_address_t loc_address = { {0} };
1297 char src_address[BT_ADDRESS_STRING_SIZE] = { 0 };
1298 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1299 GError *error = NULL;
1303 if (is_initialized == TRUE) {
1304 BT_ERR("Bluetooth telephony already initilized");
1305 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1308 is_initialized = TRUE;
1310 telephony_dbus_info.conn = _bt_gdbus_init_system_gconn();
1311 if (!telephony_dbus_info.conn) {
1312 is_initialized = FALSE;
1313 BT_ERR("Could not get DBus Connection");
1314 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1318 snprintf(telephony_info.call_path, sizeof(telephony_info.call_path),
1319 CSD_CALL_APP_PATH, getpid());
1320 BT_INFO("Call Path = %s", telephony_info.call_path);
1321 memset(telephony_info.address, 0x00, sizeof(telephony_info.address));
1323 if (__bluetooth_telephony_proxy_init()) {
1324 BT_ERR("__bluetooth_telephony_proxy_init failed\n");
1325 telephony_dbus_info.conn = NULL;
1326 is_initialized = FALSE;
1327 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1330 telephony_dbus_info.manager_proxy = g_dbus_proxy_new_sync(
1331 telephony_dbus_info.conn,
1332 G_DBUS_PROXY_FLAGS_NONE, NULL,
1333 BLUEZ_SERVICE_NAME, "/",
1334 BLUEZ_MANAGER_INTERFACE, NULL, &error);
1335 if (telephony_dbus_info.manager_proxy == NULL) {
1336 BT_ERR("Could not create a manager proxy");
1337 __bluetooth_telephony_proxy_deinit();
1338 telephony_dbus_info.conn = NULL;
1339 is_initialized = FALSE;
1341 g_dbus_error_strip_remote_error(error);
1342 ret = __bt_telephony_get_error(error->message);
1343 BT_ERR("Error here %d\n", ret);
1344 g_error_free(error);
1347 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1350 telephony_dbus_info.dbus_proxy = g_dbus_proxy_new_sync(
1351 telephony_dbus_info.conn,
1352 G_DBUS_PROXY_FLAGS_NONE, NULL,
1353 BT_EVENT_FREEDESKTOP, BT_FREEDESKTOP_PATH,
1354 BT_EVENT_FREEDESKTOP, NULL, &error);
1355 if (NULL == telephony_dbus_info.dbus_proxy) {
1356 __bluetooth_telephony_proxy_deinit();
1357 telephony_dbus_info.conn = NULL;
1358 g_object_unref(telephony_dbus_info.manager_proxy);
1359 telephony_dbus_info.manager_proxy = NULL;
1360 is_initialized = FALSE;
1361 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1364 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, TRUE) != 0) {
1365 BT_ERR("Fail to Subscribe Adapter Signal");
1369 /*Callback and user applicaton data*/
1370 telephony_info.cb = cb;
1371 telephony_info.user_data = user_data;
1372 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1374 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, TRUE) != 0) {
1375 BT_ERR("Fail to Subscribe telephony event Signal");
1379 if (bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED)
1380 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1382 /*Bluetooth is active, therefore set the flag */
1385 ret = bluetooth_get_local_address(&loc_address);
1386 if (ret != BLUETOOTH_ERROR_NONE) {
1387 BT_ERR("Fail to get local address\n");
1388 ret = BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1391 _bt_convert_addr_type_to_string(src_address, loc_address.addr);
1392 src_addr = g_strdup(src_address);
1394 ret = __bluetooth_telephony_register();
1395 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1396 BT_ERR("__bluetooth_telephony_register failed\n");
1400 if (TIZEN_PROFILE_WEARABLE || TIZEN_PROFILE_IVI)
1401 __bluetooth_telephony_init_headset_state();
1406 bluetooth_telephony_deinit();
1410 BT_EXPORT_API int bluetooth_telephony_deinit(void)
1413 BT_TELEPHONY_CHECK_INITIALIZED();
1415 is_initialized = FALSE;
1417 if (__bt_telephony_event_subscribe_signal(telephony_dbus_info.conn, FALSE) != 0)
1418 BT_ERR("Fail to UnSubscribe telephony event Signal");
1420 if (bluetooth_check_adapter() != BLUETOOTH_ADAPTER_DISABLED ||
1421 bluetooth_check_adapter_le() != BLUETOOTH_ADAPTER_LE_DISABLED)
1422 __bluetooth_telephony_unregister();
1424 __bluetooth_telephony_proxy_deinit();
1426 telephony_info.cb = NULL;
1427 telephony_info.user_data = NULL;
1428 telephony_info.call_count = 0;
1429 telephony_info.headset_state = BLUETOOTH_STATE_DISCONNETED;
1431 /* Remove BT enabled signal */
1432 if (__bt_telephony_subscribe_adapter_signal(telephony_dbus_info.conn, FALSE) != 0)
1433 BT_ERR("Fail to UnSubscribe Adapter event Signal");
1438 if (telephony_dbus_info.manager_proxy != NULL) {
1439 g_object_unref(telephony_dbus_info.manager_proxy);
1440 telephony_dbus_info.manager_proxy = NULL;
1443 if (telephony_dbus_info.conn != NULL)
1444 telephony_dbus_info.conn = NULL;
1446 if (telephony_dbus_info.dbus_proxy != NULL) {
1447 g_object_unref(telephony_dbus_info.dbus_proxy);
1448 telephony_dbus_info.dbus_proxy = NULL;
1452 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1455 BT_EXPORT_API gboolean bluetooth_telephony_is_sco_connected(void)
1459 gboolean status = FALSE;
1463 retv_if(is_initialized == FALSE, FALSE);
1464 retv_if(bluetooth_check_adapter() == BLUETOOTH_ADAPTER_DISABLED, FALSE);
1466 reply = __bluetooth_telephony_dbus_method_send(
1467 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1468 "IsPlaying", &err, NULL);
1471 BT_ERR("Error returned in method call\n");
1473 BT_ERR("Error message = %s", err->message);
1478 g_variant_get(reply, "(b)", &status);
1479 g_variant_unref(reply);
1481 if (TIZEN_PROFILE_WEARABLE || TIZEN_PROFILE_IVI)
1482 if (status == TRUE && telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1483 telephony_info.headset_state = BLUETOOTH_STATE_PLAYING;
1485 BT_INFO("SCO Connected Status = [%d]", status);
1489 BT_EXPORT_API int bluetooth_telephony_is_nrec_enabled(gboolean *status)
1494 GVariant *param_inner;
1498 BT_TELEPHONY_CHECK_INITIALIZED();
1499 BT_TELEPHONY_CHECK_ENABLED();
1502 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1504 if (telephony_info.headset_state == BLUETOOTH_STATE_DISCONNETED)
1505 return BLUETOOTH_TELEPHONY_ERROR_AUDIO_NOT_CONNECTED;
1507 reply = __bluetooth_telephony_dbus_method_send(
1508 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1509 "GetProperties", &err, NULL);
1512 BT_ERR("Error returned in method call\n");
1514 BT_DBG("Error message = %s", err->message);
1517 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1520 g_variant_iter_init(&iter, reply);
1521 while ((param_inner = g_variant_iter_next_value(&iter))) {
1524 value = g_variant_lookup_value(param_inner,
1525 "nrec", G_VARIANT_TYPE_BOOLEAN);
1527 BT_DBG("Property NREC Found");
1528 *status = g_variant_get_boolean(value);
1529 BT_DBG("NREC status = [%d]", *status);
1530 g_variant_unref(value);
1531 g_variant_unref(param_inner);
1534 g_variant_unref(param_inner);
1536 BT_DBG("NREC status = [%d]", *status);
1537 g_variant_unref(reply);
1540 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1543 BT_EXPORT_API int bluetooth_telephony_is_wbs_mode(gboolean *status)
1549 GVariant *param_inner;
1553 BT_TELEPHONY_CHECK_INITIALIZED();
1554 BT_TELEPHONY_CHECK_ENABLED();
1557 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1561 reply = __bluetooth_telephony_dbus_method_send(
1562 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1563 "GetProperties", &err, NULL);
1566 BT_ERR("Error returned in method call");
1568 BT_ERR("Error message = %s", err->message);
1571 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1574 g_variant_iter_init(&iter, reply);
1575 while ((param_inner = g_variant_iter_next_value(&iter))) {
1578 value = g_variant_lookup_value(param_inner,
1579 "codec", G_VARIANT_TYPE_UINT32);
1581 BT_DBG("Property CODEC Found");
1582 codec = g_variant_get_uint32(value);
1583 g_variant_unref(value);
1584 BT_DBG("Codec = [%d]", codec);
1586 *status = codec == BT_MSBC_CODEC_ID ? TRUE : FALSE;
1587 BT_DBG("NREC status = [%d]", *status);
1588 g_variant_unref(value);
1589 g_variant_unref(param_inner);
1592 g_variant_unref(param_inner);
1595 g_variant_unref(reply);
1596 BT_DBG("MSBC status = [%d]", *status);
1599 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1602 BT_EXPORT_API int bluetooth_telephony_send_vendor_cmd(const char *cmd)
1604 GError *error = NULL;
1605 GVariant *reply, *parameters;
1606 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
1610 BT_TELEPHONY_CHECK_INITIALIZED();
1611 BT_TELEPHONY_CHECK_ENABLED();
1613 BT_DBG("Send Vendor %s", cmd);
1615 if (telephony_dbus_info.proxy == NULL)
1616 telephony_dbus_info.proxy =
1617 __bluetooth_telephony_get_connected_device_proxy();
1619 if (telephony_dbus_info.proxy == NULL)
1620 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1622 parameters = g_variant_new("s", cmd);
1623 reply = g_dbus_proxy_call_sync(telephony_dbus_info.proxy,
1624 "SendVendorAtCmd", parameters,
1625 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1627 g_variant_unref(reply);
1630 g_dbus_error_strip_remote_error(error);
1631 ret = __bt_telephony_get_error(error->message);
1632 BT_ERR("Error here %d\n", ret);
1633 g_error_free(error);
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 g_dbus_error_strip_remote_error(err);
1662 ret = __bt_telephony_get_error(err->message);
1666 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1669 g_variant_unref(reply);
1671 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1674 BT_EXPORT_API int bluetooth_telephony_stop_voice_recognition(void)
1680 gboolean state = FALSE;
1684 BT_TELEPHONY_CHECK_INITIALIZED();
1685 BT_TELEPHONY_CHECK_ENABLED();
1687 param = g_variant_new("(b)", &state);
1688 reply = __bluetooth_telephony_dbus_method_send(
1689 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1690 "SetVoiceDial", &err, param);
1693 BT_ERR("Error returned in method call\n");
1695 g_dbus_error_strip_remote_error(err);
1696 ret = __bt_telephony_get_error(err->message);
1700 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1703 g_variant_unref(reply);
1706 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1709 static void __bluetooth_telephony_sco_start_cb(GDBusProxy *proxy,
1710 GAsyncResult *res, gpointer user_data)
1712 GError *error = NULL;
1713 GVariant *value = NULL;
1715 value = g_dbus_proxy_call_finish(proxy, res, &error);
1716 if (value == NULL) {
1717 if (error != NULL) {
1718 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1719 error->code, error->message);
1720 g_clear_error(&error);
1722 BT_ERR("SCo Start Failed");
1724 g_object_unref(proxy);
1728 BT_DBG("sco_start_cb : -");
1729 g_object_unref(proxy);
1730 g_variant_unref(value);
1733 BT_EXPORT_API int bluetooth_telephony_audio_open(void)
1735 GDBusConnection *conn;
1742 BT_TELEPHONY_CHECK_INITIALIZED();
1743 BT_TELEPHONY_CHECK_ENABLED();
1745 /* Because this API is async call, so can't use dbus SMACK */
1746 if (__bt_telephony_check_privilege() ==
1747 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1748 BT_ERR("Don't have a privilege to use this API");
1749 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1752 conn = _bt_gdbus_get_system_gconn();
1754 BT_DBG("No System Bus found\n");
1755 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1758 if (telephony_info.headset_state == BLUETOOTH_STATE_PLAYING)
1759 return BLUETOOTH_TELEPHONY_ERROR_ALREADY_CONNECTED;
1761 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1762 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1763 HFP_AGENT_INTERFACE, NULL, &err);
1764 if (proxy == NULL) {
1765 BT_ERR("Unable to allocate new proxy");
1767 g_dbus_error_strip_remote_error(err);
1768 ret = __bt_telephony_get_error(err->message);
1769 BT_ERR("Error here %d\n", ret);
1773 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1776 g_dbus_proxy_call(proxy, "Play", NULL, G_DBUS_CALL_FLAGS_NONE,
1777 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_start_cb, NULL);
1780 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1783 static void __bluetooth_telephony_sco_close_cb(GDBusProxy *proxy,
1784 GAsyncResult *res, gpointer user_data)
1786 GError *error = NULL;
1787 GVariant *value = NULL;
1789 value = g_dbus_proxy_call_finish(proxy, res, &error);
1790 if (value == NULL) {
1791 if (error != NULL) {
1792 BT_ERR("sco_close_cb error. errCode[%x],message[%s]",
1793 error->code, error->message);
1794 g_clear_error(&error);
1796 BT_ERR("SCo close Failed");
1798 g_object_unref(proxy);
1802 BT_DBG("sco_close_cb : -");
1803 g_object_unref(proxy);
1804 g_variant_unref(value);
1806 BT_EXPORT_API int bluetooth_telephony_audio_close(void)
1808 GDBusConnection *conn;
1815 BT_TELEPHONY_CHECK_INITIALIZED();
1816 BT_TELEPHONY_CHECK_ENABLED();
1818 /* Because this API is async call, so can't use dbus SMACK */
1819 if (__bt_telephony_check_privilege() ==
1820 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1821 BT_ERR("Don't have a privilege to use this API");
1822 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
1825 conn = _bt_gdbus_get_system_gconn();
1827 BT_DBG("No System Bus found\n");
1828 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1831 if (telephony_info.headset_state != BLUETOOTH_STATE_PLAYING)
1832 return BLUETOOTH_TELEPHONY_ERROR_NOT_CONNECTED;
1834 proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
1835 HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1836 HFP_AGENT_INTERFACE, NULL, &err);
1837 if (proxy == NULL) {
1838 BT_ERR("Unable to allocate new proxy");
1840 g_dbus_error_strip_remote_error(err);
1841 ret = __bt_telephony_get_error(err->message);
1842 BT_ERR("Error here %d\n", ret);
1846 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
1849 g_dbus_proxy_call(proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE,
1850 -1, NULL, (GAsyncReadyCallback)__bluetooth_telephony_sco_close_cb, NULL);
1852 telephony_info.headset_state = BLUETOOTH_STATE_CONNECTED;
1855 return BLUETOOTH_TELEPHONY_ERROR_NONE;
1858 BT_EXPORT_API int bluetooth_telephony_call_remote_ringing(unsigned int call_id)
1862 BT_TELEPHONY_CHECK_INITIALIZED();
1863 BT_TELEPHONY_CHECK_ENABLED();
1866 BT_DBG("call_id = [%d]", call_id);
1868 /*Make sure SCO is already connected */
1869 ret = __bluetooth_telephony_send_call_status(
1870 CSD_CALL_STATUS_MO_ALERTING, call_id, NULL);
1872 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1873 BT_ERR("send call status Failed = [%d]", ret);
1879 BT_EXPORT_API int bluetooth_telephony_call_answered(unsigned int call_id,
1880 unsigned int bt_audio)
1885 BT_DBG("call_id = [%d]", call_id);
1887 BT_TELEPHONY_CHECK_INITIALIZED();
1888 BT_TELEPHONY_CHECK_ENABLED();
1890 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1892 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
1893 BT_ERR("send call status Failed = [%d]", ret);
1898 if (!bluetooth_telephony_is_sco_connected()) {
1899 ret = bluetooth_telephony_audio_open();
1900 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1901 BT_ERR("Audio connection call Failed[%d]", ret);
1909 BT_EXPORT_API int bluetooth_telephony_call_end(unsigned int call_id)
1914 BT_DBG("call_id = [%d]", call_id);
1916 BT_TELEPHONY_CHECK_INITIALIZED();
1917 BT_TELEPHONY_CHECK_ENABLED();
1919 if (telephony_info.call_count > 0)
1920 telephony_info.call_count = telephony_info.call_count - 1;
1922 if (telephony_info.call_count == 0) {
1923 if (bluetooth_telephony_is_sco_connected()) {
1924 ret = bluetooth_telephony_audio_close();
1925 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1926 BT_ERR(" Failed = [%d]", ret);
1930 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_MT_RELEASE,
1932 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1933 BT_ERR("send call status Failed = [%d]", ret);
1939 BT_EXPORT_API int bluetooth_telephony_call_held(unsigned int call_id)
1944 BT_DBG("call_id = [%d]", call_id);
1946 BT_TELEPHONY_CHECK_INITIALIZED();
1947 BT_TELEPHONY_CHECK_ENABLED();
1949 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_HOLD,
1951 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1952 BT_ERR("send call status Failed = [%d]", ret);
1958 BT_EXPORT_API int bluetooth_telephony_call_retrieved(unsigned int call_id)
1963 BT_DBG("call_id = [%d]", call_id);
1965 BT_TELEPHONY_CHECK_INITIALIZED();
1966 BT_TELEPHONY_CHECK_ENABLED();
1968 ret = __bluetooth_telephony_send_call_status(CSD_CALL_STATUS_ACTIVE,
1970 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
1971 BT_ERR("send call status Failed = [%d]", ret);
1977 BT_EXPORT_API int bluetooth_telephony_call_swapped(void *call_list,
1978 unsigned int call_count)
1982 GList *list = call_list;
1983 bt_telephony_call_status_info_t *call_status;
1987 BT_TELEPHONY_CHECK_INITIALIZED();
1988 BT_TELEPHONY_CHECK_ENABLED();
1991 BT_ERR("call_list is invalid");
1992 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
1995 /* Because this API is async call, so can't use dbus SMACK */
1996 if (__bt_telephony_check_privilege() ==
1997 BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED) {
1998 BT_ERR("Don't have a privilege to use this API");
1999 return BLUETOOTH_TELEPHONY_ERROR_PERMISSION_DENIED;
2002 BT_DBG(" call_count = [%d]", call_count);
2004 for (i = 0; i < call_count; i++) {
2005 call_status = g_list_nth_data(list, i);
2007 if (NULL == call_status)
2010 BT_DBG(" %d : Call id [%d] status[%d]", i,
2011 call_status->call_id,
2012 call_status->call_status);
2014 if (NULL != call_status->phone_number)
2015 DBG_SECURE("Number [%s]", call_status->phone_number);
2017 switch (call_status->call_status) {
2018 case BLUETOOTH_CALL_STATE_HELD:
2019 ret = __bluetooth_telephony_send_call_status(
2020 CSD_CALL_STATUS_HOLD,
2021 call_status->call_id,
2022 call_status->phone_number);
2023 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2024 BT_ERR("Failed = %d", ret);
2029 case BLUETOOTH_CALL_STATE_CONNECTED:
2030 ret = __bluetooth_telephony_send_call_status(
2031 CSD_CALL_STATUS_ACTIVE,
2032 call_status->call_id,
2033 call_status->phone_number);
2034 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2035 BT_ERR("Failed = [%d]", ret);
2041 if ((call_status->call_status <
2042 BLUETOOTH_CALL_STATE_NONE) ||
2043 (call_status->call_status >=
2044 BLUETOOTH_CALL_STATE_ERROR)) {
2045 BT_ERR("Unknown Call state");
2046 return BLUETOOTH_TELEPHONY_ERROR_NOT_AVAILABLE;
2052 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2055 BT_EXPORT_API int bluetooth_telephony_set_call_status(void *call_list,
2056 unsigned int call_count)
2062 ret = bluetooth_telephony_call_swapped(call_list, call_count);
2064 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE) {
2065 BT_ERR("Failed = [%d]", ret);
2069 telephony_info.call_count = call_count;
2072 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2075 BT_EXPORT_API int bluetooth_telephony_indicate_outgoing_call(
2076 const char *ph_number, unsigned int call_id,
2077 unsigned int bt_audio)
2082 const char *path = telephony_info.call_path;
2083 int ret = BLUETOOTH_TELEPHONY_ERROR_NONE;
2087 BT_TELEPHONY_CHECK_INITIALIZED();
2088 BT_TELEPHONY_CHECK_ENABLED();
2090 if (NULL == ph_number)
2091 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2093 param = g_variant_new("(ssi)", path, ph_number, call_id);
2094 reply = __bluetooth_telephony_dbus_method_send(
2095 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2096 "OutgoingCall", &err, param);
2099 BT_ERR("Error returned in method call\n");
2101 g_dbus_error_strip_remote_error(err);
2102 ret = __bt_telephony_get_error(err->message);
2106 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2109 g_variant_unref(reply);
2111 telephony_info.call_count++;
2112 BT_DBG(" ag_info.ag_call_count = [%d]", telephony_info.call_count);
2115 if (!bluetooth_telephony_is_sco_connected()) {
2116 ret = bluetooth_telephony_audio_open();
2118 BT_ERR(" Audio connection Failed = %d", ret);
2126 BT_EXPORT_API int bluetooth_telephony_indicate_incoming_call(
2127 const char *ph_number, unsigned int call_id)
2132 const char *path = telephony_info.call_path;
2137 BT_TELEPHONY_CHECK_INITIALIZED();
2138 BT_TELEPHONY_CHECK_ENABLED();
2140 if (NULL == ph_number)
2141 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2143 param = g_variant_new("(ssi)", path, ph_number, call_id);
2144 reply = __bluetooth_telephony_dbus_method_send(
2145 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2146 "IncomingCall", &err, param);
2149 BT_ERR("Error returned in method call\n");
2151 g_dbus_error_strip_remote_error(err);
2152 ret = __bt_telephony_get_error(err->message);
2156 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2159 g_variant_unref(reply);
2160 telephony_info.call_count++;
2161 BT_DBG("telephony_info.call_count = [%d]", telephony_info.call_count);
2163 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2166 BT_EXPORT_API int bluetooth_telephony_set_speaker_gain(
2167 unsigned short speaker_gain)
2176 BT_TELEPHONY_CHECK_INITIALIZED();
2177 BT_TELEPHONY_CHECK_ENABLED();
2179 BT_DBG("set speaker_gain= [%d]", speaker_gain);
2181 param = g_variant_new("(q)", speaker_gain);
2182 reply = __bluetooth_telephony_dbus_method_send(
2183 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2184 "SetSpeakerGain", &err, param);
2187 BT_ERR("Error returned in method call\n");
2189 g_dbus_error_strip_remote_error(err);
2190 ret = __bt_telephony_get_error(err->message);
2194 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2197 g_variant_unref(reply);
2199 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2202 BT_EXPORT_API int bluetooth_telephony_get_headset_volume(
2203 unsigned int *speaker_gain)
2212 BT_TELEPHONY_CHECK_INITIALIZED();
2213 BT_TELEPHONY_CHECK_ENABLED();
2215 reply = __bluetooth_telephony_dbus_method_send(
2216 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2217 "GetSpeakerGain", &err, NULL);
2220 BT_ERR("Error returned in method call\n");
2222 g_dbus_error_strip_remote_error(err);
2223 ret = __bt_telephony_get_error(err->message);
2227 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2229 g_variant_get(reply, "(q)", &gain);
2230 *speaker_gain = gain;
2231 BT_DBG("Get speaker_gain= [%d]", *speaker_gain);
2233 g_variant_unref(reply);
2236 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2239 BT_EXPORT_API int bluetooth_telephony_is_connected(gboolean *ag_connected)
2244 gboolean ag_connected_from_bt_agent;
2246 BT_CHECK_ENABLED(return);
2248 reply = __bluetooth_telephony_dbus_method_send(
2249 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2250 "IsConnected", &err, NULL);
2253 BT_ERR("Error returned in method call\n");
2255 g_dbus_error_strip_remote_error(err);
2256 ret = __bt_telephony_get_error(err->message);
2260 return BLUETOOTH_ERROR_INTERNAL;
2262 g_variant_get(reply, "(b)", &ag_connected_from_bt_agent);
2263 *ag_connected = ag_connected_from_bt_agent;
2265 BT_DBG("Conn Status: %s", *ag_connected ? "Connected" : "Disconnected");
2267 g_variant_unref(reply);
2269 return BLUETOOTH_ERROR_NONE;
2272 BT_EXPORT_API int bluetooth_telephony_set_active_headset(const char *remote_addr)
2274 #ifdef TIZEN_BT_DUAL_HEADSET_CONNECT
2280 BT_CHECK_ENABLED(return);
2282 if (NULL == remote_addr)
2283 return BLUETOOTH_TELEPHONY_ERROR_INVALID_PARAM;
2285 param = g_variant_new("(s)", remote_addr);
2286 reply = __bluetooth_telephony_dbus_method_send(
2287 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
2288 "SwapHeadset", &err, param);
2291 BT_ERR("Error returned in method call\n");
2293 g_dbus_error_strip_remote_error(err);
2294 ret = __bt_telephony_get_error(err->message);
2298 return BLUETOOTH_TELEPHONY_ERROR_INTERNAL;
2301 g_variant_unref(reply);
2302 return BLUETOOTH_TELEPHONY_ERROR_NONE;
2304 return BLUETOOTH_ERROR_NOT_SUPPORT;
2308 static void __bt_telephony_adapter_filter(GDBusConnection *connection,
2309 const gchar *sender_name,
2310 const gchar *object_path,
2311 const gchar *interface_name,
2312 const gchar *signal_name,
2313 GVariant *parameters,
2320 if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
2321 GVariant *optional_param = NULL;
2323 g_variant_get(parameters, "(&o@a{sa{sv}})",
2324 &path, &optional_param);
2327 BT_ERR("Invalid adapter path");
2331 BT_INFO("Adapter Path = [%s]", path);
2332 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
2333 if (__bt_telephony_get_src_addr(optional_param))
2334 BT_ERR("Fail to get the local adapter address");
2336 ret = __bluetooth_telephony_register();
2337 if (ret != BLUETOOTH_TELEPHONY_ERROR_NONE)
2338 BT_ERR("__bluetooth_telephony_register failed");
2341 g_variant_unref(optional_param);
2347 static int __bt_telephony_get_src_addr(GVariant *value)
2350 GVariant *param = NULL;
2353 /* signature a{sa{sv}} */
2354 g_variant_iter_init(&iter, value);
2355 while ((param = g_variant_iter_next_value(&iter))) {
2356 char *interface_name;
2357 GVariant *interface_var = NULL;
2358 GVariant *param_inner = NULL;
2360 g_variant_get(param, "{&s*}", &interface_name, &interface_var);
2361 g_variant_unref(param);
2363 BT_DBG("interface_name: %s", interface_name);
2364 /* format of interface_var: a{sv}*/
2365 if (strcasecmp(interface_name, BLUEZ_ADAPTER_INTERFACE) == 0) {
2366 GVariantIter iter_inner;
2368 g_variant_iter_init(&iter_inner, interface_var);
2369 while ((param_inner = g_variant_iter_next_value(&iter_inner))) {
2370 char *property_name;
2371 GVariant *property_var;
2373 g_variant_get(param_inner, "{&sv}",
2376 g_variant_unref(param_inner);
2378 if (strcasecmp(property_name, "Address") == 0) {
2379 const gchar *bd_addr;
2381 bd_addr = g_variant_get_string(
2384 src_addr = g_strdup(bd_addr);
2385 BT_DBG("Address: %s", src_addr);
2387 g_variant_unref(interface_var);
2388 g_variant_unref(property_var);
2391 g_variant_unref(property_var);
2394 g_variant_unref(interface_var);
2398 return BLUETOOTH_ERROR_NONE;