bluez: refactor to use glib and add connection state tracking
authorNick Stoughton <nstoughton@aether.com>
Tue, 30 Dec 2014 15:21:44 +0000 (07:21 -0800)
committerArun Raghavan <git@arunraghavan.net>
Fri, 3 Jul 2015 10:11:52 +0000 (15:41 +0530)
configure.ac
sys/bluez/Makefile.am
sys/bluez/gstavdtpsink.c
sys/bluez/gstavdtpsrc.c
sys/bluez/gstavdtputil.c
sys/bluez/gstavdtputil.h
sys/bluez/org.bluez.xml [new file with mode: 0644]

index 82f6022..de53bb8 100644 (file)
@@ -1620,8 +1620,13 @@ AG_GST_CHECK_FEATURE(BLUEZ, [Bluez], bluez, [
     AC_DEFINE(HAVE_BLUEZ4,[1],[Old bluez detected])
   ], [
     PKG_CHECK_MODULES([BLUEZ5], [bluez >= 5.0], [
-      HAVE_BLUEZ=yes
-      AC_DEFINE(HAVE_BLUEZ5,[1],[Current bluez detected])
+      PKG_CHECK_MODULES([GIO_UNIX], gio-unix-2.0 > 2.24, [
+        AC_CHECK_PROG([GDBUS_CODEGEN],[gdbus-codegen],[gdbus-codegen])
+        HAVE_BLUEZ=yes
+        AC_DEFINE(HAVE_BLUEZ5,[1],[Current bluez detected])
+      ], [
+        HAVE_BLUEZ=no
+      ])
     ], [
       HAVE_BLUEZ=no
     ])
index cc90176..b67c8ba 100644 (file)
@@ -5,20 +5,23 @@ libgstbluez_la_SOURCES = \
        gsta2dpsink.c \
        gstavdtpsink.c \
        gstavdtpsrc.c \
-       gstavdtputil.c
+       gstavdtputil.c \
+       $(BUILT_SOURCES)
 
 libgstbluez_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) \
        $(GST_PLUGINS_BASE_CFLAGS) \
        $(GST_BASE_CFLAGS) \
        $(GST_CFLAGS) \
-       $(DBUS_CFLAGS)
+       $(GIO_CFLAGS) \
+       $(GIO_UNIX_CFLAGS)
 libgstbluez_la_LIBADD = \
        $(GST_PLUGINS_BASE_LIBS) \
        -lgstaudio-$(GST_API_VERSION) \
        -lgstrtp-$(GST_API_VERSION) \
        $(GST_BASE_LIBS) \
        $(GST_LIBS) \
-       $(DBUS_LIBS)
+       $(GIO_LIBS) \
+       $(GIO_UNIX_LIBS)
 libgstbluez_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstbluez_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 
@@ -27,4 +30,17 @@ noinst_HEADERS = \
        gsta2dpsink.h \
        gstavdtpsink.h \
        gstavdtpsrc.h \
-       gstavdtputil.h
+       gstavdtputil.h \
+       bluez.h
+
+BUILT_SOURCES = \
+       bluez.h \
+       bluez.c
+
+bluez.h: bluez.c
+bluez.c: org.bluez.xml
+       $(AM_V_GEN) $(GDBUS_CODEGEN) \
+        --c-namespace=Bluez \
+        --generate-c-code=bluez \
+        --interface-prefix=org.bluez \
+        $<
index b549caa..70dc742 100644 (file)
@@ -34,8 +34,6 @@
 #include <fcntl.h>
 #include <netinet/in.h>
 
-#include <dbus/dbus.h>
-
 #include "a2dp-codecs.h"
 
 #include "gstavdtpsink.h"
@@ -263,7 +261,7 @@ gst_avdtp_sink_start (GstBaseSink * basesink)
   if (self->conn.transport == NULL)
     return FALSE;
 
-  if (!gst_avdtp_connection_acquire (&self->conn)) {
+  if (!gst_avdtp_connection_acquire (&self->conn, FALSE)) {
     GST_ERROR_OBJECT (self, "Failed to acquire connection");
     return FALSE;
   }
index 311c407..176c2d4 100644 (file)
@@ -39,7 +39,7 @@ GST_DEBUG_CATEGORY_STATIC (avdtpsrc_debug);
 enum
 {
   PROP_0,
-  PROP_TRANSPORT
+  PROP_TRANSPORT,
 };
 
 #define parent_class gst_avdtp_src_parent_class
@@ -262,7 +262,7 @@ gst_avdtp_src_start (GstBaseSrc * bsrc)
    * connection to figure out what format the device is going to send us.
    */
 
-  if (!gst_avdtp_connection_acquire (&avdtpsrc->conn)) {
+  if (!gst_avdtp_connection_acquire (&avdtpsrc->conn, FALSE)) {
     GST_ERROR_OBJECT (avdtpsrc, "Failed to acquire connection");
     return FALSE;
   }
index 787a063..52a90a5 100644 (file)
 #include <bluetooth/bluetooth.h>
 #include "a2dp-codecs.h"
 
+#include <gio/gunixfdlist.h>
 #include <gst/gst.h>
 #include "gstavdtputil.h"
+#include "bluez.h"
 
 #define TEMPLATE_MAX_BITPOOL 64
 
 GST_DEBUG_CATEGORY_EXTERN (avdtp_debug);
 #define GST_CAT_DEFAULT avdtp_debug
 
+static void gst_avdtp_connection_transport_release (GstAvdtpConnection * conn);
+
+static gboolean
+on_state_change (BluezMediaTransport1 * proxy, GParamSpec * pspec,
+    GstAvdtpConnection * conn)
+{
+  const gchar *newstate;
+  gboolean is_idle;
+
+  newstate = bluez_media_transport1_get_state (proxy);
+  is_idle = g_str_equal (newstate, "idle");
+
+  if (!conn->data.is_acquired && !is_idle) {
+    GST_DEBUG ("Re-acquiring connection");
+    gst_avdtp_connection_acquire (conn, TRUE);
+
+  } else if (is_idle) {
+    /* We don't know if we need to release the transport -- that may have been
+     * done for us by bluez already! Or not ... so release it just in case, but
+     * mark its stale beforehand to suppress any errors. */
+    GST_DEBUG ("Marking connection stale");
+    conn->data.is_acquired = FALSE;
+    gst_avdtp_connection_transport_release (conn);
+
+  } else
+    GST_DEBUG ("State is %s, acquired is %s", newstate,
+        conn->data.is_acquired ? "true" : "false");
+
+  return TRUE;
+}
+
 gboolean
-gst_avdtp_connection_acquire (GstAvdtpConnection * conn)
+gst_avdtp_connection_acquire (GstAvdtpConnection * conn, gboolean use_try)
 {
-  DBusMessage *msg, *reply;
-  DBusError err;
-#ifdef HAVE_BLUEZ4
-  const char *access_type = "rw";
-#endif
+  GVariant *handle = NULL;
+  GUnixFDList *fd_list = NULL;
+  GError *err = NULL;
   int fd;
   uint16_t imtu, omtu;
 
-  dbus_error_init (&err);
-
   if (conn->transport == NULL) {
     GST_ERROR ("No transport specified");
     return FALSE;
   }
 
-  if (conn->data.conn == NULL)
-    conn->data.conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
-
-#ifdef HAVE_BLUEZ4
-  msg = dbus_message_new_method_call ("org.bluez", conn->transport,
-      "org.bluez.MediaTransport", "Acquire");
+  if (conn->data.conn == NULL) {
+    conn->data.conn =
+        bluez_media_transport1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+        G_DBUS_PROXY_FLAGS_NONE, "org.bluez", conn->transport, NULL, &err);
 
-  dbus_message_append_args (msg, DBUS_TYPE_STRING, &access_type,
-      DBUS_TYPE_INVALID);
-#else
-  msg = dbus_message_new_method_call ("org.bluez", conn->transport,
-      "org.bluez.MediaTransport1", "Acquire");
-#endif
+    if (conn->data.conn == NULL) {
+      GST_ERROR ("Failed to create proxy for media transport: %s",
+          err && err->message ? err->message : "Unknown error");
+      return FALSE;
+    }
 
-  reply = dbus_connection_send_with_reply_and_block (conn->data.conn,
-      msg, -1, &err);
+    g_signal_connect (conn->data.conn, "notify::state",
+        G_CALLBACK (on_state_change), conn);
+  }
 
-  dbus_message_unref (msg);
+  if (conn->data.is_acquired) {
+    GST_INFO ("Transport is already acquired");
+    return TRUE;
+  }
 
-  if (dbus_error_is_set (&err))
-    goto fail;
+  if (use_try) {
+    if (!bluez_media_transport1_call_try_acquire_sync (conn->data.conn,
+            NULL, &handle, &imtu, &omtu, &fd_list, NULL, &err))
+      goto fail;
+  } else {
+    if (!bluez_media_transport1_call_acquire_sync (conn->data.conn,
+            NULL, &handle, &imtu, &omtu, &fd_list, NULL, &err))
+      goto fail;
+  }
 
-  if (dbus_message_get_args (reply, &err, DBUS_TYPE_UNIX_FD, &fd,
-          DBUS_TYPE_UINT16, &imtu,
-          DBUS_TYPE_UINT16, &omtu, DBUS_TYPE_INVALID) == FALSE)
+  fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (handle), &err);
+  if (fd < 0)
     goto fail;
 
-  dbus_message_unref (reply);
-
+  g_variant_unref (handle);
+  g_object_unref (fd_list);
   conn->stream = g_io_channel_unix_new (fd);
   g_io_channel_set_encoding (conn->stream, NULL, NULL);
   g_io_channel_set_close_on_unref (conn->stream, TRUE);
   conn->data.link_mtu = omtu;
+  conn->data.is_acquired = TRUE;
 
   return TRUE;
 
 fail:
-  GST_ERROR ("Failed to acquire transport stream: %s", err.message);
-
-  dbus_error_free (&err);
+  GST_ERROR ("Failed to %s transport stream: %s", use_try ? "try_acquire" :
+      "acquire", err && err->message ? err->message : "unknown error");
 
-  if (reply)
-    dbus_message_unref (reply);
+  g_clear_error (&err);
+  if (handle)
+    g_variant_unref (handle);
 
+  conn->data.is_acquired = FALSE;
   return FALSE;
 }
 
 static void
 gst_avdtp_connection_transport_release (GstAvdtpConnection * conn)
 {
-  DBusMessage *msg;
-#ifdef HAVE_BLUEZ4
-  const char *access_type = "rw";
-
-  msg = dbus_message_new_method_call ("org.bluez", conn->transport,
-      "org.bluez.MediaTransport", "Release");
+  GError *err = NULL;
 
-  dbus_message_append_args (msg, DBUS_TYPE_STRING, &access_type,
-      DBUS_TYPE_INVALID);
-#else
-  msg = dbus_message_new_method_call ("org.bluez", conn->transport,
-      "org.bluez.MediaTransport1", "Release");
-#endif
-  dbus_connection_send (conn->data.conn, msg, NULL);
+  if (!bluez_media_transport1_call_release_sync (conn->data.conn, NULL, &err)) {
+    /* We don't care about errors if the transport was already marked stale */
+    if (!conn->data.is_acquired)
+      return;
 
-  dbus_message_unref (msg);
+    GST_ERROR ("Failed to release transport stream: %s", err->message ?
+        err->message : "unknown error");
+  }
+  conn->data.is_acquired = FALSE;
 }
 
 void
@@ -153,9 +186,7 @@ gst_avdtp_connection_release (GstAvdtpConnection * conn)
     if (conn->transport)
       gst_avdtp_connection_transport_release (conn);
 
-    dbus_connection_unref (conn->data.conn);
-
-    conn->data.conn = NULL;
+    g_clear_object (&conn->data.conn);
   }
 }
 
