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; l = g_slist_next(l)) {
79 if (req_info == NULL || req_info->service_function != service_function)
82 switch (service_function) {
83 case BT_HDP_REGISTER_SINK_APP:
84 case BT_HDP_UNREGISTER_SINK_APP: {
85 int app_id = *((int *)data);
88 if (*((int *)req_info->user_data) != app_id)
91 app_handle = g_strdup_printf("health_app_%d", app_id);
92 BT_DBG("app_handle: %s", app_handle);
94 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
95 g_array_append_vals(out_param, app_handle, strlen(app_handle));
96 _bt_service_method_return(req_info->context, out_param, result);
97 g_free(req_info->user_data);
98 _bt_free_info_from_invocation_list(req_info);
99 g_array_free(out_param, TRUE);
103 case BT_HDP_CONNECT: {
104 bt_hdp_conn_info_t *info = data;
105 bt_hdp_connected_t *conn_data = info->data;
106 bt_hdp_connected_t *req_conn_data = req_info->user_data;
111 if (req_conn_data->channel_id != conn_data->channel_id)
114 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
115 g_array_append_vals(out_param, conn_data, sizeof(bt_hdp_connected_t));
117 _bt_service_method_return(req_info->context, out_param, result);
118 g_free(req_info->user_data);
119 _bt_free_info_from_invocation_list(req_info);
120 g_array_free(out_param, TRUE);
123 case BT_HDP_DISCONNECT: {
124 bt_hdp_disconnected_t *disconn_data = data;
125 bt_hdp_disconnected_t *req_disconn_data = req_info->user_data;
127 if (req_disconn_data->channel_id != disconn_data->channel_id)
130 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
131 g_array_append_vals(out_param, disconn_data, sizeof(bt_hdp_disconnected_t));
132 _bt_service_method_return(req_info->context, out_param, result);
133 g_free(req_info->user_data);
134 _bt_free_info_from_invocation_list(req_info);
135 g_array_free(out_param, TRUE);
138 case BT_HDP_GET_FD: {
139 GUnixFDList *fd_list = NULL;
141 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
142 if (BLUETOOTH_ERROR_NONE == result) {
143 GError *error = NULL;
144 bt_hdp_conn_info_t *info = data;
145 bt_hdp_connected_t *conn_data = info->data;
147 if (*((int *)req_info->user_data) != (int)conn_data->channel_id)
150 BT_DBG("fd: %d", info->fd);
152 fd_list = g_unix_fd_list_new();
153 g_unix_fd_list_append(fd_list, info->fd, &error);
154 g_assert_no_error(error);
158 _bt_service_method_return_with_unix_fd_list(
159 req_info->context, out_param, result, fd_list);
161 g_object_unref(fd_list);
162 g_free(req_info->user_data);
163 _bt_free_info_from_invocation_list(req_info);
164 g_array_free(out_param, TRUE);
168 BT_ERR("Unknown service function");
176 static bt_hdp_qos_type_t __convert_oal_ch_type_to_hdp_qos_type(int channel_type)
178 switch (channel_type) {
179 case OAL_CHANNEL_TYPE_RELIABLE:
180 return HDP_QOS_RELIABLE;
181 case OAL_CHANNEL_TYPE_STREAMING:
182 return HDP_QOS_STREAMING;
188 static void __handle_hdp_channel_connected(event_hdp_channel_conn_t *event)
191 bt_hdp_app_info_t *app;
192 bt_hdp_conn_info_t *hdp_conn;
193 bt_hdp_connected_t *conn_info;
194 char address[BT_ADDRESS_STRING_SIZE];
199 app = __find_app_by_id(event->app_id);
202 app_handle = g_strdup_printf("health_app_%d", event->app_id);
204 conn_info = g_new0(bt_hdp_connected_t, 1);
205 conn_info->type = __convert_oal_ch_type_to_hdp_qos_type(event->ch_type);
206 conn_info->channel_id = event->channel_id;
207 conn_info->app_handle = app_handle;
208 memcpy(conn_info->device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
210 hdp_conn = g_new0(bt_hdp_conn_info_t, 1);
211 hdp_conn->fd = event->fd;
212 hdp_conn->data = conn_info;
213 pending_conn_list = g_slist_append(pending_conn_list, hdp_conn);
215 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_NONE,
216 BT_HDP_CONNECT, (void *)hdp_conn, sizeof(bt_hdp_conn_info_t));
218 _bt_convert_addr_type_to_string(address, event->address.addr);
219 BT_DBG("HDP connected to %s, app_handle: %s", address, conn_info->app_handle);
221 param = g_variant_new("(issui)",
222 BLUETOOTH_ERROR_NONE,
223 address, conn_info->app_handle,
224 conn_info->channel_id, conn_info->type);
225 _bt_send_event_to_dest(app->owner,
226 BT_HDP_EVENT, BLUETOOTH_EVENT_HDP_CONNECTED, param);
233 static void __handle_hdp_channel_disconnected(event_hdp_channel_conn_t *event)
235 bt_hdp_app_info_t *app;
240 app = __find_app_by_id(event->app_id);
243 /* reply to pending requests if any */
245 bt_hdp_conn_info_t hdp_conn;
246 bt_hdp_connected_t conn_info;
249 BT_DBG("Connect request failed for channel_id: %d", event->channel_id);
250 memset(&conn_info, 0x00, sizeof(bt_hdp_connected_t));
251 conn_info.type = __convert_oal_ch_type_to_hdp_qos_type(event->ch_type);
252 conn_info.channel_id = event->channel_id;
254 app_handle = g_strdup_printf("health_app_%d", event->app_id);
255 conn_info.app_handle = app_handle;
257 memcpy(conn_info.device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
259 hdp_conn.fd = event->fd;
260 hdp_conn.data = &conn_info;
262 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_INTERNAL,
263 BT_HDP_CONNECT, (void *)&hdp_conn, sizeof(bt_hdp_conn_info_t));
267 bt_hdp_disconnected_t disconn_info;
268 char address[BT_ADDRESS_STRING_SIZE];
272 memset(&disconn_info, 0x00, sizeof(bt_hdp_disconnected_t));
273 disconn_info.channel_id = event->channel_id;
274 memcpy(disconn_info.device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
276 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_NONE,
277 BT_HDP_DISCONNECT, (void *)&disconn_info, sizeof(bt_hdp_disconnected_t));
279 /* Send event to application */
280 _bt_convert_addr_type_to_string(address, event->address.addr);
281 app_handle = g_strdup_printf("health_app_%d", event->app_id);
283 BT_DBG("HDP disconnected from %s, app_handle: %s", address, app_handle);
284 param = g_variant_new("(isu)",
285 BLUETOOTH_ERROR_NONE,
286 address, event->channel_id);
287 _bt_send_event_to_dest(app->owner,
288 BT_HDP_EVENT, BLUETOOTH_EVENT_HDP_DISCONNECTED, param);
296 static void __bt_hdp_event_handler(int event_type, gpointer event_data)
298 BT_INFO("OAL event = 0x%x, \n", event_type);
300 switch (event_type) {
301 case OAL_EVENT_HDP_APP_REGISTERED: {
302 event_hdp_app_reg_t *app_data = event_data;
306 ret_if(NULL == event_data);
307 app_id = app_data->app_id;
308 if (OAL_STATUS_SUCCESS != app_data->status) {
309 bt_hdp_app_info_t *app = __find_app_by_id(app_id);
311 app_list = g_slist_remove(app_list, app);
315 result = BLUETOOTH_ERROR_INTERNAL;
317 result = BLUETOOTH_ERROR_NONE;
320 BT_DBG("app_id: %d, resut: %d", app_id, result);
321 __bt_hdp_handle_pending_request_info(result,
322 BT_HDP_REGISTER_SINK_APP, (void *)&app_id, sizeof(app_id));
325 case OAL_EVENT_HDP_APP_UNREGISTERED: {
326 event_hdp_app_reg_t *app_data = event_data;
330 ret_if(NULL == event_data);
331 app_id = app_data->app_id;
332 if (OAL_STATUS_SUCCESS != app_data->status) {
333 result = BLUETOOTH_ERROR_INTERNAL;
335 bt_hdp_app_info_t *app = __find_app_by_id(app_id);
337 app_list = g_slist_remove(app_list, app);
341 result = BLUETOOTH_ERROR_NONE;
344 BT_DBG("app_id: %d, resut: %d", app_id, result);
345 __bt_hdp_handle_pending_request_info(result,
346 BT_HDP_UNREGISTER_SINK_APP, (void *)&app_id, sizeof(app_id));
349 case OAL_EVENT_HDP_CHANNEL_CONNECTED: {
350 ret_if(NULL == event_data);
351 __handle_hdp_channel_connected((event_hdp_channel_conn_t *)event_data);
354 case OAL_EVENT_HDP_CHANNEL_DESTROYED: {
355 ret_if(NULL == event_data);
356 __handle_hdp_channel_disconnected((event_hdp_channel_conn_t *)event_data);
360 BT_ERR("Invalid event:%d\n", event_type);
365 int _bt_hdp_init(void)
369 if (OAL_STATUS_SUCCESS != hdp_init()) {
370 BT_ERR("hdp_init failed");
371 return BLUETOOTH_ERROR_INTERNAL;
374 /* Register SOCKET event handler */
375 _bt_service_register_event_handler_callback(BT_HEALTH_MODULE, __bt_hdp_event_handler);
377 return BLUETOOTH_ERROR_NONE;
380 void _bt_hdp_deinit(void)
384 if (OAL_STATUS_SUCCESS != hdp_cleanup())
385 BT_ERR("hdp_cleanup failed");
387 /* Un-register SOCKET event handler */
388 _bt_service_unregister_event_handler_callback(BT_HEALTH_MODULE);
392 int _bt_hdp_app_register(bt_hdp_role_type_t role, bt_hdp_qos_type_t channel_type,
393 unsigned short data_type, char *sender, int *app_id)
395 oal_channel_type_t ch_type;
396 oal_hdp_role_t dev_role;
397 bt_hdp_app_info_t *app;
401 retv_if(NULL == app_id, BLUETOOTH_ERROR_INVALID_PARAM);
404 case HDP_ROLE_SOURCE:
405 dev_role = OAL_HDP_ROLE_SOURCE;
408 dev_role = OAL_HDP_ROLE_SINK;
411 BT_ERR("Invalid HDP role");
412 return BLUETOOTH_ERROR_INVALID_PARAM;
415 switch (channel_type) {
416 case HDP_QOS_RELIABLE:
417 ch_type = OAL_CHANNEL_TYPE_RELIABLE;
419 case HDP_QOS_STREAMING:
420 ch_type = OAL_CHANNEL_TYPE_STREAMING;
423 ch_type = OAL_CHANNEL_TYPE_ANY;
426 BT_ERR("Invalid channel type");
427 return BLUETOOTH_ERROR_INVALID_PARAM;
430 *app_id = hdp_register_application(dev_role, ch_type, sender, data_type);
432 BT_ERR("hdp_register_application failed");
433 return BLUETOOTH_ERROR_INTERNAL;
436 /* Add application to the list */
437 app = g_new0(bt_hdp_app_info_t, 1);
438 app->app_id = *app_id;
439 app->owner = g_strdup(sender);
440 app_list = g_slist_append(app_list, app);
443 return BLUETOOTH_ERROR_NONE;
446 int _bt_hdp_app_unregister(int app_id)
452 ret = hdp_unregister_application(app_id);
453 if (OAL_STATUS_SUCCESS != ret) {
454 BT_ERR("hdp_unregister_application failed");
455 return BLUETOOTH_ERROR_INTERNAL;
459 return BLUETOOTH_ERROR_NONE;
462 int _bt_hdp_connect(int app_id, bluetooth_device_address_t *address,
463 bt_hdp_qos_type_t channel_type, int *channel_id)
465 bt_address_t bd_addr;
469 retv_if(NULL == address, BLUETOOTH_ERROR_INVALID_PARAM);
470 retv_if(NULL == channel_id, BLUETOOTH_ERROR_INVALID_PARAM);
472 memset(&bd_addr, 0x00, sizeof(bt_address_t));
473 memcpy(bd_addr.addr, address->addr, BT_ADDRESS_BYTES_NUM);
475 *channel_id = hdp_connect_channel(app_id, &bd_addr);
476 if (0 > *channel_id) {
477 BT_ERR("hdp_connect_channel failed");
478 return BLUETOOTH_ERROR_INTERNAL;
482 return BLUETOOTH_ERROR_NONE;
485 int _bt_hdp_disconnect(int channel_id)
491 ret = hdp_disconnect_channel(channel_id);
492 if (OAL_STATUS_SUCCESS != ret) {
493 BT_ERR("hdp_disconnect_channel failed");
494 return BLUETOOTH_ERROR_INTERNAL;
498 return BLUETOOTH_ERROR_NONE;
501 gboolean __send_fd(gpointer data)
503 bt_hdp_conn_info_t *info = data;
508 pending_conn_list = g_slist_remove(pending_conn_list, info);
509 __bt_hdp_handle_pending_request_info(BLUETOOTH_ERROR_NONE,
510 BT_HDP_GET_FD, (void *)info, sizeof(bt_hdp_conn_info_t));
514 __bt_hdp_handle_pending_request_info(
515 BLUETOOTH_ERROR_INTERNAL, BT_HDP_GET_FD, NULL, 0);
522 int _bt_hdp_get_fd(int channel_id)
525 bt_hdp_conn_info_t *info = NULL;
526 bt_hdp_connected_t *conn_info = NULL;
530 BT_DBG("channel_id: %d, pending_conn_list: %p", channel_id, pending_conn_list);
531 for (l = pending_conn_list; NULL != l; l = g_slist_next(l)) {
537 conn_info = (bt_hdp_connected_t *)(info->data);
538 if (conn_info && ((int)conn_info->channel_id == channel_id)) {
539 BT_DBG("Match found");
547 g_idle_add(__send_fd, info);
549 return BLUETOOTH_ERROR_NONE;
552 void _bt_check_hdp_app_termination(const char *name)
555 bt_hdp_app_info_t *app = NULL;
557 ret_if(NULL == name);
559 for (l = app_list; NULL != l; l = g_slist_next(l)) {
565 if (app->owner && !strncasecmp(app->owner, name, strlen(name))) {
566 BT_DBG("Match found, name: %s", name);
567 _bt_hdp_app_unregister(app->app_id);