[pulseaudio-commits] 8 commits - src/modules
Tanu Kaskinen
tanuk at kemper.freedesktop.org
Wed Aug 10 18:37:39 UTC 2016
src/modules/bluetooth/backend-native.c | 2
src/modules/bluetooth/bluez4-util.c | 123 ++++++++-------------
src/modules/bluetooth/bluez4-util.h | 34 +----
src/modules/bluetooth/bluez5-util.c | 125 ++++++++++++++++++++-
src/modules/bluetooth/bluez5-util.h | 4
src/modules/bluetooth/module-bluez4-device.c | 158 +++++++++++++++------------
src/modules/bluetooth/module-bluez5-device.c | 72 ++++++++----
src/modules/module-card-restore.c | 32 -----
8 files changed, 319 insertions(+), 231 deletions(-)
New commits:
commit 32c2a6d64aaa1d14b06c1af27a616e58d04e8e79
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Jul 31 02:44:55 2016 +0300
bluetooth: don't create the HSP/HFP profile twice
create_card_profile() used to get called separately for HSP and HFP,
so if a headset supports both profiles, a profile named
"headset_head_unit" would get created twice. The second instance would
get immediately freed, so that wasn't a particularly serious problem.
However, I think it makes more sense to create the profile only once.
This patch makes things so that before a profile is created, we check
what name that profile would have, and if a profile with that name
already exists, we don't create the profile.
A couple of Yocto releases (jethro and krogoth) have non-upstream
patches that suffer from this double creation. The patches add
associations between profiles and ports, and those associations use
the profile name as the key. When the second profile gets freed, the
associations between the profile and its ports get removed, and since
the profile name is used as the key, this erroneously affects the
first profile too. Crashing ensues.
BugLink: https://bugzilla.yoctoproject.org/show_bug.cgi?id=10018
diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
index 0c561d1..0de8ecb 100644
--- a/src/modules/bluetooth/module-bluez4-device.c
+++ b/src/modules/bluetooth/module-bluez4-device.c
@@ -2162,18 +2162,23 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
}
/* Run from main thread */
-static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid, pa_hashmap *ports) {
+static pa_card_profile *create_card_profile(struct userdata *u, pa_bluez4_profile_t profile, pa_hashmap *ports) {
pa_device_port *input_port, *output_port;
+ const char *name;
pa_card_profile *p = NULL;
- pa_bluez4_profile_t *d;
+ pa_bluez4_profile_t *d = NULL;
+ pa_bluez4_transport *t;
pa_assert(u->input_port_name);
pa_assert(u->output_port_name);
pa_assert_se(input_port = pa_hashmap_get(ports, u->input_port_name));
pa_assert_se(output_port = pa_hashmap_get(ports, u->output_port_name));
- if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SINK)) {
- p = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP)"), sizeof(pa_bluez4_profile_t));
+ name = pa_bluez4_profile_to_string(profile);
+
+ switch (profile) {
+ case PA_BLUEZ4_PROFILE_A2DP_SINK:
+ p = pa_card_profile_new(name, _("High Fidelity Playback (A2DP)"), sizeof(pa_bluez4_profile_t));
p->priority = 10;
p->n_sinks = 1;
p->n_sources = 0;
@@ -2182,9 +2187,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_A2DP_SINK;
- } else if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SOURCE)) {
- p = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP)"), sizeof(pa_bluez4_profile_t));
+ break;
+
+ case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
+ p = pa_card_profile_new(name, _("High Fidelity Capture (A2DP)"), sizeof(pa_bluez4_profile_t));
p->priority = 10;
p->n_sinks = 0;
p->n_sources = 1;
@@ -2193,9 +2199,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(input_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
- } else if (pa_streq(uuid, PA_BLUEZ4_UUID_HSP_HS) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_HF)) {
- p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(pa_bluez4_profile_t));
+ break;
+
+ case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
+ p = pa_card_profile_new(name, _("Telephony Duplex (HSP/HFP)"), sizeof(pa_bluez4_profile_t));
p->priority = 20;
p->n_sinks = 1;
p->n_sources = 1;
@@ -2205,9 +2212,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
- } else if (pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG)) {
- p = pa_card_profile_new("hfgw", _("Handsfree Gateway"), sizeof(pa_bluez4_profile_t));
+ break;
+
+ case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
+ p = pa_card_profile_new(name, _("Handsfree Gateway"), sizeof(pa_bluez4_profile_t));
p->priority = 20;
p->n_sinks = 1;
p->n_sources = 1;
@@ -2217,19 +2225,35 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
+ break;
+
+ case PA_BLUEZ4_PROFILE_OFF:
+ pa_assert_not_reached();
}
- if (p) {
- pa_bluez4_transport *t;
+ *d = profile;
- if ((t = u->device->transports[*d]))
- p->available = transport_state_to_availability(t->state);
- }
+ if ((t = u->device->transports[*d]))
+ p->available = transport_state_to_availability(t->state);
return p;
}
+static int uuid_to_profile(const char *uuid, pa_bluez4_profile_t *_r) {
+ if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SINK))
+ *_r = PA_BLUEZ4_PROFILE_A2DP_SINK;
+ else if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SOURCE))
+ *_r = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
+ else if (pa_streq(uuid, PA_BLUEZ4_UUID_HSP_HS) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_HF))
+ *_r = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
+ else if (pa_streq(uuid, PA_BLUEZ4_UUID_HSP_AG) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG))
+ *_r = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
+ else
+ return -PA_ERR_INVALID;
+
+ return 0;
+}
+
/* Run from main thread */
static int add_card(struct userdata *u) {
pa_card_new_data data;
@@ -2278,16 +2302,15 @@ static int add_card(struct userdata *u) {
create_card_ports(u, data.ports);
PA_HASHMAP_FOREACH(uuid, device->uuids, state) {
- p = create_card_profile(u, uuid, data.ports);
+ pa_bluez4_profile_t profile;
- if (!p)
+ if (uuid_to_profile(uuid, &profile) < 0)
continue;
- if (pa_hashmap_get(data.profiles, p->name)) {
- pa_card_profile_free(p);
+ if (pa_hashmap_get(data.profiles, pa_bluez4_profile_to_string(profile)))
continue;
- }
+ p = create_card_profile(u, profile, data.ports);
pa_hashmap_put(data.profiles, p->name, p);
}
@@ -2387,6 +2410,7 @@ static pa_bluez4_device* find_device(struct userdata *u, const char *address, co
/* Run from main thread */
static pa_hook_result_t uuid_added_cb(pa_bluez4_discovery *y, const struct pa_bluez4_hook_uuid_data *data,
struct userdata *u) {
+ pa_bluez4_profile_t profile;
pa_card_profile *p;
pa_assert(data);
@@ -2397,16 +2421,13 @@ static pa_hook_result_t uuid_added_cb(pa_bluez4_discovery *y, const struct pa_bl
if (data->device != u->device)
return PA_HOOK_OK;
- p = create_card_profile(u, data->uuid, u->card->ports);
-
- if (!p)
+ if (uuid_to_profile(data->uuid, &profile) < 0)
return PA_HOOK_OK;
- if (pa_hashmap_get(u->card->profiles, p->name)) {
- pa_card_profile_free(p);
+ if (pa_hashmap_get(u->card->profiles, pa_bluez4_profile_to_string(profile)))
return PA_HOOK_OK;
- }
+ p = create_card_profile(u, profile, u->card->ports);
pa_card_add_profile(u->card, p);
return PA_HOOK_OK;
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 498d0e1..e610095 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -1772,8 +1772,9 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
}
/* Run from main thread */
-static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid, pa_hashmap *ports) {
+static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_profile_t profile, pa_hashmap *ports) {
pa_device_port *input_port, *output_port;
+ const char *name;
pa_card_profile *cp = NULL;
pa_bluetooth_profile_t *p;
@@ -1782,8 +1783,11 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_assert_se(input_port = pa_hashmap_get(ports, u->input_port_name));
pa_assert_se(output_port = pa_hashmap_get(ports, u->output_port_name));
- if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK)) {
- cp = pa_card_profile_new("a2dp_sink", _("High Fidelity Playback (A2DP Sink)"), sizeof(pa_bluetooth_profile_t));
+ name = pa_bluetooth_profile_to_string(profile);
+
+ switch (profile) {
+ case PA_BLUETOOTH_PROFILE_A2DP_SINK:
+ cp = pa_card_profile_new(name, _("High Fidelity Playback (A2DP Sink)"), sizeof(pa_bluetooth_profile_t));
cp->priority = 10;
cp->n_sinks = 1;
cp->n_sources = 0;
@@ -1792,9 +1796,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, cp->name, cp);
p = PA_CARD_PROFILE_DATA(cp);
- *p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
- } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE)) {
- cp = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t));
+ break;
+
+ case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
+ cp = pa_card_profile_new(name, _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t));
cp->priority = 10;
cp->n_sinks = 0;
cp->n_sources = 1;
@@ -1803,9 +1808,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(input_port->profiles, cp->name, cp);
p = PA_CARD_PROFILE_DATA(cp);
- *p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
- } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) {
- cp = pa_card_profile_new("headset_head_unit", _("Headset Head Unit (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
+ break;
+
+ case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
+ cp = pa_card_profile_new(name, _("Headset Head Unit (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
cp->priority = 20;
cp->n_sinks = 1;
cp->n_sources = 1;
@@ -1815,9 +1821,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, cp->name, cp);
p = PA_CARD_PROFILE_DATA(cp);
- *p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
- } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG)) {
- cp = pa_card_profile_new("headset_audio_gateway", _("Headset Audio Gateway (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
+ break;
+
+ case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
+ cp = pa_card_profile_new(name, _("Headset Audio Gateway (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
cp->priority = 20;
cp->n_sinks = 1;
cp->n_sources = 1;
@@ -1827,16 +1834,19 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, cp->name, cp);
p = PA_CARD_PROFILE_DATA(cp);
- *p = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
- }
+ break;
- if (cp) {
- if (u->device->transports[*p])
- cp->available = transport_state_to_availability(u->device->transports[*p]->state);
- else
- cp->available = PA_AVAILABLE_NO;
+ case PA_BLUETOOTH_PROFILE_OFF:
+ pa_assert_not_reached();
}
+ *p = profile;
+
+ if (u->device->transports[*p])
+ cp->available = transport_state_to_availability(u->device->transports[*p]->state);
+ else
+ cp->available = PA_AVAILABLE_NO;
+
return cp;
}
@@ -1882,6 +1892,21 @@ off:
return -PA_ERR_IO;
}
+static int uuid_to_profile(const char *uuid, pa_bluetooth_profile_t *_r) {
+ if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK))
+ *_r = PA_BLUETOOTH_PROFILE_A2DP_SINK;
+ else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
+ *_r = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
+ else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF))
+ *_r = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
+ else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG))
+ *_r = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
+ else
+ return -PA_ERR_INVALID;
+
+ return 0;
+}
+
/* Run from main thread */
static int add_card(struct userdata *u) {
const pa_bluetooth_device *d;
@@ -1923,16 +1948,15 @@ static int add_card(struct userdata *u) {
create_card_ports(u, data.ports);
PA_HASHMAP_FOREACH(uuid, d->uuids, state) {
- cp = create_card_profile(u, uuid, data.ports);
+ pa_bluetooth_profile_t profile;
- if (!cp)
+ if (uuid_to_profile(uuid, &profile) < 0)
continue;
- if (pa_hashmap_get(data.profiles, cp->name)) {
- pa_card_profile_free(cp);
+ if (pa_hashmap_get(data.profiles, pa_bluetooth_profile_to_string(profile)))
continue;
- }
+ cp = create_card_profile(u, profile, data.ports);
pa_hashmap_put(data.profiles, cp->name, cp);
}
commit 83ac6c5ae52d8463f479b84a0829597f3b470caf
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:54 2016 +0300
bluetooth: refactor BlueZ 4 transport state setting
Add transport_set_state() that encapsulates changing the variable,
logging and firing the change hook.
I also made a cosmetic change to the corresponding BlueZ 5 log
message so that both messages have the format that I like.
diff --git a/src/modules/bluetooth/bluez4-util.c b/src/modules/bluetooth/bluez4-util.c
index baf3aea..90b1563 100644
--- a/src/modules/bluetooth/bluez4-util.c
+++ b/src/modules/bluetooth/bluez4-util.c
@@ -77,6 +77,7 @@ static pa_dbus_pending* send_and_add_to_pending(pa_bluez4_discovery *y, DBusMess
void *call_data);
static void found_adapter(pa_bluez4_discovery *y, const char *path);
static pa_bluez4_device *found_device(pa_bluez4_discovery *y, const char* path);
+static void transport_set_state(pa_bluez4_transport *transport, pa_bluez4_transport_state_t state);
static pa_bluez4_audio_state_t audio_state_from_string(const char* value) {
pa_assert(value);
@@ -198,8 +199,7 @@ static void device_free(pa_bluez4_device *d) {
d->transports[i] = NULL;
pa_hashmap_remove(d->discovery->transports, t->path);
- t->state = PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED;
- pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED], t);
+ transport_set_state(t, PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED);
transport_free(t);
}
@@ -515,7 +515,6 @@ static int parse_audio_property(pa_bluez4_device *d, const char *interface, DBus
if (pa_streq(key, "State")) {
pa_bluez4_audio_state_t state = audio_state_from_string(value);
- pa_bluez4_transport_state_t old_state;
pa_log_debug("Device %s interface %s property 'State' changed to value '%s'", d->path, interface, value);
@@ -534,16 +533,7 @@ static int parse_audio_property(pa_bluez4_device *d, const char *interface, DBus
if (!transport)
break;
- old_state = transport->state;
- transport->state = audio_state_to_transport_state(state);
-
- if (transport->state != old_state) {
- pa_log_debug("Transport %s (profile %s) changed state from %s to %s.", transport->path,
- pa_bluez4_profile_to_string(transport->profile), transport_state_to_string(old_state),
- transport_state_to_string(transport->state));
-
- pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED], transport);
- }
+ transport_set_state(transport, audio_state_to_transport_state(state));
}
break;
@@ -1248,6 +1238,18 @@ static pa_bluez4_transport *transport_new(pa_bluez4_device *d, const char *owner
return t;
}
+static void transport_set_state(pa_bluez4_transport *transport, pa_bluez4_transport_state_t state) {
+ if (transport->state == state)
+ return;
+
+ pa_log_debug("Transport %s state: %s -> %s",
+ transport->path, transport_state_to_string(transport->state), transport_state_to_string(state));
+
+ transport->state = state;
+
+ pa_hook_fire(&transport->device->discovery->hooks[PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED], transport);
+}
+
static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) {
pa_bluez4_discovery *y = userdata;
pa_bluez4_device *d;
@@ -1392,8 +1394,7 @@ static DBusMessage *endpoint_clear_configuration(DBusConnection *c, DBusMessage
pa_log_debug("Clearing transport %s profile %d", t->path, t->profile);
t->device->transports[t->profile] = NULL;
pa_hashmap_remove(y->transports, t->path);
- t->state = PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED;
- pa_hook_fire(&y->hooks[PA_BLUEZ4_HOOK_TRANSPORT_STATE_CHANGED], t);
+ transport_set_state(t, PA_BLUEZ4_TRANSPORT_STATE_DISCONNECTED);
if (old_any_connected != pa_bluez4_device_any_audio_connected(t->device))
run_callback(t->device, false);
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
index 93eebde..7d63f35 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -267,7 +267,7 @@ void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_tr
old_any_connected = pa_bluetooth_device_any_transport_connected(t->device);
- pa_log_debug("Transport %s state changed from %s to %s",
+ pa_log_debug("Transport %s state: %s -> %s",
t->path, transport_state_to_string(t->state), transport_state_to_string(state));
t->state = state;
commit 15e3d828dd4e811f558ec98f4d6fb4df7df84e30
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:53 2016 +0300
bluetooth: unify BlueZ 4 and BlueZ 5 profile constant names
This should make it slightly easier to copy code between BlueZ 4 and
BlueZ 5.
diff --git a/src/modules/bluetooth/bluez4-util.c b/src/modules/bluetooth/bluez4-util.c
index a30e438..baf3aea 100644
--- a/src/modules/bluetooth/bluez4-util.c
+++ b/src/modules/bluetooth/bluez4-util.c
@@ -95,13 +95,13 @@ static pa_bluez4_audio_state_t audio_state_from_string(const char* value) {
const char *pa_bluez4_profile_to_string(pa_bluez4_profile_t profile) {
switch(profile) {
- case PA_BLUEZ4_PROFILE_A2DP:
+ case PA_BLUEZ4_PROFILE_A2DP_SINK:
return "a2dp";
case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
return "a2dp_source";
- case PA_BLUEZ4_PROFILE_HSP:
+ case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
return "hsp";
- case PA_BLUEZ4_PROFILE_HFGW:
+ case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
return "hfgw";
case PA_BLUEZ4_PROFILE_OFF:
pa_assert_not_reached();
@@ -115,16 +115,16 @@ static int profile_from_interface(const char *interface, pa_bluez4_profile_t *p)
pa_assert(p);
if (pa_streq(interface, "org.bluez.AudioSink")) {
- *p = PA_BLUEZ4_PROFILE_A2DP;
+ *p = PA_BLUEZ4_PROFILE_A2DP_SINK;
return 0;
} else if (pa_streq(interface, "org.bluez.AudioSource")) {
*p = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
return 0;
} else if (pa_streq(interface, "org.bluez.Headset")) {
- *p = PA_BLUEZ4_PROFILE_HSP;
+ *p = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
return 0;
} else if (pa_streq(interface, "org.bluez.HandsfreeGateway")) {
- *p = PA_BLUEZ4_PROFILE_HFGW;
+ *p = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
return 0;
}
@@ -1197,7 +1197,7 @@ void pa_bluez4_transport_set_microphone_gain(pa_bluez4_transport *t, uint16_t va
dbus_uint16_t gain = PA_MIN(value, HSP_MAX_GAIN);
pa_assert(t);
- pa_assert(t->profile == PA_BLUEZ4_PROFILE_HSP);
+ pa_assert(t->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
set_property(t->device->discovery, "org.bluez", t->device->path, "org.bluez.Headset",
"MicrophoneGain", DBUS_TYPE_UINT16, &gain);
@@ -1207,7 +1207,7 @@ void pa_bluez4_transport_set_speaker_gain(pa_bluez4_transport *t, uint16_t value
dbus_uint16_t gain = PA_MIN(value, HSP_MAX_GAIN);
pa_assert(t);
- pa_assert(t->profile == PA_BLUEZ4_PROFILE_HSP);
+ pa_assert(t->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
set_property(t->device->discovery, "org.bluez", t->device->path, "org.bluez.Headset",
"SpeakerGain", DBUS_TYPE_UINT16, &gain);
@@ -1327,11 +1327,11 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
goto fail;
if (dbus_message_has_path(m, ENDPOINT_PATH_HFP_AG))
- p = PA_BLUEZ4_PROFILE_HSP;
+ p = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
else if (dbus_message_has_path(m, ENDPOINT_PATH_HFP_HS))
- p = PA_BLUEZ4_PROFILE_HFGW;
+ p = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
else if (dbus_message_has_path(m, ENDPOINT_PATH_A2DP_SOURCE))
- p = PA_BLUEZ4_PROFILE_A2DP;
+ p = PA_BLUEZ4_PROFILE_A2DP_SINK;
else
p = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
diff --git a/src/modules/bluetooth/bluez4-util.h b/src/modules/bluetooth/bluez4-util.h
index abbbfab..ed588f1 100644
--- a/src/modules/bluetooth/bluez4-util.h
+++ b/src/modules/bluetooth/bluez4-util.h
@@ -43,10 +43,10 @@ typedef struct pa_bluez4_transport pa_bluez4_transport;
struct userdata;
typedef enum pa_bluez4_profile {
- PA_BLUEZ4_PROFILE_A2DP,
+ PA_BLUEZ4_PROFILE_A2DP_SINK,
PA_BLUEZ4_PROFILE_A2DP_SOURCE,
- PA_BLUEZ4_PROFILE_HSP,
- PA_BLUEZ4_PROFILE_HFGW,
+ PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT,
+ PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY,
PA_BLUEZ4_PROFILE_OFF
} pa_bluez4_profile_t;
diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
index bae4e45..0c561d1 100644
--- a/src/modules/bluetooth/module-bluez4-device.c
+++ b/src/modules/bluetooth/module-bluez4-device.c
@@ -198,7 +198,7 @@ enum {
#define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
-#define USE_SCO_OVER_PCM(u) (u->profile == PA_BLUEZ4_PROFILE_HSP && (u->hsp.sco_sink && u->hsp.sco_source))
+#define USE_SCO_OVER_PCM(u) (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT && (u->hsp.sco_sink && u->hsp.sco_source))
static int init_profile(struct userdata *u);
@@ -241,7 +241,7 @@ static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool) {
/* from IO thread, except in SCO over PCM */
static void bt_transport_config_mtu(struct userdata *u) {
/* Calculate block sizes */
- if (u->profile == PA_BLUEZ4_PROFILE_HSP || u->profile == PA_BLUEZ4_PROFILE_HFGW) {
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY) {
u->read_block_size = u->read_link_mtu;
u->write_block_size = u->write_link_mtu;
} else {
@@ -260,7 +260,7 @@ static void bt_transport_config_mtu(struct userdata *u) {
if (u->sink) {
pa_sink_set_max_request_within_thread(u->sink, u->write_block_size);
pa_sink_set_fixed_latency_within_thread(u->sink,
- (u->profile == PA_BLUEZ4_PROFILE_A2DP ?
+ (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK ?
FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_HSP) +
pa_bytes_to_usec(u->write_block_size, &u->sample_spec));
}
@@ -291,7 +291,7 @@ static void setup_stream(struct userdata *u) {
pa_log_debug("Stream properly set up, we're ready to roll!");
- if (u->profile == PA_BLUEZ4_PROFILE_A2DP)
+ if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK)
a2dp_set_bitpool(u, u->a2dp.max_bitpool);
u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
@@ -550,7 +550,7 @@ static int hsp_process_render(struct userdata *u) {
int ret = 0;
pa_assert(u);
- pa_assert(u->profile == PA_BLUEZ4_PROFILE_HSP || u->profile == PA_BLUEZ4_PROFILE_HFGW);
+ pa_assert(u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY);
pa_assert(u->sink);
/* First, render some data */
@@ -615,7 +615,7 @@ static int hsp_process_push(struct userdata *u) {
pa_memchunk memchunk;
pa_assert(u);
- pa_assert(u->profile == PA_BLUEZ4_PROFILE_HSP || u->profile == PA_BLUEZ4_PROFILE_HFGW);
+ pa_assert(u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY);
pa_assert(u->source);
pa_assert(u->read_smoother);
@@ -733,7 +733,7 @@ static int a2dp_process_render(struct userdata *u) {
int ret = 0;
pa_assert(u);
- pa_assert(u->profile == PA_BLUEZ4_PROFILE_A2DP);
+ pa_assert(u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK);
pa_assert(u->sink);
/* First, render some data */
@@ -1028,7 +1028,7 @@ static void thread_func(void *userdata) {
if (pollfd && (pollfd->revents & POLLIN)) {
int n_read;
- if (u->profile == PA_BLUEZ4_PROFILE_HSP || u->profile == PA_BLUEZ4_PROFILE_HFGW)
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
n_read = hsp_process_push(u);
else
n_read = a2dp_process_push(u);
@@ -1086,7 +1086,7 @@ static void thread_func(void *userdata) {
pa_memblock_unref(tmp.memblock);
u->write_index += skip_bytes;
- if (u->profile == PA_BLUEZ4_PROFILE_A2DP)
+ if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK)
a2dp_reduce_bitpool(u);
}
}
@@ -1102,7 +1102,7 @@ static void thread_func(void *userdata) {
if (u->write_index <= 0)
u->started_at = pa_rtclock_now();
- if (u->profile == PA_BLUEZ4_PROFILE_A2DP) {
+ if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK) {
if ((n_written = a2dp_process_render(u)) < 0)
goto io_fail;
} else {
@@ -1202,10 +1202,10 @@ static pa_available_t transport_state_to_availability(pa_bluez4_transport_state_
static pa_direction_t get_profile_direction(pa_bluez4_profile_t p) {
static const pa_direction_t profile_direction[] = {
- [PA_BLUEZ4_PROFILE_A2DP] = PA_DIRECTION_OUTPUT,
+ [PA_BLUEZ4_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
[PA_BLUEZ4_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
- [PA_BLUEZ4_PROFILE_HSP] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
- [PA_BLUEZ4_PROFILE_HFGW] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
+ [PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
+ [PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
[PA_BLUEZ4_PROFILE_OFF] = 0
};
@@ -1327,7 +1327,7 @@ static void sink_set_volume_cb(pa_sink *s) {
pa_assert(u);
pa_assert(u->sink == s);
- pa_assert(u->profile == PA_BLUEZ4_PROFILE_HSP);
+ pa_assert(u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
pa_assert(u->transport);
gain = (dbus_uint16_t) round((double) pa_cvolume_max(&s->real_volume) * HSP_MAX_GAIN / PA_VOLUME_NORM);
@@ -1354,7 +1354,7 @@ static void source_set_volume_cb(pa_source *s) {
pa_assert(u);
pa_assert(u->source == s);
- pa_assert(u->profile == PA_BLUEZ4_PROFILE_HSP);
+ pa_assert(u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT);
pa_assert(u->transport);
gain = (dbus_uint16_t) round((double) pa_cvolume_max(&s->real_volume) * HSP_MAX_GAIN / PA_VOLUME_NORM);
@@ -1562,7 +1562,7 @@ static int add_sink(struct userdata *u) {
data.module = u->module;
pa_sink_new_data_set_sample_spec(&data, &u->sample_spec);
pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluez4_profile_to_string(u->profile));
- if (u->profile == PA_BLUEZ4_PROFILE_HSP)
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT)
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
data.card = u->card;
data.name = get_name("sink", u->modargs, u->address, pa_bluez4_profile_to_string(u->profile), &b);
@@ -1577,11 +1577,11 @@ static int add_sink(struct userdata *u) {
if (!u->transport_acquired)
switch (u->profile) {
- case PA_BLUEZ4_PROFILE_A2DP:
- case PA_BLUEZ4_PROFILE_HSP:
+ case PA_BLUEZ4_PROFILE_A2DP_SINK:
+ case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
pa_assert_not_reached(); /* Profile switch should have failed */
break;
- case PA_BLUEZ4_PROFILE_HFGW:
+ case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
data.suspend_cause = PA_SUSPEND_USER;
break;
case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
@@ -1602,7 +1602,7 @@ static int add_sink(struct userdata *u) {
u->sink->set_port = sink_set_port_cb;
}
- if (u->profile == PA_BLUEZ4_PROFILE_HSP) {
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
u->sink->n_volume_steps = 16;
@@ -1632,7 +1632,7 @@ static int add_source(struct userdata *u) {
data.module = u->module;
pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluez4_profile_to_string(u->profile));
- if (u->profile == PA_BLUEZ4_PROFILE_HSP)
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT)
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
data.card = u->card;
@@ -1649,14 +1649,14 @@ static int add_source(struct userdata *u) {
if (!u->transport_acquired)
switch (u->profile) {
- case PA_BLUEZ4_PROFILE_HSP:
+ case PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT:
pa_assert_not_reached(); /* Profile switch should have failed */
break;
case PA_BLUEZ4_PROFILE_A2DP_SOURCE:
- case PA_BLUEZ4_PROFILE_HFGW:
+ case PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY:
data.suspend_cause = PA_SUSPEND_USER;
break;
- case PA_BLUEZ4_PROFILE_A2DP:
+ case PA_BLUEZ4_PROFILE_A2DP_SINK:
case PA_BLUEZ4_PROFILE_OFF:
pa_assert_not_reached();
}
@@ -1674,12 +1674,12 @@ static int add_source(struct userdata *u) {
u->source->set_port = source_set_port_cb;
}
- if ((u->profile == PA_BLUEZ4_PROFILE_HSP) || (u->profile == PA_BLUEZ4_PROFILE_HFGW)) {
+ if ((u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) || (u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)) {
pa_bluez4_transport *t = u->transport;
pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
}
- if (u->profile == PA_BLUEZ4_PROFILE_HSP) {
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
u->source->n_volume_steps = 16;
@@ -1794,7 +1794,7 @@ static void bt_transport_config_a2dp(struct userdata *u) {
a2dp->max_bitpool = config->max_bitpool;
/* Set minimum bitpool for source to get the maximum possible block_size */
- a2dp->sbc.bitpool = u->profile == PA_BLUEZ4_PROFILE_A2DP ? a2dp->max_bitpool : a2dp->min_bitpool;
+ a2dp->sbc.bitpool = u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK ? a2dp->max_bitpool : a2dp->min_bitpool;
a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
@@ -1803,7 +1803,7 @@ static void bt_transport_config_a2dp(struct userdata *u) {
}
static void bt_transport_config(struct userdata *u) {
- if (u->profile == PA_BLUEZ4_PROFILE_HSP || u->profile == PA_BLUEZ4_PROFILE_HFGW) {
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY) {
u->sample_spec.format = PA_SAMPLE_S16LE;
u->sample_spec.channels = 1;
u->sample_spec.rate = 8000;
@@ -1842,7 +1842,7 @@ static int setup_transport(struct userdata *u) {
u->transport = t;
- if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE || u->profile == PA_BLUEZ4_PROFILE_HFGW)
+ if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE || u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
bt_transport_acquire(u, true); /* In case of error, the sink/sources will be created suspended */
else if (bt_transport_acquire(u, false) < 0)
return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
@@ -1863,15 +1863,15 @@ static int init_profile(struct userdata *u) {
pa_assert(u->transport);
- if (u->profile == PA_BLUEZ4_PROFILE_A2DP ||
- u->profile == PA_BLUEZ4_PROFILE_HSP ||
- u->profile == PA_BLUEZ4_PROFILE_HFGW)
+ if (u->profile == PA_BLUEZ4_PROFILE_A2DP_SINK ||
+ u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT ||
+ u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
if (add_sink(u) < 0)
r = -1;
- if (u->profile == PA_BLUEZ4_PROFILE_HSP ||
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT ||
u->profile == PA_BLUEZ4_PROFILE_A2DP_SOURCE ||
- u->profile == PA_BLUEZ4_PROFILE_HFGW)
+ u->profile == PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY)
if (add_source(u) < 0)
r = -1;
@@ -1914,7 +1914,7 @@ static void stop_thread(struct userdata *u) {
}
if (u->sink) {
- if (u->profile == PA_BLUEZ4_PROFILE_HSP) {
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
pa_shared_remove(u->core, k);
pa_xfree(k);
@@ -1925,7 +1925,7 @@ static void stop_thread(struct userdata *u) {
}
if (u->source) {
- if (u->profile == PA_BLUEZ4_PROFILE_HSP) {
+ if (u->profile == PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT) {
k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
pa_shared_remove(u->core, k);
pa_xfree(k);
@@ -2182,7 +2182,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_A2DP;
+ *d = PA_BLUEZ4_PROFILE_A2DP_SINK;
} else if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SOURCE)) {
p = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP)"), sizeof(pa_bluez4_profile_t));
p->priority = 10;
@@ -2205,7 +2205,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_HSP;
+ *d = PA_BLUEZ4_PROFILE_HEADSET_HEAD_UNIT;
} else if (pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG)) {
p = pa_card_profile_new("hfgw", _("Handsfree Gateway"), sizeof(pa_bluez4_profile_t));
p->priority = 20;
@@ -2217,7 +2217,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_hashmap_put(output_port->profiles, p->name, p);
d = PA_CARD_PROFILE_DATA(p);
- *d = PA_BLUEZ4_PROFILE_HFGW;
+ *d = PA_BLUEZ4_PROFILE_HEADSET_AUDIO_GATEWAY;
}
if (p) {
commit 52a9ee618f7f250fd3c5be3f9a000f1aa5f77db6
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:52 2016 +0300
bluetooth: unify BlueZ 4 and BlueZ 5 UUID handling
A hashmap is more convenient than a linked list for storing the UUIDs,
so change the BlueZ 4 code accordingly.
Rename the BlueZ 4 UUID constants to match the BlueZ 5 naming.
The only changes to the BlueZ 5 code are the addition of one comment
and making another comment a bit clearer.
diff --git a/src/modules/bluetooth/bluez4-util.c b/src/modules/bluetooth/bluez4-util.c
index 97b5ab0..a30e438 100644
--- a/src/modules/bluetooth/bluez4-util.c
+++ b/src/modules/bluetooth/bluez4-util.c
@@ -146,23 +146,6 @@ static pa_bluez4_transport_state_t audio_state_to_transport_state(pa_bluez4_audi
pa_assert_not_reached();
}
-static pa_bluez4_uuid *uuid_new(const char *uuid) {
- pa_bluez4_uuid *u;
-
- u = pa_xnew(pa_bluez4_uuid, 1);
- u->uuid = pa_xstrdup(uuid);
- PA_LLIST_INIT(pa_bluez4_uuid, u);
-
- return u;
-}
-
-static void uuid_free(pa_bluez4_uuid *u) {
- pa_assert(u);
-
- pa_xfree(u->uuid);
- pa_xfree(u);
-}
-
static pa_bluez4_device* device_new(pa_bluez4_discovery *discovery, const char *path) {
pa_bluez4_device *d;
unsigned i;
@@ -181,7 +164,7 @@ static pa_bluez4_device* device_new(pa_bluez4_discovery *discovery, const char *
d->path = pa_xstrdup(path);
d->paired = -1;
d->alias = NULL;
- PA_LLIST_HEAD_INIT(pa_bluez4_uuid, d->uuids);
+ d->uuids = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
d->address = NULL;
d->class = -1;
d->trusted = -1;
@@ -204,7 +187,6 @@ static void transport_free(pa_bluez4_transport *t) {
}
static void device_free(pa_bluez4_device *d) {
- pa_bluez4_uuid *u;
pa_bluez4_transport *t;
unsigned i;
@@ -221,10 +203,8 @@ static void device_free(pa_bluez4_device *d) {
transport_free(t);
}
- while ((u = d->uuids)) {
- PA_LLIST_REMOVE(pa_bluez4_uuid, d->uuids, u);
- uuid_free(u);
- }
+ if (d->uuids)
+ pa_hashmap_free(d->uuids);
pa_xfree(d->name);
pa_xfree(d->path);
@@ -416,7 +396,6 @@ static int parse_device_property(pa_bluez4_device *d, DBusMessageIter *i, bool i
}
case DBUS_TYPE_ARRAY: {
-
DBusMessageIter ai;
dbus_message_iter_recurse(&variant_i, &ai);
@@ -424,42 +403,46 @@ static int parse_device_property(pa_bluez4_device *d, DBusMessageIter *i, bool i
DBusMessage *m;
bool has_audio = false;
+ /* bluetoothd never removes UUIDs from a device object so we
+ * don't need to check for disappeared UUIDs here. */
while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
- pa_bluez4_uuid *node;
const char *value;
+ char *uuid;
struct pa_bluez4_hook_uuid_data uuiddata;
dbus_message_iter_get_basic(&ai, &value);
- if (pa_bluez4_uuid_has(d->uuids, value)) {
+ if (pa_hashmap_get(d->uuids, value)) {
dbus_message_iter_next(&ai);
continue;
}
- node = uuid_new(value);
- PA_LLIST_PREPEND(pa_bluez4_uuid, d->uuids, node);
+ uuid = pa_xstrdup(value);
+ pa_hashmap_put(d->uuids, uuid, uuid);
+
+ pa_log_debug("%s: %s", key, value);
uuiddata.device = d;
uuiddata.uuid = value;
pa_hook_fire(&d->discovery->hooks[PA_BLUEZ4_HOOK_DEVICE_UUID_ADDED], &uuiddata);
/* Vudentz said the interfaces are here when the UUIDs are announced */
- if (strcasecmp(HSP_AG_UUID, value) == 0 || strcasecmp(HFP_AG_UUID, value) == 0) {
+ if (pa_streq(PA_BLUEZ4_UUID_HSP_AG, value) || pa_streq(PA_BLUEZ4_UUID_HFP_AG, value)) {
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.HandsfreeGateway",
"GetProperties"));
send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
has_audio = true;
- } else if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) {
+ } else if (pa_streq(PA_BLUEZ4_UUID_HSP_HS, value) || pa_streq(PA_BLUEZ4_UUID_HFP_HF, value)) {
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset",
"GetProperties"));
send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
has_audio = true;
- } else if (strcasecmp(A2DP_SINK_UUID, value) == 0) {
+ } else if (pa_streq(PA_BLUEZ4_UUID_A2DP_SINK, value)) {
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSink",
"GetProperties"));
send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
has_audio = true;
- } else if (strcasecmp(A2DP_SOURCE_UUID, value) == 0) {
+ } else if (pa_streq(PA_BLUEZ4_UUID_A2DP_SOURCE, value)) {
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSource",
"GetProperties"));
send_and_add_to_pending(d->discovery, m, get_properties_reply, d);
@@ -829,7 +812,7 @@ static void register_endpoint(pa_bluez4_discovery *y, const char *path, const ch
pa_dbus_append_basic_variant_dict_entry(&d, "Codec", DBUS_TYPE_BYTE, &codec);
- if (pa_streq(uuid, HFP_AG_UUID) || pa_streq(uuid, HFP_HS_UUID)) {
+ if (pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_HF)) {
uint8_t capability = 0;
pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capability, 1);
} else {
@@ -860,10 +843,10 @@ static void found_adapter(pa_bluez4_discovery *y, const char *path) {
pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "GetProperties"));
send_and_add_to_pending(y, m, get_properties_reply, NULL);
- register_endpoint(y, path, ENDPOINT_PATH_HFP_AG, HFP_AG_UUID);
- register_endpoint(y, path, ENDPOINT_PATH_HFP_HS, HFP_HS_UUID);
- register_endpoint(y, path, ENDPOINT_PATH_A2DP_SOURCE, A2DP_SOURCE_UUID);
- register_endpoint(y, path, ENDPOINT_PATH_A2DP_SINK, A2DP_SINK_UUID);
+ register_endpoint(y, path, ENDPOINT_PATH_HFP_AG, PA_BLUEZ4_UUID_HFP_AG);
+ register_endpoint(y, path, ENDPOINT_PATH_HFP_HS, PA_BLUEZ4_UUID_HFP_HF);
+ register_endpoint(y, path, ENDPOINT_PATH_A2DP_SOURCE, PA_BLUEZ4_UUID_A2DP_SOURCE);
+ register_endpoint(y, path, ENDPOINT_PATH_A2DP_SINK, PA_BLUEZ4_UUID_A2DP_SINK);
}
static void list_adapters(pa_bluez4_discovery *y) {
@@ -1888,16 +1871,3 @@ char *pa_bluez4_cleanup_name(const char *name) {
return t;
}
-
-bool pa_bluez4_uuid_has(pa_bluez4_uuid *uuids, const char *uuid) {
- pa_assert(uuid);
-
- while (uuids) {
- if (strcasecmp(uuids->uuid, uuid) == 0)
- return true;
-
- uuids = uuids->next;
- }
-
- return false;
-}
diff --git a/src/modules/bluetooth/bluez4-util.h b/src/modules/bluetooth/bluez4-util.h
index 7c76aac..abbbfab 100644
--- a/src/modules/bluetooth/bluez4-util.h
+++ b/src/modules/bluetooth/bluez4-util.h
@@ -27,34 +27,21 @@
#define PA_BLUEZ4_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
-/* UUID copied from bluez/audio/device.h */
-#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb"
-
-#define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb"
-#define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
-
-#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb"
-#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
-
-#define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb"
-
-#define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb"
-#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
+#define PA_BLUEZ4_UUID_A2DP_SOURCE "0000110a-0000-1000-8000-00805f9b34fb"
+#define PA_BLUEZ4_UUID_A2DP_SINK "0000110b-0000-1000-8000-00805f9b34fb"
+#define PA_BLUEZ4_UUID_HSP_HS "00001108-0000-1000-8000-00805f9b34fb"
+#define PA_BLUEZ4_UUID_HSP_AG "00001112-0000-1000-8000-00805f9b34fb"
+#define PA_BLUEZ4_UUID_HFP_HF "0000111e-0000-1000-8000-00805f9b34fb"
+#define PA_BLUEZ4_UUID_HFP_AG "0000111f-0000-1000-8000-00805f9b34fb"
#define HSP_MAX_GAIN 15
-typedef struct pa_bluez4_uuid pa_bluez4_uuid;
typedef struct pa_bluez4_device pa_bluez4_device;
typedef struct pa_bluez4_discovery pa_bluez4_discovery;
typedef struct pa_bluez4_transport pa_bluez4_transport;
struct userdata;
-struct pa_bluez4_uuid {
- char *uuid;
- PA_LLIST_FIELDS(pa_bluez4_uuid);
-};
-
typedef enum pa_bluez4_profile {
PA_BLUEZ4_PROFILE_A2DP,
PA_BLUEZ4_PROFILE_A2DP_SOURCE,
@@ -123,9 +110,9 @@ struct pa_bluez4_device {
pa_bluez4_transport *transports[PA_BLUEZ4_PROFILE_COUNT];
int paired;
char *alias;
- PA_LLIST_HEAD(pa_bluez4_uuid, uuids);
char *address;
int class;
+ pa_hashmap *uuids; /* char* -> char* (hashmap-as-a-set) */
int trusted;
/* Audio state */
@@ -170,7 +157,6 @@ const char *pa_bluez4_form_factor_to_string(pa_bluez4_form_factor_t ff);
char *pa_bluez4_cleanup_name(const char *name);
-bool pa_bluez4_uuid_has(pa_bluez4_uuid *uuids, const char *uuid);
const char *pa_bluez4_profile_to_string(pa_bluez4_profile_t profile);
#endif
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
index 890b8ec..93eebde 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -732,8 +732,8 @@ static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i) {
dbus_message_iter_recurse(&variant_i, &ai);
if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING && pa_streq(key, "UUIDs")) {
- /* bluetoothd never removes UUIDs from a device object so there
- * is no need to handle it here. */
+ /* bluetoothd never removes UUIDs from a device object so we
+ * don't need to check for disappeared UUIDs here. */
while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
const char *value;
char *uuid;
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
index 2aa6ea6..7f124e2 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -102,7 +102,7 @@ struct pa_bluetooth_device {
char *alias;
char *address;
uint32_t class_of_device;
- pa_hashmap *uuids;
+ pa_hashmap *uuids; /* char* -> char* (hashmap-as-a-set) */
pa_bluetooth_transport *transports[PA_BLUETOOTH_PROFILE_COUNT];
diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
index 13fb7ab..bae4e45 100644
--- a/src/modules/bluetooth/module-bluez4-device.c
+++ b/src/modules/bluetooth/module-bluez4-device.c
@@ -2172,7 +2172,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
pa_assert_se(input_port = pa_hashmap_get(ports, u->input_port_name));
pa_assert_se(output_port = pa_hashmap_get(ports, u->output_port_name));
- if (pa_streq(uuid, A2DP_SINK_UUID)) {
+ if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SINK)) {
p = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP)"), sizeof(pa_bluez4_profile_t));
p->priority = 10;
p->n_sinks = 1;
@@ -2183,7 +2183,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
d = PA_CARD_PROFILE_DATA(p);
*d = PA_BLUEZ4_PROFILE_A2DP;
- } else if (pa_streq(uuid, A2DP_SOURCE_UUID)) {
+ } else if (pa_streq(uuid, PA_BLUEZ4_UUID_A2DP_SOURCE)) {
p = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP)"), sizeof(pa_bluez4_profile_t));
p->priority = 10;
p->n_sinks = 0;
@@ -2194,7 +2194,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
d = PA_CARD_PROFILE_DATA(p);
*d = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
- } else if (pa_streq(uuid, HSP_HS_UUID) || pa_streq(uuid, HFP_HS_UUID)) {
+ } else if (pa_streq(uuid, PA_BLUEZ4_UUID_HSP_HS) || pa_streq(uuid, PA_BLUEZ4_UUID_HFP_HF)) {
p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(pa_bluez4_profile_t));
p->priority = 20;
p->n_sinks = 1;
@@ -2206,7 +2206,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
d = PA_CARD_PROFILE_DATA(p);
*d = PA_BLUEZ4_PROFILE_HSP;
- } else if (pa_streq(uuid, HFP_AG_UUID)) {
+ } else if (pa_streq(uuid, PA_BLUEZ4_UUID_HFP_AG)) {
p = pa_card_profile_new("hfgw", _("Handsfree Gateway"), sizeof(pa_bluez4_profile_t));
p->priority = 20;
p->n_sinks = 1;
@@ -2240,7 +2240,8 @@ static int add_card(struct userdata *u) {
char *n;
const char *profile_str;
const pa_bluez4_device *device;
- const pa_bluez4_uuid *uuid;
+ const char *uuid;
+ void *state;
pa_assert(u);
pa_assert(u->device);
@@ -2276,8 +2277,8 @@ static int add_card(struct userdata *u) {
create_card_ports(u, data.ports);
- PA_LLIST_FOREACH(uuid, device->uuids) {
- p = create_card_profile(u, uuid->uuid, data.ports);
+ PA_HASHMAP_FOREACH(uuid, device->uuids, state) {
+ p = create_card_profile(u, uuid, data.ports);
if (!p)
continue;
commit 570288ccc9e2ce50c270125020353c0899a29b55
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:51 2016 +0300
bluetooth: update device's valid flag after parsing properties
The properties_received flag affects whether the device should be
considered valid, so let's update the valid flag after setting the
properties_received flag.
There's a call to device_update_valid() anyway later when setting
the device adapters, so this change isn't strictly necessary, but
this makes it more obvious that the code is correct (and less
fragile).
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
index e4cf044..890b8ec 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -773,6 +773,7 @@ static void parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i)
if (!d->properties_received) {
d->properties_received = true;
+ device_update_valid(d);
if (!d->address || !d->adapter_path || !d->alias)
pa_log_error("Non-optional information missing for device %s", d->path);
commit eec4d29247386a33d8c2b94a16de8f9ccf63c563
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:50 2016 +0300
bluetooth: remove a redundant assignment
pa_bluetooth_transport_put() assigns the transport to the device's
transports array, so the caller doesn't have to do that.
diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c
index 8d9d95c..222e33b 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -351,7 +351,7 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
pathfd = pa_sprintf_malloc ("%s/fd%d", path, fd);
- d->transports[p] = t = pa_bluetooth_transport_new(d, sender, pathfd, p, NULL, 0);
+ t = pa_bluetooth_transport_new(d, sender, pathfd, p, NULL, 0);
pa_xfree(pathfd);
t->acquire = bluez5_sco_acquire_cb;
commit c538bc7aa42e8853cd155d53aeed1221eed3c1fb
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:49 2016 +0300
card-restore: don't switch profiles when availability changes
module-card-restore should only restore the initial state of new
cards, but profile_available_changed_callback() changed the profile
whenever the saved profile became available. That caused interference
with module-bluetooth-policy, which also sets card profiles based on
the availability changes.
The original reason for having this code was to work around the
problem that bluetooth cards used to be created with only one profile
available, and other profiles would become available soon after the
card creation. Now the bluetooth card creation is delayed until all
profiles are available, so this bad workaround can be removed.
Discussion:
https://lists.freedesktop.org/archives/pulseaudio-discuss/2016-August/026575.html
diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c
index 718a0dd..3c0307b 100644
--- a/src/modules/module-card-restore.c
+++ b/src/modules/module-card-restore.c
@@ -479,36 +479,6 @@ static pa_hook_result_t card_profile_added_callback(pa_core *c, pa_card_profile
return PA_HOOK_OK;
}
-static pa_hook_result_t profile_available_changed_callback(void *hook_data, void *call_data, void *userdata) {
- pa_card_profile *profile = call_data;
- pa_card *card;
- struct userdata *u = userdata;
- struct entry *entry;
-
- pa_assert(profile);
- pa_assert(u);
-
- card = profile->card;
-
- if (profile->available == PA_AVAILABLE_NO)
- return PA_HOOK_OK;
-
- entry = entry_read(u, card->name);
- if (!entry)
- return PA_HOOK_OK;
-
- if (!pa_streq(profile->name, entry->profile)) {
- entry_free(entry);
- return PA_HOOK_OK;
- }
-
- pa_log_info("Card %s profile %s became available, activating.", card->name, profile->name);
- pa_card_set_profile(profile->card, profile, true);
-
- entry_free(entry);
- return PA_HOOK_OK;
-}
-
static pa_hook_result_t port_offset_change_callback(pa_core *c, pa_device_port *port, struct userdata *u) {
struct entry *entry;
pa_card *card;
@@ -654,8 +624,6 @@ int pa__init(pa_module*m) {
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_preferred_port_changed_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_ADDED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_added_callback, u);
- pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED],
- PA_HOOK_NORMAL, profile_available_changed_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) port_offset_change_callback, u);
if (!(fname = pa_state_path("card-database", true)))
commit d9b885e0f1d3eafd38b7ff8ff09c31c040d85b47
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Sun Aug 7 18:45:48 2016 +0300
bluetooth: wait for all profiles to connect before creating card
The CONNECTION_CHANGED hook is used to notify the discovery module
about new and removed devices. When a bluetooth device connects, the
hook used to be called immediately when the first profile connected.
That meant that only one profile was marked as available during the
card creation, other profiles would get marked as available later.
That makes it hard for module-card-restore to restore the saved
profile, if the saved profile becomes available with some delay.
module-card-restore has a workaround for this problem, but that turned
out to interfere with module-bluetooth-policy, so the workaround will
be removed in the next patch.
The BlueZ 4 code doesn't need changes, because we use the
org.bluez.Audio interface to get a notification when all profiles are
connected.
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
index 03c76bf..e4cf044 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -21,6 +21,8 @@
#include <config.h>
#endif
+#include <pulse/rtclock.h>
+#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core.h>
@@ -35,6 +37,8 @@
#include "bluez5-util.h"
+#define WAIT_FOR_PROFILES_TIMEOUT_USEC (3 * PA_USEC_PER_SEC)
+
#define BLUEZ_SERVICE "org.bluez"
#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1"
#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1"
@@ -164,6 +168,95 @@ static const char *transport_state_to_string(pa_bluetooth_transport_state_t stat
return "invalid";
}
+static bool device_supports_profile(pa_bluetooth_device *device, pa_bluetooth_profile_t profile) {
+ switch (profile) {
+ case PA_BLUETOOTH_PROFILE_A2DP_SINK:
+ return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SINK);
+ case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
+ return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SOURCE);
+ case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
+ return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS)
+ || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
+ case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
+ return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG)
+ || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG);
+ case PA_BLUETOOTH_PROFILE_OFF:
+ pa_assert_not_reached();
+ }
+
+ pa_assert_not_reached();
+}
+
+static bool device_is_profile_connected(pa_bluetooth_device *device, pa_bluetooth_profile_t profile) {
+ if (device->transports[profile] && device->transports[profile]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
+ return true;
+ else
+ return false;
+}
+
+static unsigned device_count_disconnected_profiles(pa_bluetooth_device *device) {
+ pa_bluetooth_profile_t profile;
+ unsigned count = 0;
+
+ for (profile = 0; profile < PA_BLUETOOTH_PROFILE_COUNT; profile++) {
+ if (!device_supports_profile(device, profile))
+ continue;
+
+ if (!device_is_profile_connected(device, profile))
+ count++;
+ }
+
+ return count;
+}
+
+static void device_stop_waiting_for_profiles(pa_bluetooth_device *device) {
+ if (!device->wait_for_profiles_timer)
+ return;
+
+ device->discovery->core->mainloop->time_free(device->wait_for_profiles_timer);
+ device->wait_for_profiles_timer = NULL;
+}
+
+static void wait_for_profiles_cb(pa_mainloop_api *api, pa_time_event* event, const struct timeval *tv, void *userdata) {
+ pa_bluetooth_device *device = userdata;
+ pa_strbuf *buf;
+ pa_bluetooth_profile_t profile;
+ bool first = true;
+ char *profiles_str;
+
+ device_stop_waiting_for_profiles(device);
+
+ buf = pa_strbuf_new();
+
+ for (profile = 0; profile < PA_BLUETOOTH_PROFILE_COUNT; profile++) {
+ if (device_is_profile_connected(device, profile))
+ continue;
+
+ if (!device_supports_profile(device, profile))
+ continue;
+
+ if (first)
+ first = false;
+ else
+ pa_strbuf_puts(buf, ", ");
+
+ pa_strbuf_puts(buf, pa_bluetooth_profile_to_string(profile));
+ }
+
+ profiles_str = pa_strbuf_to_string_free(buf);
+ pa_log_debug("Timeout expired, and device %s still has disconnected profiles: %s",
+ device->path, profiles_str);
+ pa_xfree(profiles_str);
+ pa_hook_fire(&device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], device);
+}
+
+static void device_start_waiting_for_profiles(pa_bluetooth_device *device) {
+ pa_assert(!device->wait_for_profiles_timer);
+ device->wait_for_profiles_timer = pa_core_rttime_new(device->discovery->core,
+ pa_rtclock_now() + WAIT_FOR_PROFILES_TIMEOUT_USEC,
+ wait_for_profiles_cb, device);
+}
+
void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_transport_state_t state) {
bool old_any_connected;
@@ -181,8 +274,27 @@ void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_tr
pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED], t);
- if (old_any_connected != pa_bluetooth_device_any_transport_connected(t->device))
- pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);
+ if (old_any_connected != pa_bluetooth_device_any_transport_connected(t->device)) {
+ unsigned n_disconnected_profiles;
+
+ /* If there are profiles that are expected to get connected soon (based
+ * on the UUID list), we wait for a bit before announcing the new
+ * device, so that all profiles have time to get connected before the
+ * card object is created. If we didn't wait, the card would always
+ * have only one profile marked as available in the initial state,
+ * which would prevent module-card-restore from restoring the initial
+ * profile properly. */
+
+ n_disconnected_profiles = device_count_disconnected_profiles(t->device);
+
+ if (n_disconnected_profiles == 0)
+ device_stop_waiting_for_profiles(t->device);
+
+ if (!old_any_connected && n_disconnected_profiles > 0)
+ device_start_waiting_for_profiles(t->device);
+ else
+ pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);
+ }
}
void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
@@ -416,6 +528,8 @@ static void device_free(pa_bluetooth_device *d) {
pa_assert(d);
+ device_stop_waiting_for_profiles(d);
+
for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++) {
pa_bluetooth_transport *t;
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
index d66e8a3..2aa6ea6 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -105,6 +105,8 @@ struct pa_bluetooth_device {
pa_hashmap *uuids;
pa_bluetooth_transport *transports[PA_BLUETOOTH_PROFILE_COUNT];
+
+ pa_time_event *wait_for_profiles_timer;
};
struct pa_bluetooth_adapter {
More information about the pulseaudio-commits
mailing list