@@ -194,145 +225,22 @@ gst_avdtp_connection_set_transport (GstAvdtpConnection * conn,
   conn->transport = g_strdup (transport);
 }
 
-static gboolean
-gst_avdtp_connection_parse_property (GstAvdtpConnection * conn,
-    DBusMessageIter * i)
-{
-  const char *key;
-  DBusMessageIter variant_i;
-
-  if (dbus_message_iter_get_arg_type (i) != DBUS_TYPE_STRING) {
-    GST_ERROR ("Property name not a string.");
-    return FALSE;
-  }
-
-  dbus_message_iter_get_basic (i, &key);
-
-  if (!dbus_message_iter_next (i)) {
-    GST_ERROR ("Property value missing");
-    return FALSE;
-  }
-
-  if (dbus_message_iter_get_arg_type (i) != DBUS_TYPE_VARIANT) {
-    GST_ERROR ("Property value not a variant.");
-    return FALSE;
-  }
-
-  dbus_message_iter_recurse (i, &variant_i);
-
-  switch (dbus_message_iter_get_arg_type (&variant_i)) {
-    case DBUS_TYPE_BYTE:{
-      uint8_t value;
-      dbus_message_iter_get_basic (&variant_i, &value);
-
-      if (g_str_equal (key, "Codec") == TRUE)
-        conn->data.codec = value;
-
-      break;
-    }
-    case DBUS_TYPE_STRING:{
-      const char *value;
-      dbus_message_iter_get_basic (&variant_i, &value);
-
-      if (g_str_equal (key, "UUID") == TRUE) {
-        g_free (conn->data.uuid);
-        conn->data.uuid = g_strdup (value);
-      }
-
-      break;
-    }
-    case DBUS_TYPE_ARRAY:{
-      DBusMessageIter array_i;
-      char *value;
-      int size;
-
-      dbus_message_iter_recurse (&variant_i, &array_i);
-      dbus_message_iter_get_fixed_array (&array_i, &value, &size);
-
-      if (g_str_equal (key, "Configuration")) {
-        g_free (conn->data.config);
-        conn->data.config = g_new0 (guint8, size);
-        conn->data.config_size = size;
-        memcpy (conn->data.config, value, size);
-      }
-
-      break;
-    }
-  }
-
-  return TRUE;
-}
-
 gboolean
 gst_avdtp_connection_get_properties (GstAvdtpConnection * conn)
 {
-  DBusMessage *msg, *reply;
-  DBusMessageIter arg_i, ele_i;
-  DBusError err;
-#ifndef HAVE_BLUEZ4
-  const char *interface;
-#endif
-
-  dbus_error_init (&err);
-
-#ifdef HAVE_BLUEZ4
-  msg = dbus_message_new_method_call ("org.bluez", conn->transport,
-      "org.bluez.MediaTransport", "GetProperties");
-#else
-  msg = dbus_message_new_method_call ("org.bluez", conn->transport,
-      "org.freedesktop.DBus.Properties", "GetAll");
-#endif
-  if (!msg) {
-    GST_ERROR ("D-Bus Memory allocation failed");
-    return FALSE;
-  }
-#ifndef HAVE_BLUEZ4
-  interface = "org.bluez.MediaTransport1";
-  dbus_message_append_args (msg, DBUS_TYPE_STRING, &interface,
-        DBUS_TYPE_INVALID);
-#endif
-  reply = dbus_connection_send_with_reply_and_block (conn->data.conn,
-      msg, -1, &err);
-
-  dbus_message_unref (msg);
-
-  if (dbus_error_is_set (&err)) {
-    GST_ERROR ("GetProperties failed: %s", err.message);
-    dbus_error_free (&err);
-    return FALSE;
-  }
-
-  if (!dbus_message_iter_init (reply, &arg_i)) {
-    GST_ERROR ("GetProperties reply has no arguments.");
-    goto fail;
-  }
-
-  if (dbus_message_iter_get_arg_type (&arg_i) != DBUS_TYPE_ARRAY) {
-    GST_ERROR ("GetProperties argument is not an array.");
-    goto fail;
-  }
-
-  dbus_message_iter_recurse (&arg_i, &ele_i);
-  while (dbus_message_iter_get_arg_type (&ele_i) != DBUS_TYPE_INVALID) {
+  GVariant *var;
 
-    if (dbus_message_iter_get_arg_type (&ele_i) == DBUS_TYPE_DICT_ENTRY) {
-      DBusMessageIter dict_i;
+  conn->data.codec = bluez_media_transport1_get_codec (conn->data.conn);
 
-      dbus_message_iter_recurse (&ele_i, &dict_i);
+  conn->data.uuid = bluez_media_transport1_dup_uuid (conn->data.conn);
 
-      gst_avdtp_connection_parse_property (conn, &dict_i);
-    }
-
-    if (!dbus_message_iter_next (&ele_i))
-      break;
-  }
+  var = bluez_media_transport1_dup_configuration (conn->data.conn);
+  conn->data.config_size = g_variant_get_size (var);
+  conn->data.config = g_new0 (guint8, conn->data.config_size);
+  g_variant_store (var, conn->data.config);
+  g_variant_unref (var);
 
   return TRUE;
-
-fail:
-  dbus_message_unref (reply);
-  return FALSE;
-
 }
 
 static GstStructure *
