[pulseaudio-commits] Branch 'next' - 6 commits - src/modules

Tanu Kaskinen tanuk at kemper.freedesktop.org
Tue May 14 03:00:16 PDT 2013


 src/modules/bluetooth/bluetooth-util.c          |  236 +++++++++++++++++++++---
 src/modules/bluetooth/module-bluetooth-device.c |    8 
 2 files changed, 211 insertions(+), 33 deletions(-)

New commits:
commit 6d50c0c62f698699aa7e97cf0126ca43efb740fd
Author: Mikel Astiz <mikel.astiz at bmw-carit.de>
Date:   Fri May 10 10:30:47 2013 +0200

    bluetooth: Support transport auto-release
    
    With BlueZ 5, if the remote device suspends the audio, the transport
    state will change to "idle" and the endpoint is not required to release
    the transport, since this could introduce race conditions. Therefore,
    ignore the call to pa_bluetooth_transport_release() if the transport is
    not acquired any more.

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 2e794ac..5924736 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -1538,6 +1538,12 @@ void pa_bluetooth_transport_release(pa_bluetooth_transport *t) {
         pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
     } else {
         pa_assert(t->device->discovery->version == BLUEZ_VERSION_5);
+
+        if (t->state <= PA_BLUETOOTH_TRANSPORT_STATE_IDLE) {
+            pa_log_info("Transport %s auto-released by BlueZ or already released", t->path);
+            return;
+        }
+
         pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport1", "Release"));
     }
 

commit 477c0ebde37ac2ecd045ee2a574d4a7b1babd321
Author: Mikel Astiz <mikel.astiz at bmw-carit.de>
Date:   Fri May 10 10:30:46 2013 +0200

    bluetooth: Update to new BlueZ 5 transport acquire/release API
    
    The new D-Bus API doesn't support access rights, which weren't used by
    PulseAudio anyway, but it does solve a race condition: now optional
    acquires can be implemented by bluetooth-util atomically using the D-Bus
    TryAcquire() method.

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index ff8afaa..2e794ac 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -1452,40 +1452,52 @@ bool pa_bluetooth_device_any_audio_connected(const pa_bluetooth_device *d) {
 }
 
 int pa_bluetooth_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
-    const char *accesstype = "rw";
-    const char *interface;
     DBusMessage *m, *r;
     DBusError err;
     int ret;
     uint16_t i, o;
+    const char *method;
 
     pa_assert(t);
     pa_assert(t->device);
     pa_assert(t->device->discovery);
 
-    interface = t->device->discovery->version == BLUEZ_VERSION_4 ? "org.bluez.MediaTransport" : "org.bluez.MediaTransport1";
-
-    if (optional) {
-        /* FIXME: we are trying to acquire the transport only if the stream is
-           playing, without actually initiating the stream request from our side
-           (which is typically undesireable specially for hfgw use-cases.
-           However this approach is racy, since the stream could have been
-           suspended in the meantime, so we can't really guarantee that the
-           stream will not be requested until BlueZ's API supports this
-           atomically. */
-        if (t->state < PA_BLUETOOTH_TRANSPORT_STATE_PLAYING) {
-            pa_log_info("Failed optional acquire of transport %s", t->path);
-            return -1;
+    dbus_error_init(&err);
+
+    if (t->device->discovery->version == BLUEZ_VERSION_4) {
+        const char *accesstype = "rw";
+
+        if (optional) {
+            /* We are trying to acquire the transport only if the stream is
+               playing, without actually initiating the stream request from our side
+               (which is typically undesireable specially for hfgw use-cases.
+               However this approach is racy, since the stream could have been
+               suspended in the meantime, so we can't really guarantee that the
+               stream will not be requested with the API in BlueZ 4.x */
+            if (t->state < PA_BLUETOOTH_TRANSPORT_STATE_PLAYING) {
+                pa_log_info("Failed optional acquire of unavailable transport %s", t->path);
+                return -1;
+            }
         }
-    }
 
-    dbus_error_init(&err);
+        method = "Acquire";
+        pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport", method));
+        pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
+    } else {
+        pa_assert(t->device->discovery->version == BLUEZ_VERSION_5);
+
+        method = optional ? "TryAcquire" : "Acquire";
+        pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport1", method));
+    }
 
-    pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, interface, "Acquire"));
-    pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
     r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
 
     if (!r) {
+        if (optional && pa_streq(err.name, "org.bluez.Error.NotAvailable"))
+            pa_log_info("Failed optional acquire of unavailable transport %s", t->path);
+        else
+            pa_log("Transport %s() failed for transport %s (%s)", method, t->path, err.message);
+
         dbus_error_free(&err);
         return -1;
     }
