[pulseaudio-discuss] [RFC v0 5/5] bluetooth: Merge all ports into "bluetooth-input" and "bluetooth-output"

Mikel Astiz mikel.astiz.oss at gmail.com
Wed Feb 13 05:48:16 PST 2013


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

The card profile availability flag already provides all the necessary
information and therefore all Bluetooth ports can be merged. The
availability of this port now represents whether the device is
streaming audio, with the following mapping:
- PA_PORT_AVAILABLE_UNKNOWN: some profile connected but not streaming
- PA_PORT_AVAILABLE_NO: no profiles connected (module will unload soon)
- PA_PORT_AVAILABILE_YES: some profile streaming (regardless of which)

This information will generally be of little use, since the card profile
availability flag provides more accurate information.
---
 src/modules/bluetooth/module-bluetooth-device.c | 307 ++++++------------------
 1 file changed, 70 insertions(+), 237 deletions(-)

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 0eaa4e5..ea72a39 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1191,25 +1191,6 @@ finish:
     pa_log_debug("IO thread shutting down");
 }
 
-static pa_port_available_t transport_state_to_availability(pa_bluetooth_transport_state_t state) {
-    if (state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
-        return PA_PORT_AVAILABLE_NO;
-    else if (state >= PA_BLUETOOTH_TRANSPORT_STATE_PLAYING)
-        return PA_PORT_AVAILABLE_YES;
-    else
-        return PA_PORT_AVAILABLE_UNKNOWN;
-}
-
-static pa_port_available_t transport_state_to_availability_merged(pa_bluetooth_transport_state_t state1,
-                                                                  pa_bluetooth_transport_state_t state2) {
-    if (state1 == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED && state2 == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
-        return PA_PORT_AVAILABLE_NO;
-    else if (state1 >= PA_BLUETOOTH_TRANSPORT_STATE_PLAYING || state2 >= PA_BLUETOOTH_TRANSPORT_STATE_PLAYING)
-        return PA_PORT_AVAILABLE_YES;
-    else
-        return PA_PORT_AVAILABLE_UNKNOWN;
-}
-
 static pa_profile_available_t transport_state_to_profile_availability(pa_bluetooth_transport_state_t state) {
     if (state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
         return PA_PROFILE_AVAILABLE_NO;
@@ -1220,12 +1201,46 @@ static pa_profile_available_t transport_state_to_profile_availability(pa_bluetoo
 }
 
 /* Run from main thread */
+static pa_port_available_t get_port_availability(struct userdata *u) {
+    pa_port_available_t result = PA_PORT_AVAILABLE_NO;
+    unsigned i;
+
+    pa_assert(u);
+    pa_assert(u->device);
+
+    for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++) {
+        pa_bluetooth_transport *transport;
+
+        if (!(transport = u->device->transports[i]))
+            continue;
+
+        switch(transport->state) {
+            case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED:
+                continue;
+
+            case PA_BLUETOOTH_TRANSPORT_STATE_IDLE:
+                if (result == PA_PORT_AVAILABLE_NO)
+                    result = PA_PORT_AVAILABLE_UNKNOWN;
+
+                break;
+
+            case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING:
+                return PA_PORT_AVAILABLE_YES;
+        }
+    }
+
+    return result;
+}
+
+/* Run from main thread */
 static void handle_transport_state_change(struct userdata *u, struct pa_bluetooth_transport *transport) {
     bool acquire = false;
     bool release = false;
     enum profile profile;
     pa_card_profile *cp;
     pa_bluetooth_transport_state_t state;
+    pa_port_available_t available;
+    pa_device_port *port;
 
     pa_assert(u);
     pa_assert(transport);
@@ -1240,82 +1255,18 @@ static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot
     pa_card_profile_set_available(cp, transport_state_to_profile_availability(state));
 
     /* Update port availability */
-    switch (profile) {
-        case PROFILE_HFGW: {
-            pa_device_port *port;
-            pa_port_available_t available = transport_state_to_availability(state);
+    available = get_port_availability(u);
 
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-output"));
-            pa_device_port_set_available(port, available);
-
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-input"));
-            pa_device_port_set_available(port, available);
-
-            acquire = (available == PA_PORT_AVAILABLE_YES && u->profile == PROFILE_HFGW);
-            release = (available != PA_PORT_AVAILABLE_YES && u->profile == PROFILE_HFGW);
-
-            break;
-        }
-
-        case PROFILE_HSP: {
-            pa_device_port *port;
-            pa_port_available_t available;
-            pa_bluetooth_transport *other = u->device->transports[PROFILE_A2DP];
-
-            if (!other)
-                available = transport_state_to_availability(state);
-            else
-                available = transport_state_to_availability_merged(state, other->state);
-
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
-            pa_device_port_set_available(port, available);
-
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "hsp-input"));
-            pa_device_port_set_available(port, available);
-
-            acquire = (available == PA_PORT_AVAILABLE_YES && u->profile == PROFILE_HSP);
-            release = (available != PA_PORT_AVAILABLE_YES && u->profile == PROFILE_HSP);
-
-            break;
-        }
-
-        case PROFILE_A2DP_SOURCE: {
-            pa_device_port *port;
-            pa_port_available_t available = transport_state_to_availability(state);
-
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "a2dp-input"));
-            pa_device_port_set_available(port, available);
-
-            acquire = (available == PA_PORT_AVAILABLE_YES && u->profile == PROFILE_A2DP_SOURCE);
-            release = (available != PA_PORT_AVAILABLE_YES && u->profile == PROFILE_A2DP_SOURCE);
-
-            break;
-        }
-
-        case PROFILE_A2DP: {
-            pa_device_port *port;
-            pa_port_available_t available;
-            pa_bluetooth_transport *other = u->device->transports[PROFILE_HSP];
-
-            if (!other)
-                available = transport_state_to_availability(state);
-            else
-                available = transport_state_to_availability_merged(state, other->state);
-
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
-            pa_device_port_set_available(port, available);
-
-            acquire = (available == PA_PORT_AVAILABLE_YES && u->profile == PROFILE_A2DP);
-            release = (available != PA_PORT_AVAILABLE_YES && u->profile == PROFILE_A2DP);
-
-            break;
-        }
+    pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
+    pa_device_port_set_available(port, available);
 
-        case PROFILE_OFF:
-            pa_assert_not_reached();
-    }
+    pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-input"));
+    pa_device_port_set_available(port, available);
 
     /* Acquire or release transport as needed */
