Implement the HDP invoked CAPIs features 34/19834/1
authorWu Zheng <wu.zheng@intel.com>
Mon, 21 Apr 2014 09:28:55 +0000 (05:28 -0400)
committerWu Zheng <wu.zheng@intel.com>
Mon, 21 Apr 2014 09:28:55 +0000 (05:28 -0400)
Implement the activate/deactive/conn/disconn/send HDP features.

Change-Id: Id20eddf28e6ccb195f6dfbce1ddb840777af0416
Signed-off-by: Wu Zheng <wu.zheng@intel.com>
include/common.h
lib/bluez-hdp.c
lib/common.c

index 48aac6a..c574615 100644 (file)
@@ -113,4 +113,7 @@ void device_path_to_address(const char *device_path,
 
 void convert_addr_string_to_type(unsigned char *addr,
                                        const char *address);
+
+GDBusConnection *get_system_lib_dbus_connect(void);
+
 #endif
index b9eb8ef..975c49a 100644 (file)
@@ -6,11 +6,26 @@
 #include "common.h"
 #include "bluez.h"
 
+typedef struct {
+       char *obj_channel_path;
+       int fd;
+} hdp_obj_info_t;
+
+typedef struct {
+       void *app_handle;
+       GSList *obj_info;
+} hdp_app_list_t;
+
 static bluez_hdp_state_changed_t hdp_state_changed_cb;
 static gpointer hdp_state_changed_cb_data;
 static bluez_set_data_received_changed_t data_received_changed_cb;
 static gpointer data_received_changed_data;
 
+static void hdp_obj_info_free(hdp_obj_info_t *info);
+static hdp_app_list_t *hdp_internal_gslist_find_app_handler(void *app_handle);
+
+static GSList *g_app_list;
+
 void bluez_set_hdp_state_changed_cb(
                                bluez_hdp_state_changed_t cb,
                                gpointer user_data)
@@ -39,60 +54,465 @@ void bluez_unset_data_received_changed_cb()
        data_received_changed_data = NULL;
 }
 
