bluetooth: add proper handling for bluetooth.nrec property
authorLuiz Augusto von Dentz <luiz.dentz-von@nokia.com>
Fri, 14 Jan 2011 12:18:08 +0000 (14:18 +0200)
committerLuiz Augusto von Dentz <luiz.dentz-von@nokia.com>
Mon, 14 Mar 2011 17:52:52 +0000 (14:52 -0300)
NREC stands for Noise Reduction and Echo Cancelation, it can be changed
at any point by the headset.

When set to "1" indicates that those algorithms shall be enabled by
default and "0" means the headset probably have them active so they
should be disabled in PA side.

src/modules/bluetooth/bluetooth-util.c
src/modules/bluetooth/bluetooth-util.h
src/modules/bluetooth/module-bluetooth-device.c

index 17ba130..9c67968 100644 (file)
@@ -714,6 +714,47 @@ static void list_adapters(pa_bluetooth_discovery *y) {
     send_and_add_to_pending(y, NULL, m, list_adapters_reply);
 }
 
+int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i)
+{
+    const char *key;
+    DBusMessageIter variant_i;
+
+    if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
+        pa_log("Property name not a string.");
+        return -1;
+    }
+
+    dbus_message_iter_get_basic(i, &key);
+
+    if (!dbus_message_iter_next(i))  {
+        pa_log("Property value missing");
+        return -1;
+    }
+
+    if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
+        pa_log("Property value not a variant.");
+        return -1;
+    }
+
+    dbus_message_iter_recurse(i, &variant_i);
+
+    switch (dbus_message_iter_get_arg_type(&variant_i)) {
+
+        case DBUS_TYPE_BOOLEAN: {
+
+            pa_bool_t *value;
+            dbus_message_iter_get_basic(&variant_i, &value);
+
+            if (pa_streq(key, "NREC"))
+                t->nrec = value;
+
+            break;
+         }
+    }
+
+    return 0;
+}
+
 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
     DBusError err;
     pa_bluetooth_discovery *y;
@@ -862,6 +903,28 @@ 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.bluez.MediaTransport", "PropertyChanged")) {
+        pa_bluetooth_device *d;
+        pa_bluetooth_transport *t;
+        void *state = NULL;
+        DBusMessageIter arg_i;
+
+        while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
+            if ((t = pa_hashmap_get(d->transports, dbus_message_get_path(m))))
+                break;
+
+        if (!t)
+            goto fail;
+
+        if (!dbus_message_iter_init(m, &arg_i)) {
+            pa_log("Failed to parse PropertyChanged: %s", err.message);
+            goto fail;
+        }
+
+        if (pa_bluetooth_transport_parse_property(t, &arg_i) < 0)
+            goto fail;
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
 fail:
@@ -1035,6 +1098,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
     const char *path, *dev_path = NULL, *uuid = NULL;
     uint8_t *config = NULL;
     int size = 0;
+    pa_bool_t nrec;
     enum profile p;
     DBusMessageIter args, props;
     DBusMessage *r;
@@ -1070,6 +1134,10 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
             if (var != DBUS_TYPE_OBJECT_PATH)
                 goto fail;
             dbus_message_iter_get_basic(&value, &dev_path);
+        } else if (strcasecmp(key, "NREC") == 0) {
+            if (var != DBUS_TYPE_BOOLEAN)
+                goto fail;
+            dbus_message_iter_get_basic(&value, &nrec);
         } else if (strcasecmp(key, "Configuration") == 0) {
             DBusMessageIter array;
             if (var != DBUS_TYPE_ARRAY)
@@ -1093,6 +1161,8 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
         p = PROFILE_A2DP_SOURCE;
 
     t = transport_new(y, path, p, config, size);
+    if (nrec)
+        t->nrec = nrec;
     pa_hashmap_put(d->transports, t->path, t);
 
     pa_log_debug("Transport %s profile %d available", t->path, t->profile);
@@ -1402,6 +1472,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
                 "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
                 "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'",
                 NULL) < 0) {
         pa_log("Failed to add D-Bus matches: %s", err.message);
         goto fail;
@@ -1469,6 +1540,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
                                "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
                                "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'",
                                NULL);
 
         if (y->filter_added)
index b471c34..bb0cb24 100644 (file)
@@ -70,6 +70,7 @@ struct pa_bluetooth_transport {
     uint8_t codec;
     uint8_t *config;
     int config_size;
+    pa_bool_t nrec;
 };
 
 /* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */
@@ -128,6 +129,7 @@ const pa_bluetooth_transport* pa_bluetooth_device_get_transport(const pa_bluetoo
 
 int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *accesstype, size_t *imtu, size_t *omtu);
 void pa_bluetooth_transport_release(const pa_bluetooth_transport *t, const char *accesstype);
