Implement the HDP signal event features 35/19835/1
authorWu Zheng <wu.zheng@intel.com>
Mon, 21 Apr 2014 10:31:44 +0000 (06:31 -0400)
committerWu Zheng <wu.zheng@intel.com>
Mon, 21 Apr 2014 10:31:44 +0000 (06:31 -0400)
connect/disconnect signal event is done.
HDP data receiving is done.

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

index f29b23b..aed5701 100644 (file)
@@ -542,4 +542,10 @@ int bluetooth_hdp_connect(const char *app_handle,
 int bluetooth_hdp_disconnect(unsigned int channel_id,
                        const bluetooth_device_address_t *device_address);
 
+void hdp_internal_handle_disconnect(gpointer user_data,
+                                               GVariant *param);
+
+void hdp_internal_handle_connect(gpointer user_data,
+                                               GVariant *param);
+
 #endif
index c574615..9b6beda 100644 (file)
@@ -48,6 +48,7 @@
 #define HDP_MANAGER_INTERFACE "org.bluez.HealthManager1"
 #define HDP_DEVICE_INTERFACE "org.bluez.HealthDevice1"
 #define HDP_CHANNEL_INTERFACE "org.bluez.HealthChannel1"
+#define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
 
 enum bluez_error_type {
        ERROR_NONE,
index 975c49a..8058835 100644 (file)
@@ -16,6 +16,8 @@ typedef struct {
        GSList *obj_info;
 } hdp_app_list_t;
 
+#define HDP_BUFFER_SIZE 1024
+
 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;
@@ -54,6 +56,302 @@ void bluez_unset_data_received_changed_cb()
        data_received_changed_data = NULL;
 }
 
+static hdp_obj_info_t *hdp_internal_gslist_obj_find_using_path(
+                                       const char *obj_channel_path)
+{
+       GSList *l;
+       GSList *iter;
+       hdp_obj_info_t *info = NULL;
+
+       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) {
+                       info = iter->data;
+                       if (!info)
+                               return NULL;
+
+                       if (0 == g_strcmp0(info->obj_channel_path,
+                                                       obj_channel_path)) {
+                               list->obj_info = g_slist_remove(list->obj_info,
+                                                                       info);
+                               return info;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static void hdp_internal_handle_disconnect_cb(int sk, const char *path)
+{
+       char address[BT_ADDRESS_STRING_SIZE] = { 0, };
+       hdp_obj_info_t *info;
+
+       DBG("******** Socket Error  ******\n");
+
+       info = hdp_internal_gslist_obj_find_using_path(path);
+       if (info == NULL)
+               return;
+
+       device_path_to_address(path, address);
+
+       if (hdp_state_changed_cb)
+               hdp_state_changed_cb(BT_ERROR_NONE, address, NULL,
+                               0, sk, hdp_state_changed_cb_data);
+
+       DBG(" Removed connection from list\n");
+
+       hdp_obj_info_free(info);
+}
+
+static gboolean hdp_internal_data_received(GIOChannel *gio,
+                               GIOCondition cond, gpointer data)
+{
+       char buff[HDP_BUFFER_SIZE] = { 0, };
+       int sk;
+       int act_read;
+       const char *path = (const char *)data;
+
+       DBG("+");
+
+       sk = g_io_channel_unix_get_fd(gio);
+
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+               DBG("GIOCondition %d.............path = %s\n", cond, path);
+               hdp_internal_handle_disconnect_cb(sk, path);
+               return FALSE;
+       }
+
+       act_read = recv(sk, (void *)buff, sizeof(buff), 0);
+
+       if (act_read > 0) {
+               DBG("Received data of %d\n", act_read);
+       } else {
+               DBG("Read failed.....\n");
+               return FALSE;
+       }
+
+       if (data_received_changed_cb)
+               data_received_changed_cb(sk, buff, act_read,
+                                       data_received_changed_data);
+
+       DBG("-\n");
+
+       return TRUE;
+}
+
+static void hdp_internal_watch_fd(int file_desc, const char *path)
+{
+       GIOChannel *gio;
+
+       DBG("+");
+
+       gio = g_io_channel_unix_new(file_desc);
+
+       g_io_channel_set_close_on_unref(gio, TRUE);
+
+       g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                               hdp_internal_data_received, (void *)path);
+
+       DBG("-");
+}
+
+static int hdp_internal_acquire_fd(GVariant *param, const char *path)
+{
+       char address[BT_ADDRESS_STRING_SIZE] = { 0, };
+       char *type_qos = NULL;
+       char *device = NULL;
+       char *app_handle = NULL;
+       hdp_app_list_t *list = NULL;
+       bt_hdp_channel_type_e type = HDP_QOS_RELIABLE;
+       hdp_obj_info_t *info;
+       int fd = 0;
+       GVariant *val;
+       GDBusConnection *conn;
+       int ret;
+       GError *error;
+
+       DBG("+");
+
+       conn = get_system_lib_dbus_connect();
+       if (conn == NULL) {
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       val = g_dbus_connection_call_sync(conn, BLUEZ_NAME, path,
+                               HDP_CHANNEL_INTERFACE, "Acquire",
+                               NULL, NULL, 0, -1, NULL, &error);
+
+       if (error) {
+               DBG(" HDP:****** dbus Can't create application ****");
+               DBG("error %s", error->message);
+               g_error_free(error);
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       g_variant_get(param, "h", &fd);
+       if (fd == 0) {
+               DBG("HDP:dbus Can't get reply arguments");
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       DBG("File Descriptor = %d, Dev_path = %s\n", fd, path);
+
+       val =  g_dbus_connection_call_sync(conn, BLUEZ_NAME, path,
+               PROPERTIES_INTERFACE, "GetAll",
+               g_variant_new("(s)", HDP_CHANNEL_INTERFACE),
+               NULL, 0, -1, NULL, &error);
+
+       if (error) {
+               DBG(" HDP:dbus Can't get the reply");
+               DBG("error %s", error->message);
+               g_error_free(error);
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       if (val != NULL) {
+               if (g_variant_is_of_type(val, G_VARIANT_TYPE("(a{sv})"))) {
+                       GVariantIter *iter;
+                       GVariant *item;
+                       g_variant_get(val, "(a{sv})", &iter);
+                       while ((item = g_variant_iter_next_value(iter))) {
+                               gchar *key;
+                               GVariant *value;
+                               g_variant_get(item, "{sv}", &key, &value);
+                               if (g_strcmp0("Type", key) == 0)
+                                       g_variant_get(value, "(s)", &type_qos);
+                               else if (g_strcmp0("Device", key) == 0)
+                                       g_variant_get(value, "(o)", &device);
+                               else if (g_strcmp0("Application", key) == 0)
+                                       g_variant_get(value, "(o)",
+                                                               &app_handle);
+                       }
+               }
+       }
+
+       DBG("QOS = %s, Device = %s, Apphandler = %s",
+                               type_qos, device, app_handle);
+
+       if (NULL == type_qos || NULL == app_handle) {
+               DBG("Pasing failed\n");
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       type = (g_strcmp0(type_qos, "Reliable") == 0) ?
+               HDP_QOS_RELIABLE : HDP_QOS_STREAMING;
+
+       list = hdp_internal_gslist_find_app_handler((void *)app_handle);
+
+       if (NULL == list) {
+               DBG("**** Could not locate the list for %s*****\n", app_handle);
+               ret = BT_ERROR_OPERATION_FAILED;
+               goto done;
+       }
+
+       info = g_new0(hdp_obj_info_t, 1);
+       info->fd = fd;
+       info->obj_channel_path = g_strdup(path);
+       list->obj_info = g_slist_append(list->obj_info, info);
+
+       hdp_internal_watch_fd(fd, info->obj_channel_path);
+
+       device_path_to_address(path, address);
+
+       DBG("Going to give callback\n");
+
+       if (hdp_state_changed_cb)
+               hdp_state_changed_cb(BT_ERROR_NONE,
+                               address, app_handle, type, fd,
+                               hdp_state_changed_cb_data);
+
+       DBG("Updated fd in the list*\n");
+       DBG("-\n");
+
+       ret = BT_ERROR_NONE;
+done:
+       DBG("error");
+
+       if (hdp_state_changed_cb)
+               hdp_state_changed_cb(BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED,
+                               address, app_handle, type, fd,
+                               hdp_state_changed_cb_data);
+
+       return ret;
+}
+
+void hdp_internal_handle_connect(gpointer user_data,
+                                               GVariant *param)
+{
+       const char *path = (const char *)user_data;
+       const char *obj_channel_path;
+
+       DBG("+********Signal - ChannelConnected******\n\n");
+       DBG("Path = %s", path);
+
+       g_variant_get(param, "o", &obj_channel_path);
+       if (obj_channel_path == NULL) {
+               DBG("Unexpected parameters in ChannelConnected signal");
+               return;
+       }
+
+       DBG("Channel connected, Path = %s", obj_channel_path);
+
+       hdp_internal_acquire_fd(param, obj_channel_path);
+
+       DBG("-");
+}
+
+void hdp_internal_handle_disconnect(gpointer user_data,
+                                               GVariant *param)
+{
+       const char *path = (const char *)user_data;
+       const char *obj_channel_path;
+       char address[BT_ADDRESS_STRING_SIZE] = { 0, };
+       hdp_obj_info_t *info;
+
+       DBG("+********Signal - ChannelDeleted ******\n\n");
+       DBG("Path = %s", path);
+
+       g_variant_get(param, "o", &obj_channel_path);
+
+       if (obj_channel_path == NULL) {
+               DBG("Unexpected parameters in ChannelDeleted signal");
+               return;
+       }
+
+       DBG("Channel Deleted, Path = %s", obj_channel_path);
+
+       info = hdp_internal_gslist_obj_find_using_path(obj_channel_path);
+       if (!info) {
+               DBG("No obj info for ob_channel_path [%s]\n",
+                                               obj_channel_path);
+               return;
+       }
+
+       device_path_to_address(path, address);
+
+       if (hdp_state_changed_cb)
+               hdp_state_changed_cb(BT_ERROR_NONE, address, NULL,
+                       0, info->fd, hdp_state_changed_cb_data);
+
+       DBG(" Removed connection from list\n");
+
+       hdp_obj_info_free(info);
+}
+
 static int hdp_internal_create_application(unsigned int data_type,
                                        int role,
                                        bt_hdp_qos_type_t channel_type,
index 9da32e7..526eddb 100644 (file)
@@ -33,7 +33,6 @@
 #define NETWORK_INTERFACE "org.bluez.Network1"
 #define AGENT_INTERFACE "org.bluez.AgentManager1"
 #define PROFILE_INTERFACE "org.bluez.ProfileManager1"
-#define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
 #define MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
 
 #define BT_MEDIA_OBJECT_PATH "/Musicplayer"
@@ -617,6 +616,36 @@ static void network_properties_changed(GDBusProxy *proxy,
        g_free(properties);
 }
 
+static void hdp_properties_changed(GDBusProxy *proxy,
+                                       GVariant *changed,
+                                       GStrv *invalidated,
+                                       gpointer user_data)
+{
+       char *path = NULL;
+
+       g_variant_lookup(changed,
+                               "MainChannel", "o", &path);
+
+       if (path == NULL)
+               return;
+
+       DBG("object_path = %s", path);
+}
+
+static void hdp_signal_changed(GDBusProxy *proxy,
+                                       gchar *sender_name,
+                                       gchar *signal_name,
+                                       GVariant *param,
+                                       gpointer user_data)
+{
+       if (g_strcmp0(signal_name, "ChannelConnected") == 0) {
+               hdp_internal_handle_connect(user_data, param);
+       } else if (g_strcmp0(signal_name, "ChannelDeleted")
+                                                       == 0) {
+               hdp_internal_handle_disconnect(user_data, param);
+       }
+}
+
 static void parse_bluez_device_interfaces(gpointer data, gpointer user_data)
 {
        struct _bluez_device *device = user_data;
@@ -647,6 +676,11 @@ static void parse_bluez_device_interfaces(gpointer data, gpointer user_data)
                device->network_proxy = proxy;
                g_signal_connect(proxy, "g-properties-changed",
                        G_CALLBACK(network_properties_changed), device);
+       } else if (g_strcmp0(iface_name, HDP_DEVICE_INTERFACE) == 0) {
+               g_signal_connect(proxy, "g-properties-changed",
+                       G_CALLBACK(hdp_properties_changed), device);
+               g_signal_connect(proxy, "g-signal",
+                       G_CALLBACK(hdp_signal_changed), device);
        }
 }