4 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <dbus/dbus-glib.h>
21 #include <dbus/dbus.h>
25 #if !defined(LIBNOTIFY_SUPPORT) && !defined(LIBNOTIFICATION_SUPPORT)
26 #include <syspopup_caller.h>
29 #include "bluetooth-api.h"
30 #include "bt-internal-types.h"
32 #include "bt-service-audio.h"
33 #include "bt-service-adapter.h"
34 #include "bt-service-common.h"
35 #include "bt-service-event.h"
36 #include "bt-service-util.h"
41 char device_address[BT_ADDRESS_STRING_SIZE + 1];
42 } bt_connected_headset_data_t;
44 static GList *g_connected_list;
46 static bt_headset_wait_t *g_wait_data;
48 static void __bt_remove_device_from_wait_list();
50 static void __bt_free_wait_data();
52 static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call,
55 GError *g_error = NULL;
56 GArray *out_param1 = NULL;
57 GArray *out_param2 = NULL;
58 int result = BLUETOOTH_ERROR_NONE;
59 bt_function_data_t *func_data;
60 request_info_t *req_info;
62 dbus_g_proxy_end_call(proxy, call, &g_error, G_TYPE_INVALID);
64 g_object_unref(proxy);
66 func_data = user_data;
68 if (func_data == NULL) {
70 BT_ERR("func_data == NULL");
74 req_info = _bt_get_request_info(func_data->req_id);
75 if (req_info == NULL) {
76 BT_ERR("req_info == NULL");
83 BT_ERR("Audio Connect Dbus Call Error: %s\n", g_error->message);
85 result = BLUETOOTH_ERROR_INTERNAL;
87 /* Remove the device from the list */
88 _bt_remove_headset_from_list(BT_AUDIO_ALL, func_data->address);
90 /* Error, check if any waiting device is there */
91 if (g_wait_data == NULL)
94 if (g_strcmp0(g_wait_data->address, func_data->address) != 0) {
95 bluetooth_device_address_t device_address;
96 _bt_convert_addr_string_to_type(device_address.addr,
97 g_wait_data->address);
98 _bt_audio_connect(g_wait_data->req_id, g_wait_data->type,
99 &device_address, g_wait_data->out_param1);
102 /* Event will be sent by the event reciever */
104 if (req_info->context == NULL)
107 out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
108 out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
110 g_array_append_vals(out_param1, func_data->address,
112 g_array_append_vals(out_param2, &result, sizeof(int));
114 dbus_g_method_return(req_info->context, out_param1, out_param2);
116 g_array_free(out_param1, TRUE);
117 g_array_free(out_param2, TRUE);
119 _bt_delete_request_list(req_info->req_id);
122 g_error_free(g_error);
125 g_free(func_data->address);
130 static char *__bt_get_audio_path(bluetooth_device_address_t *address)
133 char *object_path = NULL;
134 char addr_str[BT_ADDRESS_STRING_SIZE + 1] = { 0 };
135 DBusGProxy *audio_proxy;
136 DBusGProxy *adapter_proxy;
137 DBusGConnection *g_conn;
138 GError *error = NULL;
140 retv_if(address == NULL, NULL);
142 g_conn = _bt_get_system_gconn();
143 retv_if(g_conn == NULL, NULL);
145 adapter_proxy = _bt_get_adapter_proxy();
146 retv_if(adapter_proxy == NULL, NULL);
148 _bt_convert_addr_type_to_string(addr_str, address->addr);
150 object_path = _bt_get_device_object_path(addr_str);
152 retv_if(object_path == NULL, BLUETOOTH_ERROR_NOT_FOUND);
154 audio_proxy = dbus_g_proxy_new_for_name(g_conn,
157 BT_HFP_AGENT_INTERFACE);
159 retv_if(audio_proxy == NULL, NULL);
161 g_object_unref(audio_proxy);
166 static char *__bt_get_connected_audio_path(void)
170 char *audio_path = NULL;
172 bluetooth_device_info_t info;
174 /* allocate the g_pointer_array */
175 device_list = g_array_new(FALSE, FALSE, sizeof(gchar));
177 if (_bt_get_bonded_devices(&device_list)
178 != BLUETOOTH_ERROR_NONE) {
179 g_array_free(device_list, TRUE);
183 size = device_list->len;
184 size = (device_list->len) / sizeof(bluetooth_device_info_t);
186 for (i = 0; i < size; i++) {
188 info = g_array_index(device_list,
189 bluetooth_device_info_t, i);
191 if (info.connected == TRUE) {
192 audio_path = __bt_get_audio_path(&info.device_address);
198 g_array_free(device_list, TRUE);
203 static void __bt_free_wait_data()
205 if (g_wait_data != NULL) {
206 g_free(g_wait_data->address);
212 static void __bt_remove_device_from_wait_list()
214 /* Before deleting the request update the UI */
215 GArray *out_param_1 = NULL;
216 GArray *out_param_2 = NULL;
217 int result = BLUETOOTH_ERROR_INTERNAL;
218 request_info_t *req_info;
220 req_info = _bt_get_request_info(g_wait_data->req_id);
221 if (req_info == NULL) {
222 BT_ERR("req_info == NULL");
226 out_param_1 = g_array_new(FALSE, FALSE, sizeof(gchar));
227 out_param_2 = g_array_new(FALSE, FALSE, sizeof(gchar));
228 g_array_append_vals(out_param_1, g_wait_data->address,
230 g_array_append_vals(out_param_2, &result, sizeof(int));
231 dbus_g_method_return(req_info->context,
232 out_param_1, out_param_2);
233 g_array_free(out_param_1, TRUE);
234 g_array_free(out_param_2, TRUE);
235 _bt_delete_request_list(g_wait_data->req_id);
238 static void __bt_set_headset_disconnection_type(const char *address)
240 bt_connected_headset_data_t *connected_device;
243 BT_DBG("__bt_set_headset_disconnection_type \n");
245 node = g_list_first(g_connected_list);
246 while (node != NULL) {
247 connected_device = node->data;
248 if (g_strcmp0(connected_device->device_address, address) == 0) {
249 g_wait_data->disconnection_type = connected_device->type;
252 node = g_list_next(node);
256 gboolean _bt_is_headset_type_connected(int type, char *address)
260 BT_DBG("_bt_is_headset_type_connected \n");
262 node = g_list_first(g_connected_list);
263 while (node != NULL) {
264 bt_connected_headset_data_t *connected_device = node->data;
266 if (connected_device->type & type) {
268 g_strlcpy(address, connected_device->device_address,
269 BT_ADDRESS_STRING_SIZE + 1);
273 node = g_list_next(node);
278 static gboolean __bt_is_headset_connected(int type, int req_id,
279 const char *address, GArray **out_param1)
282 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
283 bluetooth_device_address_t device_address;
285 BT_DBG("__bt_is_headset_connected \n");
287 /* Check if any other headset is connected */
288 connected = _bt_is_headset_type_connected(type, connected_address);
293 /* If already one device is waiting, remove current waiting device and add new */
294 if (g_wait_data != NULL) {
295 if (g_strcmp0(g_wait_data->address, address) != 0) {
296 __bt_remove_device_from_wait_list();
297 __bt_free_wait_data();
301 if (g_wait_data == NULL) {
302 g_wait_data = g_malloc0(sizeof(bt_headset_wait_t));
303 g_wait_data->address = g_strdup(address);
304 g_wait_data->req_id = req_id;
305 g_wait_data->type = type;
306 g_wait_data->ag_flag = FALSE;
307 g_wait_data->out_param1 = out_param1;
309 /* Set disconnection type */
310 __bt_set_headset_disconnection_type(connected_address);
313 /* Convert BD adress from string type */
314 _bt_convert_addr_string_to_type(device_address.addr, connected_address);
315 _bt_audio_disconnect(0, type, &device_address, NULL);
319 void _bt_set_audio_wait_data_flag(gboolean flag)
321 BT_DBG("_bt_set_audio_wait_data_flag \n");
322 g_wait_data->ag_flag = flag;
325 bt_headset_wait_t *_bt_get_audio_wait_data(void)
327 BT_DBG("_bt_get_audio_wait_data \n");
331 void _bt_add_headset_to_list(int type, int status, const char *address)
333 bt_connected_headset_data_t *connected_device;
334 bt_connected_headset_data_t *device;
337 BT_DBG("_bt_add_headset_to_list \n");
339 node = g_list_first(g_connected_list);
340 while (node != NULL) {
341 device = (bt_connected_headset_data_t *)node->data;
343 if (g_strcmp0(device->device_address, address) == 0) {
344 BT_DBG("Address match, update connection type \n");
345 device->type |= type;
346 device->device_state = status;
349 node = g_list_next(node);
352 connected_device = g_malloc0(sizeof(bt_connected_headset_data_t));
353 connected_device->type |= type;
354 connected_device->device_state = status;
355 g_strlcpy(connected_device->device_address, address,
356 sizeof(connected_device->device_address));
357 g_connected_list = g_list_append(g_connected_list, connected_device);
360 void _bt_remove_headset_from_list(int type, const char *address)
364 BT_DBG("_bt_remove_headset_from_list \n");
366 node = g_list_first(g_connected_list);
367 while (node != NULL) {
368 bt_connected_headset_data_t *connected_device = node->data;
370 if (g_strcmp0(connected_device->device_address, address) != 0) {
371 node = g_list_next(node);
375 BT_DBG("Address match \n");
377 BT_DBG("Connection type = %x\n", connected_device->type);
381 if (connected_device->type & BT_AUDIO_A2DP)
382 connected_device->type &= ~(BT_AUDIO_A2DP);
385 if (connected_device->type & BT_AUDIO_HSP)
386 connected_device->type &= ~(BT_AUDIO_HSP);
389 if (connected_device->type & BT_AUDIO_ALL)
390 connected_device->type &= ~(BT_AUDIO_ALL);
394 BT_DBG("Connection type = %x\n", connected_device->type);
396 if (connected_device->type == 0x00) {
397 g_connected_list = g_list_remove(g_connected_list, connected_device);
398 g_free(connected_device);
401 node = g_list_next(node);
405 int _bt_audio_connect(int request_id, int type,
406 bluetooth_device_address_t *device_address,
409 int result = BLUETOOTH_ERROR_NONE;
410 gchar *device_path = NULL;
412 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
413 bt_function_data_t *func_data;
414 DBusGProxy *adapter_proxy;
415 DBusGProxy *profile_proxy;
416 DBusGConnection *g_conn;
418 BT_CHECK_PARAMETER(device_address, return);
420 _bt_convert_addr_type_to_string(address, device_address->addr);
427 uuid = A2DP_SINK_UUID;
430 uuid = GENERIC_AUDIO_UUID;
433 BT_ERR("Unknown role");
434 result = BLUETOOTH_ERROR_INTERNAL;
438 if (__bt_is_headset_connected(type, request_id, address, out_param1))
439 return BLUETOOTH_ERROR_NONE;
441 adapter_proxy = _bt_get_adapter_proxy();
442 if (adapter_proxy == NULL) {
443 result = BLUETOOTH_ERROR_INTERNAL;
447 device_path = _bt_get_device_object_path(address);
448 if (device_path == NULL) {
449 result = BLUETOOTH_ERROR_INTERNAL;
453 g_conn = _bt_get_system_gconn();
454 if (g_conn == NULL) {
455 result = BLUETOOTH_ERROR_INTERNAL;
459 profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
460 device_path, BT_DEVICE_INTERFACE);
464 if (profile_proxy == NULL) {
465 result = BLUETOOTH_ERROR_INTERNAL;
469 func_data = g_malloc0(sizeof(bt_function_data_t));
470 func_data->address = g_strdup(address);
471 func_data->req_id = request_id;
473 if (g_strcmp0(uuid, GENERIC_AUDIO_UUID) == 0){
474 if (!dbus_g_proxy_begin_call(profile_proxy, "Connect",
475 (DBusGProxyCallNotify)__bt_audio_request_cb,
478 BT_ERR("Audio connect Dbus Call Error");
479 g_object_unref(profile_proxy);
481 g_free(func_data->address);
484 result = BLUETOOTH_ERROR_INTERNAL;
488 if (!dbus_g_proxy_begin_call(profile_proxy, "ConnectProfile",
489 (DBusGProxyCallNotify)__bt_audio_request_cb,
493 BT_ERR("Audio connect Dbus Call Error");
494 g_object_unref(profile_proxy);
496 g_free(func_data->address);
499 result = BLUETOOTH_ERROR_INTERNAL;
503 /* Add data to the connected list */
504 _bt_add_headset_to_list(type, BT_STATE_CONNECTING, address);
505 __bt_free_wait_data();
507 return BLUETOOTH_ERROR_NONE;
509 g_array_append_vals(*out_param1, address,
515 int _bt_audio_disconnect(int request_id, int type,
516 bluetooth_device_address_t *device_address,
519 int result = BLUETOOTH_ERROR_NONE;
520 gchar *device_path = NULL;
522 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
523 bt_function_data_t *func_data;
524 DBusGProxy *adapter_proxy;
525 DBusGProxy *profile_proxy;
526 DBusGConnection *g_conn;
528 BT_CHECK_PARAMETER(device_address, return);
530 _bt_convert_addr_type_to_string(address, device_address->addr);
537 uuid = A2DP_SINK_UUID;
540 uuid = GENERIC_AUDIO_UUID;
543 BT_ERR("Unknown role");
544 return BLUETOOTH_ERROR_INTERNAL;
547 adapter_proxy = _bt_get_adapter_proxy();
548 if (adapter_proxy == NULL) {
549 result = BLUETOOTH_ERROR_INTERNAL;
553 device_path = _bt_get_device_object_path(address);
554 if (device_path == NULL) {
555 result = BLUETOOTH_ERROR_INTERNAL;
559 g_conn = _bt_get_system_gconn();
560 if (g_conn == NULL) {
561 result = BLUETOOTH_ERROR_INTERNAL;
565 profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
566 device_path, BT_DEVICE_INTERFACE);
570 if (profile_proxy == NULL) {
571 result = BLUETOOTH_ERROR_INTERNAL;
575 if (g_wait_data != NULL) {
576 if (g_strcmp0(uuid, GENERIC_AUDIO_UUID) == 0){
577 if (!dbus_g_proxy_begin_call(profile_proxy,
578 "Disconnect",NULL, NULL, NULL,
580 BT_ERR("Audio disconnect Dbus Call Error");
581 g_object_unref(profile_proxy);
582 return BLUETOOTH_ERROR_INTERNAL;
585 if (!dbus_g_proxy_begin_call(profile_proxy,
586 "DisconnectProfile",NULL, NULL, NULL,
589 BT_ERR("Audio disconnect Dbus Call Error");
590 g_object_unref(profile_proxy);
591 return BLUETOOTH_ERROR_INTERNAL;
595 func_data = g_malloc0(sizeof(bt_function_data_t));
596 func_data->address = g_strdup(address);
597 func_data->req_id = request_id;
598 if (g_strcmp0(uuid, GENERIC_AUDIO_UUID) == 0){
599 if (!dbus_g_proxy_begin_call(profile_proxy,
601 (DBusGProxyCallNotify)__bt_audio_request_cb,
604 BT_ERR("Audio disconnect Dbus Call Error");
605 g_object_unref(profile_proxy);
607 g_free(func_data->address);
610 result = BLUETOOTH_ERROR_INTERNAL;
614 if (!dbus_g_proxy_begin_call(profile_proxy,
616 (DBusGProxyCallNotify)__bt_audio_request_cb,
620 BT_ERR("Audio disconnect Dbus Call Error");
621 g_object_unref(profile_proxy);
623 g_free(func_data->address);
626 result = BLUETOOTH_ERROR_INTERNAL;
632 return BLUETOOTH_ERROR_NONE;
634 g_array_append_vals(*out_param1, address,
640 int _bt_audio_get_speaker_gain(unsigned int *gain)
642 char *device_path = NULL;
643 DBusGProxy *adapter_proxy;
644 DBusGProxy *profile_proxy;
645 DBusGConnection *g_conn;
646 GHashTable *hash = NULL;
649 adapter_proxy = _bt_get_adapter_proxy();
650 retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
652 g_conn = _bt_get_system_gconn();
653 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
655 device_path = __bt_get_connected_audio_path();
656 retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
658 profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
659 device_path, BT_HFP_AGENT_INTERFACE);
663 retv_if(profile_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
665 dbus_g_proxy_call(profile_proxy, "GetProperties", NULL,
667 dbus_g_type_get_map("GHashTable",
668 G_TYPE_STRING, G_TYPE_VALUE),
669 &hash, G_TYPE_INVALID);
671 g_object_unref(profile_proxy);
673 retv_if(hash == NULL, BLUETOOTH_ERROR_INTERNAL);
675 value = g_hash_table_lookup(hash, "SpeakerGain");
676 *gain = value ? g_value_get_uint(value) : 0;
677 g_hash_table_destroy(hash);
678 return BLUETOOTH_ERROR_NONE;
681 int _bt_audio_set_speaker_gain(unsigned int gain)
683 char *device_path = NULL;
684 char *gain_str = "SpeakerGain";
685 char sig[2] = {DBUS_TYPE_UINT16, '\0'};
686 int ret = BLUETOOTH_ERROR_NONE;
688 DBusMessageIter iter;
689 DBusMessageIter value;
690 DBusConnection *conn;
692 conn = _bt_get_system_conn();
693 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
695 device_path = __bt_get_connected_audio_path();
696 retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
698 msg = dbus_message_new_method_call(BT_BLUEZ_NAME,
699 device_path, BT_HFP_AGENT_INTERFACE,
704 retv_if(msg == NULL, BLUETOOTH_ERROR_INTERNAL);
706 dbus_message_iter_init_append(msg, &iter);
707 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
709 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
711 dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT16,
713 dbus_message_iter_close_container(&iter, &value);
715 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL)
716 dbus_message_set_no_reply(msg, TRUE);
718 if (!dbus_connection_send(conn, msg, NULL)) {
719 BT_ERR("Dbus sending failed\n");
720 ret = BLUETOOTH_ERROR_INTERNAL;
722 dbus_message_unref(msg);