@@ -1510,8 +1522,6 @@ fail:
 }
 
 void pa_bluetooth_transport_release(pa_bluetooth_transport *t) {
-    const char *accesstype = "rw";
-    const char *interface;
     DBusMessage *m;
     DBusError err;
 
@@ -1519,12 +1529,18 @@ void pa_bluetooth_transport_release(pa_bluetooth_transport *t) {
     pa_assert(t->device);
     pa_assert(t->device->discovery);
 
-    interface = t->device->discovery->version == BLUEZ_VERSION_4 ? "org.bluez.MediaTransport" : "org.bluez.MediaTransport1";
-
     dbus_error_init(&err);
 
-    pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, interface, "Release"));
-    pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
+    if (t->device->discovery->version == BLUEZ_VERSION_4) {
+        const char *accesstype = "rw";
+
+        pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport", "Release"));
+        pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID));
+    } else {
+        pa_assert(t->device->discovery->version == BLUEZ_VERSION_5);
+        pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport1", "Release"));
+    }
+
     dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
 
     if (dbus_error_is_set(&err)) {
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 4146c0d..290f5ce 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -368,14 +368,8 @@ static int bt_transport_acquire(struct userdata *u, bool optional) {
     pa_log_debug("Acquiring transport %s", u->transport->path);
 
     u->stream_fd = pa_bluetooth_transport_acquire(u->transport, optional, &u->read_link_mtu, &u->write_link_mtu);
-    if (u->stream_fd < 0) {
-        if (!optional)
-            pa_log("Failed to acquire transport %s", u->transport->path);
-        else
-            pa_log_info("Failed optional acquire of transport %s", u->transport->path);
-
+    if (u->stream_fd < 0)
         return -1;
-    }
 
     u->transport_acquired = true;
     pa_log_info("Transport %s acquired: fd %d", u->transport->path, u->stream_fd);

commit 3ccabdc3626e40036fdf2e5c0df57538cf871e0b
Author: Mikel Astiz <mikel.astiz at bmw-carit.de>
Date:   Fri May 10 10:30:45 2013 +0200

    bluetooth: Support media transport's State property
    
    BlueZ 5 exposes a 'State' property in the media transport interface.
    With regard to PA, this replaces the profile-specific interfaces, since
    they were being used to know if the audio was streaming or not.

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index a0e6811..ff8afaa 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -126,6 +126,20 @@ static pa_bt_audio_state_t audio_state_from_string(const char* value) {
     return PA_BT_AUDIO_STATE_INVALID;
 }
 
+static int transport_state_from_string(const char* value, pa_bluetooth_transport_state_t *state) {
+    pa_assert(value);
+    pa_assert(state);
+
+    if (pa_streq(value, "idle"))
+        *state = PA_BLUETOOTH_TRANSPORT_STATE_IDLE;
+    else if (pa_streq(value, "pending") || pa_streq(value, "active")) /* We don't need such a separation */
+        *state = PA_BLUETOOTH_TRANSPORT_STATE_PLAYING;
+    else
+        return -1;
+
+    return 0;
+}
+
 const char *pa_bt_profile_to_string(enum profile profile) {
     switch(profile) {
         case PROFILE_A2DP:
@@ -1089,6 +1103,29 @@ static int transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *
 
             break;
          }
+
+        case DBUS_TYPE_STRING: {
+
+            const char *value;
+            dbus_message_iter_get_basic(&variant_i, &value);
+
+            if (pa_streq(key, "State")) { /* Added in BlueZ 5.0 */
+                bool old_any_connected = pa_bluetooth_device_any_audio_connected(t->device);
+
+                if (transport_state_from_string(value, &t->state) < 0) {
+                    pa_log("Transport %s has an invalid state: '%s'", t->path, value);
+                    return -1;
+                }
+
+                pa_log_debug("dbus: transport %s set to state '%s'", t->path, value);
+                pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED], t);
+
+                if (old_any_connected != pa_bluetooth_device_any_audio_connected(t->device))
+                    run_callback(t->device, old_any_connected);
+            }
+
+            break;
+        }
     }
 
     return 0;
