Tizen 2.1 base
[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 static void __bt_audio_request_cb(DBusGProxy *proxy, DBusGProxyCall *call,
37                                     gpointer user_data)
38 {
39         GError *g_error = NULL;
40         GArray *out_param1 = NULL;
41         GArray *out_param2 = NULL;
42         int result = BLUETOOTH_ERROR_NONE;
43         bt_function_data_t *func_data;
44         request_info_t *req_info;
45
46         dbus_g_proxy_end_call(proxy, call, &g_error, G_TYPE_INVALID);
47
48         g_object_unref(proxy);
49
50         func_data = user_data;
51
52         if (func_data == NULL) {
53                 /* Send reply */
54                 BT_ERR("func_data == NULL");
55                 goto done;
56         }
57
58         req_info = _bt_get_request_info(func_data->req_id);
59         if (req_info == NULL) {
60                 BT_ERR("req_info == NULL");
61                 goto done;
62         }
63
64         if (g_error != NULL) {
65                 BT_ERR("Audio Connect Dbus Call Error: %s\n", g_error->message);
66                 result = BLUETOOTH_ERROR_INTERNAL;
67                 goto dbus_return;
68         }
69
70         /* Event will be sent by the event reciever */
71 dbus_return:
72         if (req_info->context == NULL)
73                 goto done;
74
75         out_param1 = g_array_new(FALSE, FALSE, sizeof(gchar));
76         out_param2 = g_array_new(FALSE, FALSE, sizeof(gchar));
77
78         g_array_append_vals(out_param1, func_data->address,
79                                 BT_ADDRESS_STR_LEN);
80         g_array_append_vals(out_param2, &result, sizeof(int));
81
82         dbus_g_method_return(req_info->context, out_param1, out_param2);
83
84         g_array_free(out_param1, TRUE);
85         g_array_free(out_param2, TRUE);
86
87         _bt_delete_request_list(req_info->req_id);
88 done:
89         if (g_error)
90                 g_error_free(g_error);
91
92         if (func_data) {
93                 g_free(func_data->address);
94                 g_free(func_data);
95         }
96 }
97
98 static char *__bt_get_audio_path(bluetooth_device_address_t *address)
99 {
100
101         char *object_path = NULL;
102         char addr_str[BT_ADDRESS_STRING_SIZE + 1] = { 0 };
103         DBusGProxy *audio_proxy;
104         DBusGProxy *adapter_proxy;
105         DBusGConnection *g_conn;
106         GError *error = NULL;
107
108         retv_if(address == NULL, NULL);
109
110         g_conn = _bt_get_system_gconn();
111         retv_if(g_conn == NULL, NULL);
112
113         adapter_proxy = _bt_get_adapter_proxy();
114         retv_if(adapter_proxy == NULL, NULL);
115
116         _bt_convert_addr_type_to_string(addr_str, address->addr);
117
118         dbus_g_proxy_call(adapter_proxy, "FindDevice",
119                           &error, G_TYPE_STRING, addr_str,
120                           G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH,
121                           &object_path, G_TYPE_INVALID);
122
123         if (error != NULL) {
124                 BT_ERR("Failed to Find device: %s\n", error->message);
125                 g_error_free(error);
126                 return NULL;
127         }
128
129         retv_if(object_path == NULL, NULL);
130
131         audio_proxy = dbus_g_proxy_new_for_name(g_conn,
132                                         BT_BLUEZ_NAME,
133                                         object_path,
134                                         BT_HEADSET_INTERFACE);
135         retv_if(audio_proxy == NULL, NULL);
136
137         g_object_unref(audio_proxy);
138
139         return object_path;
140 }
141
142 static char *__bt_get_connected_audio_path(void)
143 {
144         int i;
145         guint size;
146         char *audio_path = NULL;
147         GArray *device_list;
148         bluetooth_device_info_t info;
149
150         /* allocate the g_pointer_array */
151         device_list = g_array_new(FALSE, FALSE, sizeof(gchar));
152
153         if (_bt_get_bonded_devices(&device_list)
154                                         != BLUETOOTH_ERROR_NONE) {
155                 g_array_free(device_list, TRUE);
156                 return NULL;
157         }
158
159         size = device_list->len;
160         size = (device_list->len) / sizeof(bluetooth_device_info_t);
161
162         for (i = 0; i < size; i++) {
163
164                 info = g_array_index(device_list,
165                                 bluetooth_device_info_t, i);
166
167                 if (info.connected == TRUE) {
168                         audio_path = __bt_get_audio_path(&info.device_address);
169                         if (audio_path)
170                                 break;
171                 }
172         }
173
174         g_array_free(device_list, TRUE);
175
176         return audio_path;
177 }
178
179 int _bt_audio_connect(int request_id, int type,
180                 bluetooth_device_address_t *device_address,
181                 GArray **out_param1)
182 {
183         int result = BLUETOOTH_ERROR_NONE;
184         gchar *device_path = NULL;
185         char *interface;
186         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
187         bt_function_data_t *func_data;
188         DBusGProxy *adapter_proxy;
189         DBusGProxy *profile_proxy;
190         DBusGConnection *g_conn;
191
192         BT_CHECK_PARAMETER(device_address);
193
194         _bt_convert_addr_type_to_string(address, device_address->addr);
195
196         switch (type) {
197         case BT_AUDIO_HSP:
198                 interface = BT_HEADSET_INTERFACE;
199                 break;
200         case BT_AUDIO_A2DP:
201                 interface = BT_SINK_INTERFACE;
202                 break;
203         case BT_AUDIO_ALL:
204                 interface = BT_AUDIO_INTERFACE;
205                 break;
206         default:
207                 BT_ERR("Unknown role");
208                 result = BLUETOOTH_ERROR_INTERNAL;
209                 goto fail;
210         }
211
212         adapter_proxy = _bt_get_adapter_proxy();
213         if (adapter_proxy == NULL) {
214                 result = BLUETOOTH_ERROR_INTERNAL;
215                 goto fail;
216         }
217
218         g_conn = _bt_get_system_gconn();
219         if (g_conn == NULL) {
220                 result = BLUETOOTH_ERROR_INTERNAL;
221                 goto fail;
222         }
223
224         dbus_g_proxy_call(adapter_proxy, "FindDevice", NULL,
225                           G_TYPE_STRING, address, G_TYPE_INVALID,
226                           DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID);
227
228         if (device_path == NULL) {
229                 BT_ERR("No paired device");
230                 result = BLUETOOTH_ERROR_NOT_PAIRED;
231                 goto fail;
232         }
233
234         profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
235                                       device_path, interface);
236
237         g_free(device_path);
238
239         if (profile_proxy == NULL) {
240                 result = BLUETOOTH_ERROR_INTERNAL;
241                 goto fail;
242         }
243
244         func_data = g_malloc0(sizeof(bt_function_data_t));
245         func_data->address = g_strdup(address);
246         func_data->req_id = request_id;
247
248         if (!dbus_g_proxy_begin_call(profile_proxy, "Connect",
249                         (DBusGProxyCallNotify)__bt_audio_request_cb,
250                         func_data, NULL,
251                         G_TYPE_INVALID)) {
252                 BT_ERR("Audio connect Dbus Call Error");
253                 g_object_unref(profile_proxy);
254
255                 g_free(func_data->address);
256                 g_free(func_data);
257
258                 result = BLUETOOTH_ERROR_INTERNAL;
259                 goto fail;
260         }
261
262         return BLUETOOTH_ERROR_NONE;
263 fail:
264         g_array_append_vals(*out_param1, address,
265                                 BT_ADDRESS_STR_LEN);
266
267         return result;
268 }
269
270 int _bt_audio_disconnect(int request_id, int type,
271                 bluetooth_device_address_t *device_address,
272                 GArray **out_param1)
273 {
274         int result = BLUETOOTH_ERROR_NONE;
275         gchar *device_path = NULL;
276         char *interface;
277         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
278         bt_function_data_t *func_data;
279         DBusGProxy *adapter_proxy;
280         DBusGProxy *profile_proxy;
281         DBusGConnection *g_conn;
282
283         BT_CHECK_PARAMETER(device_address);
284
285         _bt_convert_addr_type_to_string(address, device_address->addr);
286
287         switch (type) {
288         case BT_AUDIO_HSP:
289                 interface = BT_HEADSET_INTERFACE;
290                 break;
291         case BT_AUDIO_A2DP:
292                 interface = BT_SINK_INTERFACE;
293                 break;
294         case BT_AUDIO_ALL:
295                 interface = BT_AUDIO_INTERFACE;
296                 break;
297         default:
298                 BT_ERR("Unknown role");
299                 return BLUETOOTH_ERROR_INTERNAL;
300         }
301
302         adapter_proxy = _bt_get_adapter_proxy();
303         if (adapter_proxy == NULL) {
304                 result = BLUETOOTH_ERROR_INTERNAL;
305                 goto fail;
306         }
307
308         g_conn = _bt_get_system_gconn();
309         if (g_conn == NULL) {
310                 result = BLUETOOTH_ERROR_INTERNAL;
311                 goto fail;
312         }
313
314         dbus_g_proxy_call(adapter_proxy, "FindDevice", NULL,
315                           G_TYPE_STRING, address, G_TYPE_INVALID,
316                           DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID);
317
318         if (device_path == NULL) {
319                 BT_ERR("No paired device");
320                 result = BLUETOOTH_ERROR_NOT_PAIRED;
321                 goto fail;
322         }
323
324         profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
325                                       device_path, interface);
326
327         g_free(device_path);
328
329         if (profile_proxy == NULL) {
330                 result = BLUETOOTH_ERROR_INTERNAL;
331                 goto fail;
332         }
333
334         func_data = g_malloc0(sizeof(bt_function_data_t));
335         func_data->address = g_strdup(address);
336         func_data->req_id = request_id;
337
338         if (!dbus_g_proxy_begin_call(profile_proxy, "Disconnect",
339                         (DBusGProxyCallNotify)__bt_audio_request_cb,
340                         func_data, NULL,
341                         G_TYPE_INVALID)) {
342                 BT_ERR("Audio disconnect Dbus Call Error");
343                 g_object_unref(profile_proxy);
344
345                 g_free(func_data->address);
346                 g_free(func_data);
347
348                 result = BLUETOOTH_ERROR_INTERNAL;
349                 goto fail;
350         }
351
352         return BLUETOOTH_ERROR_NONE;
353 fail:
354         g_array_append_vals(*out_param1, address,
355                                 BT_ADDRESS_STR_LEN);
356
357         return result;
358 }
359
360 int _bt_audio_get_speaker_gain(unsigned int *gain)
361 {
362         char *device_path = NULL;
363         DBusGProxy *adapter_proxy;
364         DBusGProxy *profile_proxy;
365         DBusGConnection *g_conn;
366         GHashTable *hash = NULL;
367         GValue *value;
368
369         adapter_proxy = _bt_get_adapter_proxy();
370         retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
371
372         g_conn = _bt_get_system_gconn();
373         retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
374
375         device_path = __bt_get_connected_audio_path();
376         retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
377
378         profile_proxy = dbus_g_proxy_new_for_name(g_conn, BT_BLUEZ_NAME,
379                                       device_path, BT_HEADSET_INTERFACE);
380
381         g_free(device_path);
382
383         retv_if(profile_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
384
385         dbus_g_proxy_call(profile_proxy, "GetProperties", NULL,
386                         G_TYPE_INVALID,
387                         dbus_g_type_get_map("GHashTable",
388                         G_TYPE_STRING, G_TYPE_VALUE),
389                         &hash, G_TYPE_INVALID);
390
391         g_object_unref(profile_proxy);
392
393         retv_if(hash == NULL, BLUETOOTH_ERROR_INTERNAL);
394
395         value = g_hash_table_lookup(hash, "SpeakerGain");
396         *gain = value ? g_value_get_uint(value) : 0;
397         g_hash_table_destroy(hash);
398         return BLUETOOTH_ERROR_NONE;
399 }
400
401 int _bt_audio_set_speaker_gain(unsigned int gain)
402 {
403         char *device_path = NULL;
404         char *gain_str = "SpeakerGain";
405         char sig[2] = {DBUS_TYPE_UINT16, '\0'};
406         int ret = BLUETOOTH_ERROR_NONE;
407         DBusMessage *msg;
408         DBusMessageIter iter;
409         DBusMessageIter value;
410         DBusConnection *conn;
411
412         conn = _bt_get_system_conn();
413         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
414
415         device_path = __bt_get_connected_audio_path();
416         retv_if(device_path == NULL, BLUETOOTH_ERROR_NOT_CONNECTED);
417
418         msg = dbus_message_new_method_call(BT_BLUEZ_NAME,
419                         device_path, BT_HEADSET_INTERFACE,
420                         "SetProperty");
421
422         g_free(device_path);
423
424         retv_if(msg == NULL, BLUETOOTH_ERROR_INTERNAL);
425
426         dbus_message_iter_init_append(msg, &iter);
427         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
428                         &gain_str);
429         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
430                         sig, &value);
431         dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT16,
432                         &gain);
433         dbus_message_iter_close_container(&iter, &value);
434
435         if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL)
436                 dbus_message_set_no_reply(msg, TRUE);
437
438         if (!dbus_connection_send(conn, msg, NULL)) {
439                 BT_ERR("Dbus sending failed\n");
440                 ret = BLUETOOTH_ERROR_INTERNAL;
441         }
442         dbus_message_unref(msg);
443
444         return ret;
445 }