+int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i);
 
 pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *d);
 
index 75cf498..86aaa46 100644 (file)
@@ -1751,7 +1751,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
                  dbus_message_get_path(m),
                  dbus_message_get_member(m));
 
-    if (!dbus_message_has_path(m, u->path))
+    if (!dbus_message_has_path(m, u->path) && !dbus_message_has_path(m, u->transport))
         goto fail;
 
     if (dbus_message_is_signal(m, "org.bluez.Headset", "SpeakerGainChanged") ||
@@ -1777,6 +1777,28 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
                 pa_source_volume_changed(u->source, &v);
             }
         }
+    } else if (dbus_message_is_signal(m, "org.bluez.MediaTransport", "PropertyChanged")) {
+        DBusMessageIter arg_i;
+        pa_bluetooth_transport *t;
+        pa_bool_t nrec;
+
+        t = (pa_bluetooth_transport *) pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+        pa_assert(t);
+
+        if (!dbus_message_iter_init(m, &arg_i)) {
+            pa_log("Failed to parse PropertyChanged: %s", err.message);
+            goto fail;
+        }
+
+        nrec = t->nrec;
+
+        if (pa_bluetooth_transport_parse_property(t, &arg_i) < 0)
+            goto fail;
+
+        if (nrec != t->nrec) {
+            pa_log_debug("dbus: property 'NREC' changed to value '%s'", t->nrec ? "True" : "False");
+            pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
+        }
     }
 
 fail:
@@ -2018,6 +2040,7 @@ static int add_source(struct userdata *u) {
         pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP_SOURCE ? "a2dp_source" : "hsp");
         if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW))
             pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
+
         data.card = u->card;
         data.name = get_name("source", u->modargs, u->address, &b);
         data.namereg_fail = b;
@@ -2044,8 +2067,15 @@ static int add_source(struct userdata *u) {
                                     pa_bytes_to_usec(u->block_size, &u->sample_spec));
     }
 
-    if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW)
-        pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
+    if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW)) {
+        if (u->transport) {
+            const pa_bluetooth_transport *t;
+            t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+            pa_assert(t);
+            pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
+        } else
+            pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
+    }
 
     if (u->profile == PROFILE_HSP) {
         u->source->set_volume = source_set_volume_cb;
@@ -2196,50 +2226,6 @@ static int bt_transport_config(struct userdata *u) {
     return bt_transport_config_a2dp(u);
 }
 
-static int parse_transport_property(struct userdata *u, DBusMessageIter *i) {
-    const char *key;
-    DBusMessageIter variant_i;
-
-    pa_assert(u);
-    pa_assert(i);
-
-    if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
-        pa_log("Property name not a string.");
-        return -1;
-    }
-
-    dbus_message_iter_get_basic(i, &key);
-
-    if (!dbus_message_iter_next(i))  {
-        pa_log("Property value missing");
-        return -1;
-    }
-
-    if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
-        pa_log("Property value not a variant.");
-        return -1;
-    }
-
-    dbus_message_iter_recurse(i, &variant_i);
-
-    switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
-        case DBUS_TYPE_UINT16: {
-
-            uint16_t value;
-            dbus_message_iter_get_basic(&variant_i, &value);
-
-            if (pa_streq(key, "OMTU"))
-                u->link_mtu = value;
-
-            break;
-        }
-
-    }
-
-    return 0;
-}
-
 /* Run from main thread */
 static int bt_transport_open(struct userdata *u) {
     if (bt_transport_acquire(u, FALSE) < 0)
@@ -2725,7 +2711,7 @@ int pa__init(pa_module* m) {
     struct userdata *u;
     const char *address, *path;
     DBusError err;
-    char *mike, *speaker;
+    char *mike, *speaker, *transport;
     const pa_bluetooth_device *device;
 
     pa_assert(m);
@@ -2804,15 +2790,18 @@ int pa__init(pa_module* m) {
 
     speaker = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='SpeakerGainChanged',path='%s'", u->path);
     mike = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='MicrophoneGainChanged',path='%s'", u->path);
+    transport = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'");
 
     if (pa_dbus_add_matches(
                 pa_dbus_connection_get(u->connection), &err,
                 speaker,
                 mike,
+                transport,
                 NULL) < 0) {
 
         pa_xfree(speaker);
         pa_xfree(mike);
+        pa_xfree(transport);
 
         pa_log("Failed to add D-Bus matches: %s", err.message);
         goto fail;
@@ -2820,6 +2809,7 @@ int pa__init(pa_module* m) {
 
     pa_xfree(speaker);
     pa_xfree(mike);
+    pa_xfree(transport);
 
     /* Connect to the BT service */
     init_bt(u);