@@ -1567,7 +1604,10 @@ static pa_bluetooth_transport *transport_new(pa_bluetooth_device *d, const char
         memcpy(t->config, config, size);
     }
 
-    t->state = audio_state_to_transport_state(d->profile_state[p]);
+    if (d->discovery->version == BLUEZ_VERSION_4)
+        t->state = audio_state_to_transport_state(d->profile_state[p]);
+    else
+        t->state = PA_BLUETOOTH_TRANSPORT_STATE_IDLE;
 
     return t;
 }

commit 9ebb383a959272c18f3eabd91876c15cb6f69739
Author: Mikel Astiz <mikel.astiz at bmw-carit.de>
Date:   Fri May 10 10:30:44 2013 +0200

    bluetooth: Parse media transport's properties
    
    Add the code to parse the properties of the media transport object when
    a PropertiesChanged signal is received.
    
    Note that the transport might have an owner other than BlueZ, and thus
    the property changes would be emitted from arbitrary senders. For
    performance reasons, the installed match considers the interface name
    where the property has changed.
    
    It could be possible to install and remove the D-Bus matches dynamically
    when a new owner is registered/unregistered, but filtering based on the
    interface name seems good enough already.

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index a32227a..a0e6811 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -1094,6 +1094,24 @@ static int transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *
     return 0;
 }
 
+static int parse_transport_properties(pa_bluetooth_transport *t, DBusMessageIter *i) {
+    DBusMessageIter element_i;
+
+    dbus_message_iter_recurse(i, &element_i);
+
+    while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
+        DBusMessageIter dict_i;
+
+        dbus_message_iter_recurse(&element_i, &dict_i);
+
+        transport_parse_property(t, &dict_i);
+
+        dbus_message_iter_next(&element_i);
+    }
+
+    return 0;
+}
+
 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
     DBusError err;
     pa_bluetooth_discovery *y;
@@ -1315,6 +1333,13 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
             }
 
             parse_device_properties(d, &arg_i, true);
+        } else if (pa_streq(interface, "org.bluez.MediaTransport1")) {
+            pa_bluetooth_transport *t;
+
+            if (!(t = pa_hashmap_get(y->transports, dbus_message_get_path(m))))
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+            parse_transport_properties(t, &arg_i);
         }
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -1979,6 +2004,8 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
                 "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'",
                 "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
                 ",arg0='org.bluez.Device1'",
+                "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
+                ",arg0='org.bluez.MediaTransport1'",
                 NULL) < 0) {
         pa_log("Failed to add D-Bus matches: %s", err.message);
         goto fail;
@@ -2056,6 +2083,8 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
             "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'",
             "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
             ",arg0='org.bluez.Device1'",
+            "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
+            ",arg0='org.bluez.MediaTransport1'",
             NULL);
 
         if (y->filter_added)