-int bluetooth_hdp_activate(unsigned short data_type,
-                                       bt_hdp_role_type_t role,
+static int hdp_internal_create_application(unsigned int data_type,
+                                       int role,
                                        bt_hdp_qos_type_t channel_type,
                                        char **app_handle)
 {
+       GVariantBuilder *opts;
+       guint16 value;
+       const char *svalue;
+       GDBusConnection *connection;
+       GVariant *val;
+       GError *error = NULL;
        int ret;
+       hdp_app_list_t *list;
+       char *app_path;
 
-       DBG("");
+       connection = get_system_lib_dbus_connect();
+       if (connection == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       opts = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+
+       value = (guint16)data_type;
+       g_variant_builder_add(opts, "{sv}", "DataType",
+                                       g_variant_new("q", value));
+
+       svalue = (role == HDP_ROLE_SINK) ? "Sink" : "Source";
+       g_variant_builder_add(opts, "{sv}", "Role",
+                                       g_variant_new("s", svalue));
+
+       g_variant_builder_add(opts, "{sv}", "Description",
+                               g_variant_new("s", "Health Device"));
+
+       if (role == HDP_ROLE_SOURCE) {
+               if (channel_type == HDP_QOS_RELIABLE)
+                       svalue = "Reliable";
+               else if (channel_type == HDP_QOS_STREAMING)
+                       svalue = "Streaming";
+               else
+                       svalue = "";
+
+               g_variant_builder_add(opts, "{sv}", "ChannelType",
+                                       g_variant_new("s", svalue));
+       }
+
+       val = g_dbus_connection_call_sync(connection, BLUEZ_NAME,
+                                       "/org/bluez",
+                                       HDP_MANAGER_INTERFACE,
+                                       "CreateApplication",
+                                       g_variant_new("(a{sv})", opts),
+                                       NULL, 0, -1,
+                                       NULL, &error);
+
+       if (error) {
+               DBG("error %s", error->message);
+               g_error_free(error);
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       g_variant_get(val, "(o)", &app_path);
+
+       DBG("path = %s", app_path);
+
+       list = g_new0(hdp_app_list_t, 1);
+       list->app_handle = (void *)g_strdup(app_path);
+       *app_handle = list->app_handle;
+
+       g_app_list = g_slist_append(g_app_list, list);
 
        ret = BT_ERROR_NONE;
+done:
        return ret;
 }
 
-int bluetooth_hdp_deactivate(const char *app_handle)
+int bluetooth_hdp_activate(unsigned short data_type,
+                                       bt_hdp_role_type_t role,
+                                       bt_hdp_qos_type_t channel_type,
+                                       char **app_handle)
 {
-       int ret;
+       int result = BT_ERROR_NONE;
 
        DBG("");
 
+       if (role == HDP_ROLE_SOURCE && channel_type == HDP_QOS_ANY) {
+               DBG("For source, type is mandatory - Reliable/Streaming");
+               return BT_ERROR_INVALID_PARAMETER;
+       }
+
+       result = hdp_internal_create_application(data_type, role,
+                                               channel_type, app_handle);
+
+       return result;
+}
+
+static hdp_app_list_t *hdp_internal_gslist_find_app_handler(void *app_handle)
+{
+       GSList *l;
+
+       if (g_app_list == NULL)
+               return NULL;
+
+       DBG("List length = %d\n", g_slist_length(g_app_list));
+
+       for (l = g_app_list; l != NULL; l = l->next) {
+               hdp_app_list_t *list = l->data;
+
+               if (list) {
+                       if (0 == g_strcmp0((char *)list->app_handle,
+                                                       (char *)app_handle))
+                               return list;
+               }
+       }
+       return NULL;
+}
+
+static void hdp_obj_info_free(hdp_obj_info_t *info)
+{
+       if (info) {
+               close(info->fd);
+               g_free(info->obj_channel_path);
+               g_free(info);
+       }
+}
+
+static hdp_obj_info_t *hdp_internal_gslist_obj_find_using_fd(int fd)
+{
+       GSList *l;
+       GSList *iter;
+
+       if (g_app_list == NULL)
+               return NULL;
+
+       DBG("List length = %d\n", g_slist_length(g_app_list));
+
+       for (l = g_app_list; l != NULL; l = l->next) {
+               hdp_app_list_t *list = l->data;
+               if (!list)
+                       return NULL;
+
+               for (iter = list->obj_info; iter != NULL;
+                                               iter = iter->next) {
+                       hdp_obj_info_t *info = iter->data;
+                       if (!info)
+                               return NULL;
+
+                       if (fd == info->fd)
+                               return info;
+               }
+       }
+       return NULL;
+}
+
+static gboolean hdp_internal_destroy_application_cb(gpointer data)
+{
+       const char *app_handle;
+       hdp_app_list_t *list = NULL;
+       app_handle = (const char *)data;
+
+       DBG("+");
+
+       list = hdp_internal_gslist_find_app_handler((void *)app_handle);
+       if (NULL == list) {
+               DBG("**** list not found for %s ******\n", app_handle);
+               return FALSE;
+       }
+
+       g_app_list = g_slist_remove(g_app_list, list);
+
+       g_free(list->app_handle);
+       g_slist_foreach(list->obj_info, (GFunc)hdp_obj_info_free, NULL);
+       g_free(list);
+
+       DBG("List length = %d\n", g_slist_length(g_app_list));
+
+       DBG("-");
+       return FALSE;
+}
+
+static int hdp_internal_destroy_application(const char *app_handle)
+{
+       GDBusConnection *connection;
+       GError *error = NULL;
+       int ret;
+
+       connection = get_system_lib_dbus_connect();
+       if (connection == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       g_dbus_connection_call_sync(connection, BLUEZ_NAME,
+                               "/org/bluez",
+                               HDP_MANAGER_INTERFACE,
+                               "DestroyApplication",
+                               g_variant_new("(o)", app_handle),
+                               NULL, 0, -1,
+                               NULL, &error);
+
+       if (error) {
+               DBG("error %s", error->message);
+               g_error_free(error);
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       DBG("Destroyed health application: %s", (char *)app_handle);
+
+       g_idle_add(hdp_internal_destroy_application_cb,
+                                       (gpointer)app_handle);
+
        ret = BT_ERROR_NONE;
+done:
        return ret;
 }
 
+int bluetooth_hdp_deactivate(const char *app_handle)
+{
+       return hdp_internal_destroy_application(app_handle);
+}
+
 int bluetooth_hdp_send_data(unsigned int channel_id,
                                        const char *buffer,
                                        unsigned int size)
 {
-       int ret;
+       int wbytes = 0;
+       int written = 0;
 
-       DBG("");
+       DBG("+");
 
-       ret = BT_ERROR_NONE;
-       return ret;
+       if ((channel_id == 0) || (NULL == buffer) || (size == 0)) {
+               DBG("Invalid arguments..\n");
+               return BT_ERROR_INVALID_PARAMETER;
+       } else {
+               while (wbytes < size) {
+                       written = write(channel_id, buffer + wbytes,
+                                               size - wbytes);
+                       if (written <= 0) {
+                               DBG("write failed..\n");
+                               return BT_ERROR_OPERATION_FAILED;
+                       }
+                       wbytes += written;
+               }
+       }
+
+       return BT_ERROR_NONE;
+}
+
+static void hdp_connect_request_cb(GObject *source_object,
+                               GAsyncResult *res, gpointer user_data)
+{
+       GError *error;
+       GVariant *result;
+       char *obj_connect_path;
+       GDBusConnection *conn;
+       char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+       bt_hdp_connected_t *conn_ind = user_data;
+
+       conn = get_system_lib_dbus_connect();
+       if (conn == NULL)
+               goto done;
+       result = g_dbus_connection_call_finish(conn,
+                                                       res,
+                                                       &error);
+       if (error) {
+               DBG("HDP connection  Dbus Call Error: %s\n", error->message);
+               convert_addr_type_to_string(address,
+                       (unsigned char *)conn_ind->device_address.addr);
+
+               if (hdp_state_changed_cb)
+                       hdp_state_changed_cb(
+                               BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED,
+                               address, conn_ind->app_handle,
+                               conn_ind->type, 0,
+                               hdp_state_changed_cb_data);
+               g_error_free(error);
+       } else {
+               g_variant_get(result, "(o)", &obj_connect_path);
+               DBG("Obj Path returned = %s\n", obj_connect_path);
+       }
+
+done:
+       g_free((void *)conn_ind->app_handle);
+       g_free(conn_ind);
 }
 
 int bluetooth_hdp_connect(const char *app_handle,
                        bt_hdp_qos_type_t channel_type,
                        const bluetooth_device_address_t *device_address)
 {
+       bt_hdp_connected_t *param;
+       char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+       char *dev_path = NULL;
+       char *role;
+       bluez_adapter_t *adapter = NULL;
+       GDBusConnection *conn;
        int ret;
 
-       DBG("");
+       DBG("+");
+
+       adapter = bluez_adapter_get_adapter(DEFAULT_ADAPTER_NAME);
+
+       if (adapter == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       if (channel_type == HDP_QOS_RELIABLE) {
+               role = "Reliable";
+       } else if (channel_type == HDP_QOS_STREAMING) {
+               role = "Streaming";
+       } else if (channel_type == HDP_QOS_ANY) {
+               role = "Any";
+       } else {
+               DBG("Invalid channel_type %d", channel_type);
+               return BT_ERROR_INVALID_PARAMETER;
+       }
+
+       conn = get_system_lib_dbus_connect();
+       if (conn == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       convert_addr_type_to_string(address,
+                       (unsigned char *)device_address->addr);
+
+       DBG("create conection to %s", address);
+
+       dev_path = g_strdup_printf("/org/bluez/%s/dev_%s",
+                                       DEFAULT_ADAPTER_NAME, address);
+       if (dev_path == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       g_strdelimit(dev_path, ":", '_');
+
+       DBG("path: %s", dev_path);
+
+       param = g_new0(bt_hdp_connected_t, 1);
+       param->app_handle = g_strdup(app_handle);
+       memcpy(&param->device_address, device_address,
+                                       BLUETOOTH_ADDRESS_LENGTH);
+       param->type = channel_type;
+
+       g_dbus_connection_call(conn, BLUEZ_NAME,
+                               dev_path,
+                               HDP_DEVICE_INTERFACE,
+                               "CreateChannel",
+                               g_variant_new("(os)", app_handle, role),
+                               NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+                               hdp_connect_request_cb, param);
+
+       g_free(dev_path);
 
        ret = BT_ERROR_NONE;
+done:
        return ret;
 }
 
+static void hdp_disconnect_request_cb(GObject *source_object,
+                       GAsyncResult *res, gpointer user_data)
+{
+       bt_hdp_disconnected_t *disconn_ind = user_data;
+       char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+       GError *error;
+       GDBusConnection *conn;
+
+       conn = get_system_lib_dbus_connect();
+       if (conn == NULL)
+               goto done;
+
+       g_dbus_connection_call_finish(conn, res, &error);
+
+       if (error) {
+               DBG("HDP discon  Dbus Call Error: %s\n", error->message);
+               convert_addr_type_to_string(address,
+                       (unsigned char *)disconn_ind->device_address.addr);
+               if (hdp_state_changed_cb)
+                       hdp_state_changed_cb(BT_ERROR_NONE,
+                                       address, NULL,
+                                       0, disconn_ind->channel_id,
+                                       hdp_state_changed_cb_data);
+               g_error_free(error);
+       } else {
+               DBG("HDP disconnection Dbus Call is done\n");
+       }
+
+done:
+       g_free(disconn_ind);
+}
+
 int bluetooth_hdp_disconnect(unsigned int channel_id,
                const bluetooth_device_address_t *device_address)
 {
+       bt_hdp_disconnected_t *param;
+       char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+       char *dev_path = NULL;
+       bluez_adapter_t *adapter = NULL;
+       GDBusConnection *conn;
+       hdp_obj_info_t *info = NULL;
        int ret;
 
-       DBG("");
+       DBG("+");
+
+       adapter = bluez_adapter_get_adapter(DEFAULT_ADAPTER_NAME);
+
+       if (adapter == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       info = hdp_internal_gslist_obj_find_using_fd(channel_id);
+       if (NULL == info) {
+               DBG("*** Could not locate the list for %d*****\n", channel_id);
+               ret = BT_ERROR_INVALID_PARAMETER;
+               goto done;
+       }
+
+       conn = get_system_lib_dbus_connect();
+       if (conn == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       convert_addr_type_to_string(address,
+               (unsigned char *)device_address->addr);
+
+       DBG("create conection to %s", address);
+
+       dev_path = g_strdup_printf("/org/bluez/%s/dev_%s",
+                                       DEFAULT_ADAPTER_NAME, address);
+       if (dev_path == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       g_strdelimit(dev_path, ":", '_');
+
+       DBG("path: %s", dev_path);
+
+       param = g_new0(bt_hdp_disconnected_t, 1);
+       param->channel_id = channel_id;
+       memcpy(&param->device_address, device_address,
+                                       BLUETOOTH_ADDRESS_LENGTH);
+
+       g_dbus_connection_call(conn, BLUEZ_NAME,
+                               dev_path,
+                               HDP_DEVICE_INTERFACE,
+                               "DestroyChannel",
+                               g_variant_new("(o)", info->obj_channel_path),
+                               NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+                               hdp_disconnect_request_cb, param);
+
+       g_free(dev_path);
 
        ret = BT_ERROR_NONE;
+done:
        return ret;
 }
index f339c23..85aaa94 100644 (file)
 *
 */
 
+#include <stdbool.h>
+#include <gio/gio.h>
+#include <dbus/dbus.h>
+#include <gio/gunixfdlist.h>
 #include <string.h>
 #include <stdio.h>
 #include "common.h"
@@ -37,6 +41,8 @@ struct error_map_t {
        {NULL,                          ERROR_NONE},
 };
 
+static GDBusConnection *conn;
+
 enum bluez_error_type get_error_type(GError *error)
 {
        int i = 0;
@@ -303,3 +309,20 @@ void convert_addr_string_to_type(unsigned char *addr,
                }
        }
 }
+
+GDBusConnection *get_system_lib_dbus_connect(void)
+{
+       GError *error = NULL;
+
+       if (conn)
+               return conn;
+
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (conn == NULL) {
+               DBG("%s", error->message);
+
+               g_error_free(error);
+       }
+
+       return conn;
+}