[pulseaudio-discuss] [PATCH v0] bluetooth: Fix potential assertion failure during pairing

Mikel Astiz mikel.astiz.oss at gmail.com
Mon Feb 11 02:42:53 PST 2013


From: Mikel Astiz <mikel.astiz at bmw-carit.de>

Commit 40329acc1a28145643e49207e9d65cd05bbda2c8 introduced a potential
issue during headset pairing. If a headset supporting both HSP/HFP and
A2DP is paired, and a late UUID (i.e. A2DP) is announced after HSP/HFP
is already connected, the code in uuid_added_cb() can result in
duplicated port creation and therefore an assertion failure:

D: [pulseaudio] bluetooth-util.c: dbus: interface=org.bluez.Headset, path=/org/bluez/12840/hci0/dev_00_13_1E_1F_F1_53, member=PropertyChanged
D: [pulseaudio] bluetooth-util.c: dbus: interface=org.bluez.MediaTransport, path=/org/bluez/12840/hci0/dev_00_13_1E_1F_F1_53/fd0, member=PropertyChanged
D: [pulseaudio] bluetooth-util.c: dbus: interface=org.bluez.Device, path=/org/bluez/12840/hci0/dev_00_13_1E_1F_F1_53, member=PropertyChanged
D: [pulseaudio] protocol-dbus.c: Interface org.PulseAudio.Core1.CardProfile added for object /org/pulseaudio/core1/card3/profile2
E: [pulseaudio] card.c: Assertion 'pa_hashmap_put(c->ports, p->name, p) >= 0' failed at pulsecore/card.c:107, function pa_card_add_ports(). Aborting.

The issue is very unlikely to reproduce but gains interest if further
ports needs to be merged in the future as well.
---
 src/modules/bluetooth/module-bluetooth-device.c | 42 +++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 33b2afa..9921892 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -2401,6 +2401,44 @@ static pa_bluetooth_device* find_device(struct userdata *u, const char *address,
 }
 
 /* Run from main thread */
+static void handle_duplicated_ports(struct userdata *u, pa_hashmap *new_ports) {
+    void *state;
+    pa_device_port *new_port;
+    pa_device_port *old_port;
+
+    pa_assert(u);
+    pa_assert(new_ports);
+
+    /* Late-announced UUIDs might create duplicated ports because the code in
+     * create_ports_for_profile() does not consider previously existing ports.
+     * The scenario is very unlikely but possible if a headset being paired
+     * connects HSP/HFP before the A2DP UUID is received. In this case the port
+     * "bluetooth-output" will already exist and therefore it has to be removed
+     * from the new_ports hashmap */
+    PA_HASHMAP_FOREACH(new_port, new_ports, state) {
+        if ((old_port = pa_hashmap_get(u->card->ports, new_port->name)) == NULL)
+            continue;
+
+        pa_assert(new_port->is_input == old_port->is_input);
+        pa_assert(new_port->is_output == old_port->is_output);
+
+        /* FIXME: we should not modify the port's priority without a proper hook
+         * to propagate this change. However, the scenario is very unlikely and
+         * other extensions to the core are recently being discussed which would
+         * also fix this minor issue */
+        old_port->priority = PA_MAX(old_port->priority, new_port->priority);
+
+        if (new_port->available == PA_PORT_AVAILABLE_YES)
+            pa_device_port_set_available(old_port, PA_PORT_AVAILABLE_YES);
+        else if (new_port->available == PA_PORT_AVAILABLE_UNKNOWN && old_port->available == PA_PORT_AVAILABLE_NO)
+            pa_device_port_set_available(old_port, PA_PORT_AVAILABLE_UNKNOWN);
+
+        pa_hashmap_remove(new_ports, new_port->name);
+        pa_device_port_unref(new_port);
+    }
+}
+
+/* Run from main thread */
 static pa_hook_result_t uuid_added_cb(pa_bluetooth_discovery *y, const struct pa_bluetooth_hook_uuid_data *data,
                                       struct userdata *u) {
     pa_card_profile *p;
@@ -2414,6 +2452,8 @@ static pa_hook_result_t uuid_added_cb(pa_bluetooth_discovery *y, const struct pa
     if (data->device != u->device)
         return PA_HOOK_OK;
 
+    pa_log_info("Device %s: new UUID '%s'", data->device->path, data->uuid);
+
     p = create_card_profile(u, data->uuid);
 
     if (!p)
@@ -2430,6 +2470,8 @@ static pa_hook_result_t uuid_added_cb(pa_bluetooth_discovery *y, const struct pa
 
     create_ports_for_profile(u, new_ports, p);
 
+    handle_duplicated_ports(u, new_ports);
+
     pa_card_add_ports(u->card, new_ports);
 
     pa_device_port_hashmap_free(new_ports);
-- 
1.8.1



More information about the pulseaudio-discuss mailing list