Merge branch 'master' into tizen_2.1
[platform/core/connectivity/bluetooth-frwk.git] / bt-service / bt-service-audio.c
1 /*
2  * bluetooth-frwk
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #include <dbus/dbus-glib.h>
21 #include <dbus/dbus.h>
22 #include <glib.h>
23 #include <dlog.h>
24 #include <string.h>
25 #include <syspopup_caller.h>
26
27 #include "bluetooth-api.h"
28 #include "bt-internal-types.h"
29
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"
35
36 typedef struct {
37         unsigned int type;
38         int device_state;
39         char device_address[BT_ADDRESS_STRING_SIZE + 1];
40 } bt_connected_headset_data_t;
41
42 static GList *g_connected_list;
43
44 static bt_headset_wait_t *g_wait_data;
45
46 static void __bt_remove_device_from_wait_list();
47
48 static void __bt_free_wait_data();
49
50 static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call,
51                                     gpointer user_data)
52 {
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;
59
60         dbus_g_proxy_end_call(proxy, call, &g_error, G_TYPE_INVALID);
61
62         g_object_unref(proxy);
63
64         func_data = user_data;
65
66         if (func_data == NULL) {
67                 /* Send reply */
68                 BT_ERR("func_data == NULL");
69                 goto done;
70         }
71
72         req_info = _bt_get_request_info(func_data->req_id);
73         if (req_info == NULL) {
74                 BT_ERR("req_info == NULL");
75                 goto done;
76         }
77
78         if (g_error == NULL)
79                 goto dbus_return;
80
81         BT_ERR("Audio Connect Dbus Call Error: %s\n", g_error->message);
82
83         result = BLUETOOTH_ERROR_INTERNAL;
84
85         /* Remove the device from the list */
86         _bt_remove_headset_from_list(BT_AUDIO_ALL, func_data->address);
87
88         /* Error, check if any waiting device is there */
89         if (g_wait_data == NULL)
90                 goto dbus_return;
91
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);
98         }
99
100         /* Event will be sent by the event reciever */
101 dbus_return:
102         if (req_info->context == NULL)
103                 goto done;
104
105         out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
106         out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
107
108         g_array_append_vals(out_param1, func_data->address,
109                                 BT_ADDRESS_STR_LEN);
110         g_array_append_vals(out_param2, &result, sizeof(int));
111
112         dbus_g_method_return(req_info->context, out_param1, out_param2);
113
114         g_array_free(out_param1, TRUE);
115         g_array_free(out_param2, TRUE);
116
117         _bt_delete_request_list(req_info->req_id);
118 done:
119         if (g_error)
120                 g_error_free(g_error);
121
122         if (func_data) {
123                 g_free(func_data->address);
124                 g_free(func_data);
125         }
126 }
127
128 static char *__bt_get_audio_path(bluetooth_device_address_t *address)
129 {
130
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;
137
138         retv_if(address == NULL, NULL);
139
140         g_conn = _bt_get_system_gconn();
141         retv_if(g_conn == NULL, NULL);
142
143         adapter_proxy = _bt_get_adapter_proxy();
144         retv_if(adapter_proxy == NULL, NULL);
145
146         _bt_convert_addr_type_to_string(addr_str, address->addr);
147
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);
152
153         if (error != NULL) {
154                 BT_ERR("Failed to Find device: %s\n", error->message);
155                 g_error_free(error);
156                 return NULL;
157         }
158
159         retv_if(object_path == NULL, NULL);
160
161         audio_proxy = dbus_g_proxy_new_for_name(g_conn,
162                                         BT_BLUEZ_NAME,
163                                         object_path,
164                                         BT_HEADSET_INTERFACE);
165
166         retv_if(audio_proxy == NULL, NULL);
167
168         g_object_unref(audio_proxy);
169
170         return object_path;
171 }
172
173 static char *__bt_get_connected_audio_path(void)
174 {
175         int i;
176         guint size;
177         char *audio_path = NULL;
178         GArray *device_list;
179         bluetooth_device_info_t info;
180
181         /* allocate the g_pointer_array */
182         device_list = g_array_new(FALSE, FALSE, sizeof(gchar));
183
184         if (_bt_get_bonded_devices(&device_list)
185                                         != BLUETOOTH_ERROR_NONE) {
186                 g_array_free(device_list, TRUE);
187                 return NULL;
188         }
189
190         size = device_list->len;
191         size = (device_list->len) / sizeof(bluetooth_device_info_t);
192
193         for (i = 0; i < size; i++) {
194
195                 info = g_array_index(device_list,
196                                 bluetooth_device_info_t, i);
197
198                 if (info.connected == TRUE) {
199                         audio_path = __bt_get_audio_path(&info.device_address);
200                         if (audio_path)
201                                 break;
202                 }
203         }
204
205         g_array_free(device_list, TRUE);
206
207         return audio_path;
208 }
209
210 static void __bt_free_wait_data()
211 {
212         if (g_wait_data != NULL) {
213                 g_free(g_wait_data->address);
214                 g_free(g_wait_data);
215                 g_wait_data = NULL;
216         }
217 }
218
219 static void __bt_remove_device_from_wait_list()
220 {
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;
226
227         req_info = _bt_get_request_info(g_wait_data->req_id);
228         if (req_info == NULL) {
229                 BT_ERR("req_info == NULL");
230                 return;
231         }
232
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,
236                                 BT_ADDRESS_STR_LEN);
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);
243 }
244
245 static void __bt_set_headset_disconnection_type(const char *address)
246 {
247         bt_connected_headset_data_t *connected_device;
248         GList *node;
249
250         BT_DBG("__bt_set_headset_disconnection_type \n");
251
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;
257                         return;
258                 }
259                 node = g_list_next(node);
260         }
261 }
262
263 gboolean _bt_is_headset_type_connected(int type, char *address)
264 {
265         GList *node;
266
267         BT_DBG("_bt_is_headset_type_connected \n");
268
269         node = g_list_first(g_connected_list);
270         while (node != NULL) {
271                 bt_connected_headset_data_t *connected_device = node->data;
272
273                 if (connected_device->type & type) {
274                         if (address != NULL)
275                                 g_strlcpy(address, connected_device->device_address,
276                                                 BT_ADDRESS_STRING_SIZE + 1);
277                         return TRUE;
278                 }
279
280                 node = g_list_next(node);
281         }
282         return FALSE;
283 }
284
285 static gboolean __bt_is_headset_connected(int type, int req_id,
286                                 const char *address, GArray **out_param1)
287 {
288         gboolean connected;
289         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
290         bluetooth_device_address_t device_address;
291
292         BT_DBG("__bt_is_headset_connected \n");
293
294         /* Check if any other headset is connected */
295         connected = _bt_is_headset_type_connected(type, connected_address);
296
297         if (!connected)
298                 return FALSE;
299
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();
305                 }
306         }
307
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;
315
316                 /* Set disconnection type */
317                 __bt_set_headset_disconnection_type(connected_address);
318         }
319
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);
323         return TRUE;
324 }
325
326 void _bt_set_audio_wait_data_flag(gboolean flag)
327 {
328         BT_DBG("_bt_set_audio_wait_data_flag \n");
329         g_wait_data->ag_flag = flag;
330 }
331
332 bt_headset_wait_t *_bt_get_audio_wait_data(void)
333 {
334         BT_DBG("_bt_get_audio_wait_data \n");
335         return g_wait_data;
336 }
337
338 void _bt_add_headset_to_list(int type, int status, const char *address)
339 {
340         bt_connected_headset_data_t *connected_device;
341         bt_connected_headset_data_t *device;
342         GList *node;
343
344         BT_DBG("_bt_add_headset_to_list \n");
345
346         node = g_list_first(g_connected_list);
347         while (node != NULL) {
348                 device = (bt_connected_headset_data_t *)node->data;
349
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;
354                         return;
355                 }
356                 node = g_list_next(node);
357         }
358
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);
365 }
366
367 void _bt_remove_headset_from_list(int type, const char *address)
368 {
369         GList *node;
370
371         BT_DBG("_bt_remove_headset_from_list \n");
372
373         node = g_list_first(g_connected_list);
374         while (node != NULL) {
375                 bt_connected_headset_data_t *connected_device = node->data;
376
377                 if (g_strcmp0(connected_device->device_address, address) != 0) {
378                         node = g_list_next(node);
379                         continue;
380                 }
381
382                 BT_DBG("Address match \n");
383
384                 BT_DBG("Connection type = %x\n", connected_device->type);
385
386                 switch (type) {
387                 case BT_AUDIO_A2DP:
388                         if (connected_device->type & BT_AUDIO_A2DP)
389                                 connected_device->type &= ~(BT_AUDIO_A2DP);
390                         break;
391                 case BT_AUDIO_HSP:
392                         if (connected_device->type & BT_AUDIO_HSP)
393                                 connected_device->type &= ~(BT_AUDIO_HSP);
394                         break;
395                 case BT_AUDIO_ALL:
396                         if (connected_device->type & BT_AUDIO_ALL)
397                                 connected_device->type &= ~(BT_AUDIO_ALL);
398                         break;
399                 }
400
401                 BT_DBG("Connection type = %x\n", connected_device->type);
402
403                 if (connected_device->type == 0x00) {
404                         g_connected_list = g_list_remove(g_connected_list, connected_device);
405                         g_free(connected_device);
406                 }
407
408                 node = g_list_next(node);
409         }
410 }
411
412 int _bt_audio_connect(int request_id, int type,
413                 bluetooth_device_address_t *device_address,
414                 GArray **out_param1)
415 {
416         int result = BLUETOOTH_ERROR_NONE;
417         gchar *device_path = NULL;
418         char *interface;
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;
424
425         BT_CHECK_PARAMETER(device_address, return);
426
427         _bt_convert_addr_type_to_string(address, device_address->addr);
428
429         switch (type) {
430         case BT_AUDIO_HSP:
431                 interface = BT_HEADSET_INTERFACE;
432                 break;
433         case BT_AUDIO_A2DP:
434                 interface = BT_SINK_INTERFACE;
435                 break;
436         case BT_AUDIO_ALL:
437                 interface = BT_AUDIO_INTERFACE;
438                 break;
439         default:
440                 BT_ERR("Unknown role");
441                 result = BLUETOOTH_ERROR_INTERNAL;
442                 goto fail;
443         }
444
445         if (__bt_is_headset_connected(type, request_id, address, out_param1))
446                 return BLUETOOTH_ERROR_NONE;
447
448         adapter_proxy = _bt_get_adapter_proxy();
449         if (adapter_proxy == NULL) {
450                 result = BLUETOOTH_ERROR_INTERNAL;
451                 goto fail;
452         }
453
454         g_conn = _bt_get_system_gconn();
455         if (g_conn == NULL) {
456                 result = BLUETOOTH_ERROR_INTERNAL;
457                 goto fail;
458         }
459
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);
463
464         if (device_path == NULL) {
465                 BT_ERR("No paired device");
466                 result = BLUETOOTH_ERROR_NOT_PAIRED;
467                 goto fail;
468         }
469
470         profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
471                                       device_path, interface);
472
473         g_free(device_path);
474
475         if (profile_proxy == NULL) {
476                 result = BLUETOOTH_ERROR_INTERNAL;
477                 goto fail;
478         }
479
480         func_data = g_malloc0(sizeof(bt_function_data_t));
481         func_data->address = g_strdup(address);
482         func_data->req_id = request_id;
483
484         if (!dbus_g_proxy_begin_call(profile_proxy, "Connect",
485                         (DBusGProxyCallNotify)__bt_audio_request_cb,
486                         func_data, NULL,
487                         G_TYPE_INVALID)) {
488                 BT_ERR("Audio connect Dbus Call Error");
489                 g_object_unref(profile_proxy);
490
491                 g_free(func_data->address);
492                 g_free(func_data);
493
494                 result = BLUETOOTH_ERROR_INTERNAL;
495                 goto fail;
496         }
497         /* Add data to the connected list */
498         _bt_add_headset_to_list(type, BT_STATE_CONNECTING, address);
499         __bt_free_wait_data();
500
501         return BLUETOOTH_ERROR_NONE;
502 fail:
503         g_array_append_vals(*out_param1, address,
504                                 BT_ADDRESS_STR_LEN);
505
506         return result;
507 }
508
509 int _bt_audio_disconnect(int request_id, int type,
510                 bluetooth_device_address_t *device_address,
511                 GArray **out_param1)
512 {
513         int result = BLUETOOTH_ERROR_NONE;
514         gchar *device_path = NULL;
515         char *interface;
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;
521
522         BT_CHECK_PARAMETER(device_address, return);
523
524         _bt_convert_addr_type_to_string(address, device_address->addr);
525
526         switch (type) {
527         case BT_AUDIO_HSP:
528                 interface = BT_HEADSET_INTERFACE;
529                 break;
530         case BT_AUDIO_A2DP:
531                 interface = BT_SINK_INTERFACE;
532                 break;
533         case BT_AUDIO_ALL:
534                 interface = BT_AUDIO_INTERFACE;
535                 break;
536         default:
537                 BT_ERR("Unknown role");
538                 return BLUETOOTH_ERROR_INTERNAL;
539         }
540
541         adapter_proxy = _bt_get_adapter_proxy();
542         if (adapter_proxy == NULL) {
543                 result = BLUETOOTH_ERROR_INTERNAL;
544                 goto fail;
545         }
546
547         g_conn = _bt_get_system_gconn();
548         if (g_conn == NULL) {
549                 result = BLUETOOTH_ERROR_INTERNAL;
550                 goto fail;
551         }
552
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);
556
557         if (device_path == NULL) {
558                 BT_ERR("No paired device");
559                 result = BLUETOOTH_ERROR_NOT_PAIRED;
560                 goto fail;
561         }
562
563         profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
564                                       device_path, interface);
565
566         g_free(device_path);
567
568         if (profile_proxy == NULL) {
569                 result = BLUETOOTH_ERROR_INTERNAL;
570                 goto fail;
571         }
572
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;
579                 }
580         } else {
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,
586                                 func_data, NULL,
587                                 G_TYPE_INVALID)) {
588                         BT_ERR("Audio disconnect Dbus Call Error");
589                         g_object_unref(profile_proxy);
590
591                         g_free(func_data->address);
592                         g_free(func_data);
593
594                         result = BLUETOOTH_ERROR_INTERNAL;
595                         goto fail;
596                 }
597         }
598
599         return BLUETOOTH_ERROR_NONE;
600 fail:
601         g_array_append_vals(*out_param1, address,
602                                 BT_ADDRESS_STR_LEN);
603
604         return result;
605 }
606
607 int _bt_audio_get_speaker_gain(unsigned int *gain)
608 {
609         char *device_path = NULL;
610         DBusGProxy *adapter_proxy;
611         DBusGProxy *profile_proxy;
612         DBusGConnection *g_conn;
613         GHashTable *hash = NULL;
614         GValue *value;
615
616         adapter_proxy = _bt_get_adapter_proxy();
617         retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
618
619         g_conn = _bt_get_system_gconn();
620         retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
621
622         device_path = __bt_get_connected_audio_path();
623         retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
624
625         profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
626                                       device_path, BT_HEADSET_INTERFACE);
627
628         g_free(device_path);
629
630         retv_if(profile_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
631
632         dbus_g_proxy_call(profile_proxy, "GetProperties", NULL,
633                         G_TYPE_INVALID,
634                         dbus_g_type_get_map("GHashTable",
635                         G_TYPE_STRING, G_TYPE_VALUE),
636                         &hash, G_TYPE_INVALID);
637
638         g_object_unref(profile_proxy);
639
640         retv_if(hash == NULL, BLUETOOTH_ERROR_INTERNAL);
641
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;
646 }
647
648 int _bt_audio_set_speaker_gain(unsigned int gain)
649 {
650         char *device_path = NULL;
651         char *gain_str = "SpeakerGain";
652         char sig[2] = {DBUS_TYPE_UINT16, '\0'};
653         int ret = BLUETOOTH_ERROR_NONE;
654         DBusMessage *msg;
655         DBusMessageIter iter;
656         DBusMessageIter value;
657         DBusConnection *conn;
658
659         conn = _bt_get_system_conn();
660         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
661
662         device_path = __bt_get_connected_audio_path();
663         retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
664
665         msg = dbus_message_new_method_call(BT_BLUEZ_NAME,
666                         device_path, BT_HEADSET_INTERFACE,
667                         "SetProperty");
668
669         g_free(device_path);
670
671         retv_if(msg == NULL, BLUETOOTH_ERROR_INTERNAL);
672
673         dbus_message_iter_init_append(msg, &iter);
674         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
675                         &gain_str);
676         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
677                         sig, &value);
678         dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT16,
679                         &gain);
680         dbus_message_iter_close_container(&iter, &value);
681
682         if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL)
683                 dbus_message_set_no_reply(msg, TRUE);
684
685         if (!dbus_connection_send(conn, msg, NULL)) {
686                 BT_ERR("Dbus sending failed\n");
687                 ret = BLUETOOTH_ERROR_INTERNAL;
688         }
689         dbus_message_unref(msg);
690
691         return ret;
692 }