commit 76103823d2b12d776938730a02349e37d957e237
Author: Mikel Astiz <mikel.astiz at bmw-carit.de>
Date:   Fri May 10 10:30:43 2013 +0200

    bluetooth: Support Properties.PropertiesChanged signal
    
    Install matches for signal Properties.PropertiesChanged and process the
    properties corresponding to the tracked devices.

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index cb7d3c4..a32227a 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -1289,6 +1289,35 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
         }
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
+        DBusMessageIter arg_i;
+        const char *interface;
+
+        if (y->version != BLUEZ_VERSION_5)
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
+
+        if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "sa{sv}as")) {
+            pa_log("Invalid signature found in PropertiesChanged");
+            goto fail;
+        }
+
+        dbus_message_iter_get_basic(&arg_i, &interface);
+
+        pa_assert_se(dbus_message_iter_next(&arg_i));
+        pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY);
+
+        if (pa_streq(interface, "org.bluez.Device1")) {
+            pa_bluetooth_device *d;
+
+            if (!(d = pa_hashmap_get(y->devices, dbus_message_get_path(m)))) {
+                pa_log_warn("Property change in unknown device %s", dbus_message_get_path(m));
+                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+            }
+
+            parse_device_properties(d, &arg_i, true);
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
 fail:
@@ -1948,6 +1977,8 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
                 "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
                 "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'",
                 "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'",
+                "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
+                ",arg0='org.bluez.Device1'",
                 NULL) < 0) {
         pa_log("Failed to add D-Bus matches: %s", err.message);
         goto fail;
@@ -2023,6 +2054,8 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
             "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
             "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'",
             "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'",
+            "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
+            ",arg0='org.bluez.Device1'",
             NULL);
 
         if (y->filter_added)

commit f699185366b4d81afd1e5754a6065fda98de4127
Author: Mikel Astiz <mikel.astiz at bmw-carit.de>
Date:   Fri May 10 10:30:42 2013 +0200

    bluetooth: Support ObjectManager interface add/remove
    
    Install matches for signals ObjectManager.InterfacesAdded and
    ObjectManager.InterfacesRemoved, and process the devices that are
    registered and unregistered dynamically.

diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index fb8f753..cb7d3c4 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -1233,6 +1233,62 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
             goto fail;
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")) {
+        DBusMessageIter arg_i;
+
+        if (y->version != BLUEZ_VERSION_5)
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
+
+        if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sa{sv}}")) {
+            pa_log("Invalid signature found in InterfacesAdded");
+            goto fail;
+        }
+
+        if (parse_interfaces_and_properties(y, &arg_i) < 0)
+            goto fail;
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved")) {
+        const char *path;
+        DBusMessageIter arg_i;
+        DBusMessageIter element_i;
+
+        if (y->version != BLUEZ_VERSION_5)
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
+
+        if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oas")) {
+            pa_log("Invalid signature found in InterfacesRemoved");
+            goto fail;
+        }
+
+        dbus_message_iter_get_basic(&arg_i, &path);
+
+        pa_assert_se(dbus_message_iter_next(&arg_i));
+        pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY);
+
+        dbus_message_iter_recurse(&arg_i, &element_i);
+
+        while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_STRING) {
+            const char *interface;
+
+            dbus_message_iter_get_basic(&element_i, &interface);
+
+            if (pa_streq(interface, "org.bluez.Device1")) {
+                pa_bluetooth_device *d;
+
+                if (!(d = pa_hashmap_remove(y->devices, path)))
+                    pa_log_warn("Unknown device removed %s", path);
+                else {
+                    pa_log_debug("Device %s removed", path);
+                    run_callback(d, true);
+                    device_free(d);
+                }
+            }
+
+            dbus_message_iter_next(&element_i);
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
 fail:
@@ -1890,6 +1946,8 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
                 "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
                 "type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
                 "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
+                "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'",
+                "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'",
                 NULL) < 0) {
         pa_log("Failed to add D-Bus matches: %s", err.message);
         goto fail;
@@ -1963,6 +2021,8 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
             "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
             "type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
             "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
+            "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'",
+            "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'",
             NULL);
 
         if (y->filter_added)



More information about the pulseaudio-commits mailing list