index b551781..1319441 100644 (file)
 
 #include <glib.h>
 
-#include <dbus/dbus.h>
+#include "bluez.h"
 
 G_BEGIN_DECLS
+
 #define DEFAULT_CODEC_BUFFER_SIZE 2048
 #define TEMPLATE_MAX_BITPOOL_STR "64"
-    struct bluetooth_data
+
+struct bluetooth_data
 {
   guint link_mtu;
 
-  DBusConnection *conn;
+  BluezMediaTransport1 *conn;
   guint8 codec;                 /* Bluetooth transport configuration */
   gchar *uuid;
   guint8 *config;
   gint config_size;
+  gboolean is_acquired;
 
   gchar buffer[DEFAULT_CODEC_BUFFER_SIZE];      /* Codec transfer buffer */
 };
@@ -56,7 +59,8 @@ struct _GstAvdtpConnection
   struct bluetooth_data data;
 };
 
-gboolean gst_avdtp_connection_acquire (GstAvdtpConnection * conn);
+gboolean gst_avdtp_connection_acquire (GstAvdtpConnection * conn,
+    gboolean use_try);
 void gst_avdtp_connection_release (GstAvdtpConnection * conn);
 void gst_avdtp_connection_reset (GstAvdtpConnection * conn);
 gboolean gst_avdtp_connection_get_properties (GstAvdtpConnection * conn);
