4 * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
6 * Author: Atul Rai <a.rai@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 #include <sys/types.h>
24 #include <gio/gunixfdlist.h>
29 #include <oal-event.h>
32 /* bt-service headers */
33 #include "bt-internal-types.h"
34 #include "bt-service-common.h"
35 #include "bt-service-util.h"
36 #include "bt-service-event-receiver.h"
37 #include "bt-service-event.h"
38 #include "bt-service-hdp.h"
50 static GSList *app_list;
51 static GSList *pending_conn_list;
53 static bt_hdp_app_info_t *__find_app_by_id(int app_id)
57 for (l = app_list; NULL != l; l = g_slist_next(l)) {
58 bt_hdp_app_info_t *app = l->data;
59 if (app && (app->app_id == app_id))
66 static void __bt_hdp_handle_pending_request_info(int result,
67 int service_function, void *data, unsigned int size)
71 invocation_info_t *req_info = NULL;
77 for (l = _bt_get_invocation_list(); l != NULL; ) {
80 if (req_info == NULL || req_info->service_function != service_function)
83 switch (service_function) {
84 case BT_HDP_REGISTER_SINK_APP:
85 case BT_HDP_UNREGISTER_SINK_APP: {
86 int app_id = *((int *)data);
89 if (*((int *)req_info->user_data) != app_id)
92 app_handle = g_strdup_printf("health_app_%d", app_id);
93 BT_DBG("app_handle: %s", app_handle);
95 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
96 g_array_append_vals(out_param, app_handle, strlen(app_handle));
97 _bt_service_method_return(req_info->context, out_param, result);
98 g_free(req_info->user_data);
99 _bt_free_info_from_invocation_list(req_info);
100 g_array_free(out_param, TRUE);
104 case BT_HDP_CONNECT: {
105 bt_hdp_conn_info_t *info = data;
106 bt_hdp_connected_t *conn_data = info->data;
107 bt_hdp_connected_t *req_conn_data = req_info->user_data;
112 if (req_conn_data->channel_id != conn_data->channel_id)
115 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
116 g_array_append_vals(out_param, conn_data, sizeof(bt_hdp_connected_t));
118 _bt_service_method_return(req_info->context, out_param, result);
119 g_free(req_info->user_data);
120 _bt_free_info_from_invocation_list(req_info);
121 g_array_free(out_param, TRUE);
124 case BT_HDP_DISCONNECT: {
125 bt_hdp_disconnected_t *disconn_data = data;
126 bt_hdp_disconnected_t *req_disconn_data = req_info->user_data;
128 if (req_disconn_data->channel_id != disconn_data->channel_id)
131 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
132 g_array_append_vals(out_param, disconn_data, sizeof(bt_hdp_disconnected_t));
133 _bt_service_method_return(req_info->context, out_param, result);
134 g_free(req_info->user_data);
135 _bt_free_info_from_invocation_list(req_info);
136 g_array_free(out_param, TRUE);
139 case BT_HDP_GET_FD: {
140 GUnixFDList *fd_list = NULL;
142 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
143 if (BLUETOOTH_ERROR_NONE == result) {
144 GError *error = NULL;
145 bt_hdp_conn_info_t *info = data;
146 bt_hdp_connected_t *conn_data = info->data;
148 if (*((int *)req_info->user_data) != (int)conn_data->channel_id)
151 BT_DBG("fd: %d", info->fd);
153 fd_list = g_unix_fd_list_new();
154 g_unix_fd_list_append(fd_list, info->fd, &error);
155 g_assert_no_error(error);
159 _bt_service_method_return_with_unix_fd_list(
160 req_info->context, out_param, result, fd_list);
162 g_object_unref(fd_list);
163 g_free(req_info->user_data);
164 _bt_free_info_from_invocation_list(req_info);
165 g_array_free(out_param, TRUE);
169 BT_ERR("Unknown service function");
177 static bt_hdp_qos_type_t __convert_oal_ch_type_to_hdp_qos_type(int channel_type)
179 switch (channel_type) {
180 case OAL_CHANNEL_TYPE_RELIABLE:
181 return HDP_QOS_RELIABLE;
182 case OAL_CHANNEL_TYPE_STREAMING:
183 return HDP_QOS_STREAMING;
189 static void __handle_hdp_channel_connected(event_hdp_channel_conn_t *event)
192 bt_hdp_app_info_t *app;
193 bt_hdp_conn_info_t *hdp_conn;
194 bt_hdp_connected_t *conn_info;
195 char address[BT_ADDRESS_STRING_SIZE];
200 app = __find_app_by_id(event->app_id);
203 app_handle = g_strdup_printf("health_app_%d", event->app_id);
205 conn_info = g_new0(bt_hdp_connected_t, 1);
206 conn_info->type = __convert_oal_ch_type_to_hdp_qos_type(event->ch_type);
207 conn_info->channel_id = event->channel_id;
208 conn_info->app_handle = app_handle;
209 memcpy(conn_info->device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
211 hdp_conn = g_new0(bt_hdp_conn_info_t, 1);
212 hdp_conn->fd = event->fd;
213 hdp_conn->data = conn_info;
214 pending_conn_list = g_slist_append(pending_conn_list, hdp_conn);
216 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_NONE,
217 BT_HDP_CONNECT, (void *)hdp_conn, sizeof(bt_hdp_conn_info_t));
219 _bt_convert_addr_type_to_string(address, event->address.addr);
220 BT_DBG("HDP connected to %s, app_handle: %s", address, conn_info->app_handle);
222 param = g_variant_new("(issui)",
223 BLUETOOTH_ERROR_NONE,
224 address, conn_info->app_handle,
225 conn_info->channel_id, conn_info->type);
226 _bt_send_event_to_dest(app->owner,
227 BT_HDP_EVENT, BLUETOOTH_EVENT_HDP_CONNECTED, param);
234 static void __handle_hdp_channel_disconnected(event_hdp_channel_conn_t *event)
236 bt_hdp_app_info_t *app;
241 app = __find_app_by_id(event->app_id);
244 /* reply to pending requests if any */
246 bt_hdp_conn_info_t hdp_conn;
247 bt_hdp_connected_t conn_info;
250 BT_DBG("Connect request failed for channel_id: %d", event->channel_id);
251 memset(&conn_info, 0x00, sizeof(bt_hdp_connected_t));
252 conn_info.type = __convert_oal_ch_type_to_hdp_qos_type(event->ch_type);
253 conn_info.channel_id = event->channel_id;
255 app_handle = g_strdup_printf("health_app_%d", event->app_id);
256 conn_info.app_handle = app_handle;
258 memcpy(conn_info.device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
260 hdp_conn.fd = event->fd;
261 hdp_conn.data = &conn_info;
263 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_INTERNAL,
264 BT_HDP_CONNECT, (void *)&hdp_conn, sizeof(bt_hdp_conn_info_t));
268 bt_hdp_disconnected_t disconn_info;
269 char address[BT_ADDRESS_STRING_SIZE];
273 memset(&disconn_info, 0x00, sizeof(bt_hdp_disconnected_t));
274 disconn_info.channel_id = event->channel_id;
275 memcpy(disconn_info.device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
277 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_NONE,
278 BT_HDP_DISCONNECT, (void *)&disconn_info, sizeof(bt_hdp_disconnected_t));
280 /* Send event to application */
281 _bt_convert_addr_type_to_string(address, event->address.addr);
282 app_handle = g_strdup_printf("health_app_%d", event->app_id);
284 BT_DBG("HDP disconnected from %s, app_handle: %s", address, app_handle);
285 param = g_variant_new("(isu)",
286 BLUETOOTH_ERROR_NONE,
287 address, event->channel_id);
288 _bt_send_event_to_dest(app->owner,
289 BT_HDP_EVENT, BLUETOOTH_EVENT_HDP_DISCONNECTED, param);
297 static void __bt_hdp_event_handler(int event_type, gpointer event_data)
299 BT_INFO("OAL event = 0x%x, \n", event_type);
301 switch (event_type) {
302 case OAL_EVENT_HDP_APP_REGISTERED: {
303 event_hdp_app_reg_t *app_data = event_data;
307 ret_if(NULL == event_data);
308 app_id = app_data->app_id;
309 if (OAL_STATUS_SUCCESS != app_data->status) {
310 bt_hdp_app_info_t *app = __find_app_by_id(app_id);
312 app_list = g_slist_remove(app_list, app);
316 result = BLUETOOTH_ERROR_INTERNAL;
318 result = BLUETOOTH_ERROR_NONE;
321 BT_DBG("app_id: %d, resut: %d", app_id, result);
322 __bt_hdp_handle_pending_request_info(result,
323 BT_HDP_REGISTER_SINK_APP, (void *)&app_id, sizeof(app_id));
326 case OAL_EVENT_HDP_APP_UNREGISTERED: {
327 event_hdp_app_reg_t *app_data = event_data;
331 ret_if(NULL == event_data);
332 app_id = app_data->app_id;
333 if (OAL_STATUS_SUCCESS != app_data->status) {
334 result = BLUETOOTH_ERROR_INTERNAL;
336 bt_hdp_app_info_t *app = __find_app_by_id(app_id);
338 app_list = g_slist_remove(app_list, app);
342 result = BLUETOOTH_ERROR_NONE;
345 BT_DBG("app_id: %d, resut: %d", app_id, result);
346 __bt_hdp_handle_pending_request_info(result,
347 BT_HDP_UNREGISTER_SINK_APP, (void *)&app_id, sizeof(app_id));
350 case OAL_EVENT_HDP_CHANNEL_CONNECTED: {
351 ret_if(NULL == event_data);
352 __handle_hdp_channel_connected((event_hdp_channel_conn_t *)event_data);
355 case OAL_EVENT_HDP_CHANNEL_DESTROYED: {
356 ret_if(NULL == event_data);
357 __handle_hdp_channel_disconnected((event_hdp_channel_conn_t *)event_data);
361 BT_ERR("Invalid event:%d\n", event_type);
366 int _bt_hdp_init(void)
370 if (OAL_STATUS_SUCCESS != hdp_init()) {
371 BT_ERR("hdp_init failed");
372 return BLUETOOTH_ERROR_INTERNAL;
375 /* Register SOCKET event handler */
376 _bt_service_register_event_handler_callback(BT_HEALTH_MODULE, __bt_hdp_event_handler);
378 return BLUETOOTH_ERROR_NONE;
381 void _bt_hdp_deinit(void)
385 if (OAL_STATUS_SUCCESS != hdp_cleanup())
386 BT_ERR("hdp_cleanup failed");
388 /* Un-register SOCKET event handler */
389 _bt_service_unregister_event_handler_callback(BT_HEALTH_MODULE);
393 int _bt_hdp_app_register(bt_hdp_role_type_t role, bt_hdp_qos_type_t channel_type,
394 unsigned short data_type, char *sender, int *app_id)
396 oal_channel_type_t ch_type;
397 oal_hdp_role_t dev_role;
398 bt_hdp_app_info_t *app;
402 retv_if(NULL == app_id, BLUETOOTH_ERROR_INVALID_PARAM);
405 case HDP_ROLE_SOURCE:
406 dev_role = OAL_HDP_ROLE_SOURCE;
409 dev_role = OAL_HDP_ROLE_SINK;
412 BT_ERR("Invalid HDP role");
413 return BLUETOOTH_ERROR_INVALID_PARAM;
416 switch (channel_type) {
417 case HDP_QOS_RELIABLE:
418 ch_type = OAL_CHANNEL_TYPE_RELIABLE;
420 case HDP_QOS_STREAMING:
421 ch_type = OAL_CHANNEL_TYPE_STREAMING;
424 ch_type = OAL_CHANNEL_TYPE_ANY;
427 BT_ERR("Invalid channel type");
428 return BLUETOOTH_ERROR_INVALID_PARAM;
431 *app_id = hdp_register_application(dev_role, ch_type, sender, data_type);
433 BT_ERR("hdp_register_application failed");
434 return BLUETOOTH_ERROR_INTERNAL;
437 /* Add application to the list */
438 app = g_new0(bt_hdp_app_info_t, 1);
439 app->app_id = *app_id;
440 app->owner = g_strdup(sender);
441 app_list = g_slist_append(app_list, app);
444 return BLUETOOTH_ERROR_NONE;
447 int _bt_hdp_app_unregister(int app_id)
453 ret = hdp_unregister_application(app_id);
454 if (OAL_STATUS_SUCCESS != ret) {
455 BT_ERR("hdp_unregister_application failed");
456 return BLUETOOTH_ERROR_INTERNAL;
460 return BLUETOOTH_ERROR_NONE;
463 int _bt_hdp_connect(int app_id, bluetooth_device_address_t *address,
464 bt_hdp_qos_type_t channel_type, int *channel_id)
466 bt_address_t bd_addr;
470 retv_if(NULL == address, BLUETOOTH_ERROR_INVALID_PARAM);
471 retv_if(NULL == channel_id, BLUETOOTH_ERROR_INVALID_PARAM);
473 memset(&bd_addr, 0x00, sizeof(bt_address_t));
474 memcpy(bd_addr.addr, address->addr, BT_ADDRESS_BYTES_NUM);
476 *channel_id = hdp_connect_channel(app_id, &bd_addr);
477 if (0 > *channel_id) {
478 BT_ERR("hdp_connect_channel failed");
479 return BLUETOOTH_ERROR_INTERNAL;
483 return BLUETOOTH_ERROR_NONE;
486 int _bt_hdp_disconnect(int channel_id)
492 ret = hdp_disconnect_channel(channel_id);
493 if (OAL_STATUS_SUCCESS != ret) {
494 BT_ERR("hdp_disconnect_channel failed");
495 return BLUETOOTH_ERROR_INTERNAL;
499 return BLUETOOTH_ERROR_NONE;
502 gboolean __send_fd(gpointer data)
504 bt_hdp_conn_info_t *info = data;
509 pending_conn_list = g_slist_remove(pending_conn_list, info);
510 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_NONE,
511 BT_HDP_GET_FD, (void *)info, sizeof(bt_hdp_conn_info_t));
515 __bt_hdp_handle_pending_request_info(
516 BLUETOOTH_ERROR_INTERNAL, BT_HDP_GET_FD, NULL, 0);
523 int _bt_hdp_get_fd(int channel_id)
526 bt_hdp_conn_info_t *info = NULL;
527 bt_hdp_connected_t *conn_info = NULL;
531 BT_DBG("channel_id: %d, pending_conn_list: %p", channel_id, pending_conn_list);
532 for (l = pending_conn_list; NULL != l; l = g_slist_next(l)) {
538 conn_info = (bt_hdp_connected_t *)(info->data);
539 if (conn_info && ((int)conn_info->channel_id == channel_id)) {
540 BT_DBG("Match found");
548 g_idle_add(__send_fd, info);
550 return BLUETOOTH_ERROR_NONE;
553 void _bt_check_hdp_app_termination(const char *name)
556 bt_hdp_app_info_t *app = NULL;
558 ret_if(NULL == name);
560 for (l = app_list; NULL != l; l = g_slist_next(l)) {
566 if (app->owner && !strncasecmp(app->owner, name, strlen(name))) {
567 BT_DBG("Match found, name: %s", name);
568 _bt_hdp_app_unregister(app->app_id);