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 #include <syspopup_caller.h>
27 #include "bluetooth-api.h"
28 #include "bt-internal-types.h"
30 #include "bt-service-audio.h"
31 #include "bt-service-adapter.h"
32 #include "bt-service-common.h"
33 #include "bt-service-event.h"
34 #include "bt-service-util.h"
39 char device_address[BT_ADDRESS_STRING_SIZE + 1];
40 } bt_connected_headset_data_t;
42 static GList *g_connected_list;
44 static bt_headset_wait_t *g_wait_data;
46 static void __bt_remove_device_from_wait_list();
48 static void __bt_free_wait_data();
50 static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call,
53 GError *g_error = NULL;
54 GArray *out_param1 = NULL;
55 GArray *out_param2 = NULL;
56 int result = BLUETOOTH_ERROR_NONE;
57 bt_function_data_t *func_data;
58 request_info_t *req_info;
60 dbus_g_proxy_end_call(proxy, call, &g_error, G_TYPE_INVALID);
62 g_object_unref(proxy);
64 func_data = user_data;
66 if (func_data == NULL) {
68 BT_ERR("func_data == NULL");
72 req_info = _bt_get_request_info(func_data->req_id);
73 if (req_info == NULL) {
74 BT_ERR("req_info == NULL");
81 BT_ERR("Audio Connect Dbus Call Error: %s\n", g_error->message);
83 result = BLUETOOTH_ERROR_INTERNAL;
85 /* Remove the device from the list */
86 _bt_remove_headset_from_list(BT_AUDIO_ALL, func_data->address);
88 /* Error, check if any waiting device is there */
89 if (g_wait_data == NULL)
92 if (g_strcmp0(g_wait_data->address, func_data->address) != 0) {
93 bluetooth_device_address_t device_address;
94 _bt_convert_addr_string_to_type(device_address.addr,
95 g_wait_data->address);
96 _bt_audio_connect(g_wait_data->req_id, g_wait_data->type,
97 &device_address, g_wait_data->out_param1);
100 /* Event will be sent by the event reciever */
102 if (req_info->context == NULL)
105 out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
106 out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
108 g_array_append_vals(out_param1, func_data->address,
110 g_array_append_vals(out_param2, &result, sizeof(int));
112 dbus_g_method_return(req_info->context, out_param1, out_param2);
114 g_array_free(out_param1, TRUE);
115 g_array_free(out_param2, TRUE);
117 _bt_delete_request_list(req_info->req_id);
120 g_error_free(g_error);
123 g_free(func_data->address);
128 static char *__bt_get_audio_path(bluetooth_device_address_t *address)
131 char *object_path = NULL;
132 char addr_str[BT_ADDRESS_STRING_SIZE + 1] = { 0 };
133 DBusGProxy *audio_proxy;
134 DBusGProxy *adapter_proxy;
135 DBusGConnection *g_conn;
136 GError *error = NULL;
138 retv_if(address == NULL, NULL);
140 g_conn = _bt_get_system_gconn();
141 retv_if(g_conn == NULL, NULL);
143 adapter_proxy = _bt_get_adapter_proxy();
144 retv_if(adapter_proxy == NULL, NULL);
146 _bt_convert_addr_type_to_string(addr_str, address->addr);
148 dbus_g_proxy_call(adapter_proxy, "FindDevice",
149 &error, G_TYPE_STRING, addr_str,
150 G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH,
151 &object_path, G_TYPE_INVALID);
154 BT_ERR("Failed to Find device: %s\n", error->message);
159 retv_if(object_path == NULL, NULL);
161 audio_proxy = dbus_g_proxy_new_for_name(g_conn,
164 BT_HEADSET_INTERFACE);
166 retv_if(audio_proxy == NULL, NULL);
168 g_object_unref(audio_proxy);
173 static char *__bt_get_connected_audio_path(void)
177 char *audio_path = NULL;
179 bluetooth_device_info_t info;
181 /* allocate the g_pointer_array */
182 device_list = g_array_new(FALSE, FALSE, sizeof(gchar));
184 if (_bt_get_bonded_devices(&device_list)
185 != BLUETOOTH_ERROR_NONE) {
186 g_array_free(device_list, TRUE);
190 size = device_list->len;
191 size = (device_list->len) / sizeof(bluetooth_device_info_t);
193 for (i = 0; i < size; i++) {
195 info = g_array_index(device_list,
196 bluetooth_device_info_t, i);
198 if (info.connected == TRUE) {
199 audio_path = __bt_get_audio_path(&info.device_address);
205 g_array_free(device_list, TRUE);
210 static void __bt_free_wait_data()
212 if (g_wait_data != NULL) {
213 g_free(g_wait_data->address);
219 static void __bt_remove_device_from_wait_list()
221 /* Before deleting the request update the UI */
222 GArray *out_param_1 = NULL;
223 GArray *out_param_2 = NULL;
224 int result = BLUETOOTH_ERROR_INTERNAL;
225 request_info_t *req_info;
227 req_info = _bt_get_request_info(g_wait_data->req_id);
228 if (req_info == NULL) {
229 BT_ERR("req_info == NULL");
233 out_param_1 = g_array_new(FALSE, FALSE, sizeof(gchar));
234 out_param_2 = g_array_new(FALSE, FALSE, sizeof(gchar));
235 g_array_append_vals(out_param_1, g_wait_data->address,
237 g_array_append_vals(out_param_2, &result, sizeof(int));
238 dbus_g_method_return(req_info->context,
239 out_param_1, out_param_2);
240 g_array_free(out_param_1, TRUE);
241 g_array_free(out_param_2, TRUE);
242 _bt_delete_request_list(g_wait_data->req_id);
245 static void __bt_set_headset_disconnection_type(const char *address)
247 bt_connected_headset_data_t *connected_device;
250 BT_DBG("__bt_set_headset_disconnection_type \n");
252 node = g_list_first(g_connected_list);
253 while (node != NULL) {
254 connected_device = node->data;
255 if (g_strcmp0(connected_device->device_address, address) == 0) {
256 g_wait_data->disconnection_type = connected_device->type;
259 node = g_list_next(node);
263 gboolean _bt_is_headset_type_connected(int type, char *address)
267 BT_DBG("_bt_is_headset_type_connected \n");
269 node = g_list_first(g_connected_list);
270 while (node != NULL) {
271 bt_connected_headset_data_t *connected_device = node->data;
273 if (connected_device->type & type) {
275 g_strlcpy(address, connected_device->device_address,
276 BT_ADDRESS_STRING_SIZE + 1);
280 node = g_list_next(node);
285 static gboolean __bt_is_headset_connected(int type, int req_id,
286 const char *address, GArray **out_param1)
289 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
290 bluetooth_device_address_t device_address;
292 BT_DBG("__bt_is_headset_connected \n");
294 /* Check if any other headset is connected */
295 connected = _bt_is_headset_type_connected(type, connected_address);
300 /* If already one device is waiting, remove current waiting device and add new */
301 if (g_wait_data != NULL) {
302 if (g_strcmp0(g_wait_data->address, address) != 0) {
303 __bt_remove_device_from_wait_list();
304 __bt_free_wait_data();
308 if (g_wait_data == NULL) {
309 g_wait_data = g_malloc0(sizeof(bt_headset_wait_t));
310 g_wait_data->address = g_strdup(address);
311 g_wait_data->req_id = req_id;
312 g_wait_data->type = type;
313 g_wait_data->ag_flag = FALSE;
314 g_wait_data->out_param1 = out_param1;
316 /* Set disconnection type */
317 __bt_set_headset_disconnection_type(connected_address);
320 /* Convert BD adress from string type */
321 _bt_convert_addr_string_to_type(device_address.addr, connected_address);
322 _bt_audio_disconnect(0, type, &device_address, NULL);
326 void _bt_set_audio_wait_data_flag(gboolean flag)
328 BT_DBG("_bt_set_audio_wait_data_flag \n");
329 g_wait_data->ag_flag = flag;
332 bt_headset_wait_t *_bt_get_audio_wait_data(void)
334 BT_DBG("_bt_get_audio_wait_data \n");
338 void _bt_add_headset_to_list(int type, int status, const char *address)
340 bt_connected_headset_data_t *connected_device;
341 bt_connected_headset_data_t *device;
344 BT_DBG("_bt_add_headset_to_list \n");
346 node = g_list_first(g_connected_list);
347 while (node != NULL) {
348 device = (bt_connected_headset_data_t *)node->data;
350 if (g_strcmp0(device->device_address, address) == 0) {
351 BT_DBG("Address match, update connection type \n");
352 device->type |= type;
353 device->device_state = status;
356 node = g_list_next(node);
359 connected_device = g_malloc0(sizeof(bt_connected_headset_data_t));
360 connected_device->type |= type;
361 connected_device->device_state = status;
362 g_strlcpy(connected_device->device_address, address,
363 sizeof(connected_device->device_address));
364 g_connected_list = g_list_append(g_connected_list, connected_device);
367 void _bt_remove_headset_from_list(int type, const char *address)
371 BT_DBG("_bt_remove_headset_from_list \n");
373 node = g_list_first(g_connected_list);
374 while (node != NULL) {
375 bt_connected_headset_data_t *connected_device = node->data;
377 if (g_strcmp0(connected_device->device_address, address) != 0) {
378 node = g_list_next(node);
382 BT_DBG("Address match \n");
384 BT_DBG("Connection type = %x\n", connected_device->type);
388 if (connected_device->type & BT_AUDIO_A2DP)
389 connected_device->type &= ~(BT_AUDIO_A2DP);
392 if (connected_device->type & BT_AUDIO_HSP)
393 connected_device->type &= ~(BT_AUDIO_HSP);
396 if (connected_device->type & BT_AUDIO_ALL)
397 connected_device->type &= ~(BT_AUDIO_ALL);
401 BT_DBG("Connection type = %x\n", connected_device->type);
403 if (connected_device->type == 0x00) {
404 g_connected_list = g_list_remove(g_connected_list, connected_device);
405 g_free(connected_device);
408 node = g_list_next(node);
412 int _bt_audio_connect(int request_id, int type,
413 bluetooth_device_address_t *device_address,
416 int result = BLUETOOTH_ERROR_NONE;
417 gchar *device_path = NULL;
419 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
420 bt_function_data_t *func_data;
421 DBusGProxy *adapter_proxy;
422 DBusGProxy *profile_proxy;
423 DBusGConnection *g_conn;
425 BT_CHECK_PARAMETER(device_address, return);
427 _bt_convert_addr_type_to_string(address, device_address->addr);
431 interface = BT_HEADSET_INTERFACE;
434 interface = BT_SINK_INTERFACE;
437 interface = BT_AUDIO_INTERFACE;
440 BT_ERR("Unknown role");
441 result = BLUETOOTH_ERROR_INTERNAL;
445 if (__bt_is_headset_connected(type, request_id, address, out_param1))
446 return BLUETOOTH_ERROR_NONE;
448 adapter_proxy = _bt_get_adapter_proxy();
449 if (adapter_proxy == NULL) {
450 result = BLUETOOTH_ERROR_INTERNAL;
454 g_conn = _bt_get_system_gconn();
455 if (g_conn == NULL) {
456 result = BLUETOOTH_ERROR_INTERNAL;
460 dbus_g_proxy_call(adapter_proxy, "FindDevice", NULL,
461 G_TYPE_STRING, address, G_TYPE_INVALID,
462 DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID);
464 if (device_path == NULL) {
465 BT_ERR("No paired device");
466 result = BLUETOOTH_ERROR_NOT_PAIRED;
470 profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
471 device_path, interface);
475 if (profile_proxy == NULL) {
476 result = BLUETOOTH_ERROR_INTERNAL;
480 func_data = g_malloc0(sizeof(bt_function_data_t));
481 func_data->address = g_strdup(address);
482 func_data->req_id = request_id;
484 if (!dbus_g_proxy_begin_call(profile_proxy, "Connect",
485 (DBusGProxyCallNotify)__bt_audio_request_cb,
488 BT_ERR("Audio connect Dbus Call Error");
489 g_object_unref(profile_proxy);
491 g_free(func_data->address);
494 result = BLUETOOTH_ERROR_INTERNAL;
497 /* Add data to the connected list */
498 _bt_add_headset_to_list(type, BT_STATE_CONNECTING, address);
499 __bt_free_wait_data();
501 return BLUETOOTH_ERROR_NONE;
503 g_array_append_vals(*out_param1, address,
509 int _bt_audio_disconnect(int request_id, int type,
510 bluetooth_device_address_t *device_address,
513 int result = BLUETOOTH_ERROR_NONE;
514 gchar *device_path = NULL;
516 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
517 bt_function_data_t *func_data;
518 DBusGProxy *adapter_proxy;
519 DBusGProxy *profile_proxy;
520 DBusGConnection *g_conn;
522 BT_CHECK_PARAMETER(device_address, return);
524 _bt_convert_addr_type_to_string(address, device_address->addr);
528 interface = BT_HEADSET_INTERFACE;
531 interface = BT_SINK_INTERFACE;
534 interface = BT_AUDIO_INTERFACE;
537 BT_ERR("Unknown role");
538 return BLUETOOTH_ERROR_INTERNAL;
541 adapter_proxy = _bt_get_adapter_proxy();
542 if (adapter_proxy == NULL) {
543 result = BLUETOOTH_ERROR_INTERNAL;
547 g_conn = _bt_get_system_gconn();
548 if (g_conn == NULL) {
549 result = BLUETOOTH_ERROR_INTERNAL;
553 dbus_g_proxy_call(adapter_proxy, "FindDevice", NULL,
554 G_TYPE_STRING, address, G_TYPE_INVALID,
555 DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID);
557 if (device_path == NULL) {
558 BT_ERR("No paired device");
559 result = BLUETOOTH_ERROR_NOT_PAIRED;
563 profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
564 device_path, interface);
568 if (profile_proxy == NULL) {
569 result = BLUETOOTH_ERROR_INTERNAL;
573 if (g_wait_data != NULL) {
574 if (!dbus_g_proxy_begin_call(profile_proxy, "Disconnect",
575 NULL, NULL, NULL, G_TYPE_INVALID)) {
576 BT_ERR("Audio disconnect Dbus Call Error");
577 g_object_unref(profile_proxy);
578 return BLUETOOTH_ERROR_INTERNAL;
581 func_data = g_malloc0(sizeof(bt_function_data_t));
582 func_data->address = g_strdup(address);
583 func_data->req_id = request_id;
584 if (!dbus_g_proxy_begin_call(profile_proxy, "Disconnect",
585 (DBusGProxyCallNotify)__bt_audio_request_cb,
588 BT_ERR("Audio disconnect Dbus Call Error");
589 g_object_unref(profile_proxy);
591 g_free(func_data->address);
594 result = BLUETOOTH_ERROR_INTERNAL;
599 return BLUETOOTH_ERROR_NONE;
601 g_array_append_vals(*out_param1, address,
607 int _bt_audio_get_speaker_gain(unsigned int *gain)
609 char *device_path = NULL;
610 DBusGProxy *adapter_proxy;
611 DBusGProxy *profile_proxy;
612 DBusGConnection *g_conn;
613 GHashTable *hash = NULL;
616 adapter_proxy = _bt_get_adapter_proxy();
617 retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
619 g_conn = _bt_get_system_gconn();
620 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
622 device_path = __bt_get_connected_audio_path();
623 retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
625 profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
626 device_path, BT_HEADSET_INTERFACE);
630 retv_if(profile_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
632 dbus_g_proxy_call(profile_proxy, "GetProperties", NULL,
634 dbus_g_type_get_map("GHashTable",
635 G_TYPE_STRING, G_TYPE_VALUE),
636 &hash, G_TYPE_INVALID);
638 g_object_unref(profile_proxy);
640 retv_if(hash == NULL, BLUETOOTH_ERROR_INTERNAL);
642 value = g_hash_table_lookup(hash, "SpeakerGain");
643 *gain = value ? g_value_get_uint(value) : 0;
644 g_hash_table_destroy(hash);
645 return BLUETOOTH_ERROR_NONE;
648 int _bt_audio_set_speaker_gain(unsigned int gain)
650 char *device_path = NULL;
651 char *gain_str = "SpeakerGain";
652 char sig[2] = {DBUS_TYPE_UINT16, '\0'};
653 int ret = BLUETOOTH_ERROR_NONE;
655 DBusMessageIter iter;
656 DBusMessageIter value;
657 DBusConnection *conn;
659 conn = _bt_get_system_conn();
660 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
662 device_path = __bt_get_connected_audio_path();
663 retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
665 msg = dbus_message_new_method_call(BT_BLUEZ_NAME,
666 device_path, BT_HEADSET_INTERFACE,
671 retv_if(msg == NULL, BLUETOOTH_ERROR_INTERNAL);
673 dbus_message_iter_init_append(msg, &iter);
674 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
676 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
678 dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT16,
680 dbus_message_iter_close_container(&iter, &value);
682 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL)
683 dbus_message_set_no_reply(msg, TRUE);
685 if (!dbus_connection_send(conn, msg, NULL)) {
686 BT_ERR("Dbus sending failed\n");
687 ret = BLUETOOTH_ERROR_INTERNAL;
689 dbus_message_unref(msg);