+    acquire = (state == PA_BLUETOOTH_TRANSPORT_STATE_PLAYING && u->profile == profile);
+    release = (state != PA_BLUETOOTH_TRANSPORT_STATE_PLAYING && u->profile == profile);
+
     if (acquire)
         if (bt_transport_acquire(u, true) >= 0) {
             if (u->source) {
@@ -1548,54 +1499,20 @@ static pa_hook_result_t transport_speaker_gain_changed_cb(pa_bluetooth_discovery
 }
 
 static void connect_ports(struct userdata *u, void *sink_or_source_new_data, pa_direction_t direction) {
-    union {
-        pa_sink_new_data *sink_new_data;
-        pa_source_new_data *source_new_data;
-    } data;
     pa_device_port *port;
 
-    if (direction == PA_DIRECTION_OUTPUT)
-        data.sink_new_data = sink_or_source_new_data;
-    else
-        data.source_new_data = sink_or_source_new_data;
-
-    switch (u->profile) {
-        case PROFILE_A2DP:
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
-            pa_assert_se(pa_hashmap_put(data.sink_new_data->ports, port->name, port) >= 0);
-            pa_device_port_ref(port);
-            break;
-
-        case PROFILE_A2DP_SOURCE:
-            pa_assert_se(port = pa_hashmap_get(u->card->ports, "a2dp-input"));
-            pa_assert_se(pa_hashmap_put(data.source_new_data->ports, port->name, port) >= 0);
-            pa_device_port_ref(port);
-            break;
-
-        case PROFILE_HSP:
-            if (direction == PA_DIRECTION_OUTPUT) {
-                pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
-                pa_assert_se(pa_hashmap_put(data.sink_new_data->ports, port->name, port) >= 0);
-            } else {
-                pa_assert_se(port = pa_hashmap_get(u->card->ports, "hsp-input"));
-                pa_assert_se(pa_hashmap_put(data.source_new_data->ports, port->name, port) >= 0);
-            }
-            pa_device_port_ref(port);
-            break;
+    if (direction == PA_DIRECTION_OUTPUT) {
+        pa_sink_new_data *sink_new_data = sink_or_source_new_data;
 
-        case PROFILE_HFGW:
-            if (direction == PA_DIRECTION_OUTPUT) {
-                pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-output"));
-                pa_assert_se(pa_hashmap_put(data.sink_new_data->ports, port->name, port) >= 0);
-            } else {
-                pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-input"));
-                pa_assert_se(pa_hashmap_put(data.source_new_data->ports, port->name, port) >= 0);
-            }
-            pa_device_port_ref(port);
-            break;
+        pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
+        pa_assert_se(pa_hashmap_put(sink_new_data->ports, port->name, port) >= 0);
+        pa_device_port_ref(port);
+    } else {
+        pa_source_new_data *source_new_data = sink_or_source_new_data;
 
-        default:
-            pa_assert_not_reached();
+        pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-input"));
+        pa_assert_se(pa_hashmap_put(source_new_data->ports, port->name, port) >= 0);
+        pa_device_port_ref(port);
     }
 }
 
@@ -2135,100 +2052,24 @@ off:
     return -PA_ERR_IO;
 }
 
-static void create_ports_for_profile(struct userdata *u, pa_hashmap *ports, pa_card_profile *profile) {
-    pa_bluetooth_device *device = u->device;
+/* Run from main thread */
+static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
     pa_device_port *port;
-    enum profile *d;
-    pa_bluetooth_transport *transport;
-    pa_bluetooth_transport_state_t transport_state;
-
-    d = PA_CARD_PROFILE_DATA(profile);
-
-    pa_assert(*d != PROFILE_OFF);
-
-    transport = device->transports[*d];
-    transport_state = transport ? transport->state : PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED;
-
-    switch (*d) {
-        case PROFILE_A2DP:
-            if ((port = pa_hashmap_get(ports, "bluetooth-output")) != NULL) {
-                pa_bluetooth_transport *other = device->transports[PROFILE_HSP];
-                pa_bluetooth_transport_state_t other_state = other ? other->state : PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED;
-
-                port->priority = PA_MAX(port->priority, profile->priority * 100);
-                port->available = transport_state_to_availability_merged(transport_state, other_state);
-                pa_hashmap_put(port->profiles, profile->name, profile);
-            } else {
-                pa_assert_se(port = pa_device_port_new(u->core, "bluetooth-output", _("Bluetooth Output"), 0));
-                pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-                port->is_output = 1;
-                port->is_input = 0;
-                port->priority = profile->priority * 100;
-                port->available = transport_state_to_availability(transport_state);
-                pa_hashmap_put(port->profiles, profile->name, profile);
-            }
-
-            break;
-
-        case PROFILE_A2DP_SOURCE:
-            pa_assert_se(port = pa_device_port_new(u->core, "a2dp-input", _("Bluetooth High Quality (A2DP)"), 0));
-            pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-            port->is_output = 0;
-            port->is_input = 1;
-            port->priority = profile->priority * 100;
-            port->available = transport_state_to_availability(transport_state);
-            pa_hashmap_put(port->profiles, profile->name, profile);
-            break;
-
-        case PROFILE_HSP:
-            if ((port = pa_hashmap_get(ports, "bluetooth-output")) != NULL) {
-                pa_bluetooth_transport *other = device->transports[PROFILE_A2DP];
-                pa_bluetooth_transport_state_t other_state = other ? other->state : PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED;
-
-                port->priority = PA_MAX(port->priority, profile->priority * 100);
-                port->available = transport_state_to_availability_merged(transport_state, other_state);
-                pa_hashmap_put(port->profiles, profile->name, profile);
-            } else {
-                pa_assert_se(port = pa_device_port_new(u->core, "bluetooth-output", _("Bluetooth Output"), 0));
-                pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-                port->is_output = 1;
-                port->is_input = 0;
-                port->priority = profile->priority * 100;
-                port->available = transport_state_to_availability(transport_state);
-                pa_hashmap_put(port->profiles, profile->name, profile);
-            }
-
-            pa_assert_se(port = pa_device_port_new(u->core, "hsp-input", _("Bluetooth Telephony (HSP/HFP)"), 0));
-            pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-            port->is_output = 0;
-            port->is_input = 1;
-            port->priority = profile->priority * 100;
-            port->available = transport_state_to_availability(transport_state);
-            pa_hashmap_put(port->profiles, profile->name, profile);
-            break;
-
-        case PROFILE_HFGW:
-            pa_assert_se(port = pa_device_port_new(u->core, "hfgw-output", _("Bluetooth Handsfree Gateway"), 0));
-            pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-            port->is_output = 1;
-            port->is_input = 0;
-            port->priority = profile->priority * 100;
-            port->available = transport_state_to_availability(transport_state);
-            pa_hashmap_put(port->profiles, profile->name, profile);
-
-            pa_assert_se(port = pa_device_port_new(u->core, "hfgw-input", _("Bluetooth Handsfree Gateway"), 0));
-            pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
-            port->is_output = 0;
-            port->is_input = 1;
-            port->priority = profile->priority * 100;
-            port->available = transport_state_to_availability(transport_state);
-            pa_hashmap_put(port->profiles, profile->name, profile);
-            break;
-
-        default:
-            pa_assert_not_reached();
-    }
 
+    pa_assert(u);
+    pa_assert(ports);
+
+    pa_assert_se(port = pa_device_port_new(u->core, "bluetooth-output", _("Bluetooth Output"), 0));
+    pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
+    port->is_output = 1;
+    port->is_input = 0;
+    port->available = get_port_availability(u);
+
+    pa_assert_se(port = pa_device_port_new(u->core, "bluetooth-input", _("Bluetooth Input"), 0));
+    pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
+    port->is_output = 0;
+    port->is_input = 1;
+    port->available = get_port_availability(u);
 }
 
 /* Run from main thread */
@@ -2333,11 +2174,12 @@ static int add_card(struct userdata *u) {
         }
 
         pa_hashmap_put(data.profiles, p->name, p);
-        create_ports_for_profile(u, data.ports, p);
     }
 
     pa_assert(!pa_hashmap_isempty(data.profiles));
 
+    create_card_ports(u, data.ports);
+
     p = pa_card_profile_new("off", _("Off"), sizeof(enum profile));
     d = PA_CARD_PROFILE_DATA(p);
     *d = PROFILE_OFF;
@@ -2419,7 +2261,6 @@ static pa_bluetooth_device* find_device(struct userdata *u, const char *address,
 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;
-    pa_hashmap *new_ports;
 
     pa_assert(data);
     pa_assert(data->device);
@@ -2441,14 +2282,6 @@ static pa_hook_result_t uuid_added_cb(pa_bluetooth_discovery *y, const struct pa
 
     pa_card_add_profile(u->card, p);
 
-    new_ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
-    create_ports_for_profile(u, new_ports, p);
-
-    pa_card_add_ports(u->card, new_ports);
-
-    pa_device_port_hashmap_free(new_ports);
-
     return PA_HOOK_OK;
 }
 
-- 
1.8.1



More information about the pulseaudio-discuss mailing list