diff --git a/sys/bluez/org.bluez.xml b/sys/bluez/org.bluez.xml
new file mode 100644 (file)
index 0000000..ff52ee3
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<node>
+<interface name="org.bluez.MediaTransport1">
+    <method name="Acquire">
+        <annotation name="org.gtk.GDBus.C.UnixFD" value="true" />
+        <arg name="fd" type="h" direction="out"/>
+        <arg name="mtu_r" type="q" direction="out"/>
+        <arg name="mtu_w" type="q" direction="out"/>
+    </method>
+    <method name="TryAcquire">
+        <annotation name="org.gtk.GDBus.C.UnixFD" value="true" />
+        <arg name="fd" type="h" direction="out"/>
+        <arg name="mtu_r" type="q" direction="out"/>
+        <arg name="mtu_w" type="q" direction="out"/>
+    </method>
+    <method name="Release"></method>
+    <property name="Device" type="o" access="read"></property>
+    <property name="UUID" type="s" access="read"></property>
+    <property name="Codec" type="y" access="read"></property>
+    <property name="Configuration" type="ay" access="read">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true" />
+    </property>
+    <property name="State" type="s" access="read"></property>
+    <property name="Delay" type="q" access="read"></property>
+    <property name="Volume" type="q" access="readwrite"></property>
+</interface>
+</node>