summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMikel Astiz <mikel.astiz@bmw-carit.de>2012-08-31 12:51:05 +0200
committerArun Raghavan <arun.raghavan@collabora.co.uk>2012-09-26 19:27:14 +0800
commitb8fd6f869ede117bf0a0b937c49c25c60c039b7c (patch)
treebe3be62cd34b46b7cc8a4060db4e66c40f571959 /src
parent884d1d46ca5b563cae319003a2b3d0196dff05d1 (diff)
bluetooth: Do not acquire transport during profile change
Until today, setting the card to some profile resulted in a transport acquisition, leading to audio stream setup. This is generally not very interesting and even undesireable for HFGW use-cases, where the Gateway role (the remote end) would typically request the SCO link. Nevertheless, there is no safe way to implement such check without race conditions, since the BlueZ's state can change between the state report and the call to Acquire(). The chances for this to reproduce are quite low though, since interface state changes are relatively slow. This race condition requires that BlueZ's API is extended in order to perform the operation atomically, which has already been discussed and ack-ed in the BlueZ mailing list. Note that this patch does not introduce a new race condition, since it already existed before (the PropertyChanged->Acquire race condition, affecting HFGW use-cases). It is just more explicit now.
Diffstat (limited to 'src')
-rw-r--r--src/modules/bluetooth/module-bluetooth-device.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index c900979e1..6757e87bb 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -365,8 +365,26 @@ static void bt_transport_release(struct userdata *u) {
teardown_stream(u);
}
+static pa_bt_audio_state_t get_profile_audio_state(const struct userdata *u, const pa_bluetooth_device *d) {
+ switch(u->profile) {
+ case PROFILE_HSP:
+ return d->headset_state;
+ case PROFILE_A2DP:
+ return d->audio_sink_state;
+ case PROFILE_A2DP_SOURCE:
+ return d->audio_source_state;
+ case PROFILE_HFGW:
+ return d->hfgw_state;
+ case PROFILE_OFF:
+ break;
+ }
+
+ pa_assert_not_reached();
+}
+
static int bt_transport_acquire(struct userdata *u, pa_bool_t start) {
const char *accesstype = "rw";
+ const pa_bluetooth_device *d;
const pa_bluetooth_transport *t;
if (u->transport == NULL) {
@@ -382,6 +400,12 @@ static int bt_transport_acquire(struct userdata *u, pa_bool_t start) {
pa_log_debug("Acquiring transport %s", u->transport);
+ d = pa_bluetooth_discovery_get_by_path(u->discovery, u->path);
+ if (!d) {
+ pa_log_error("Failed to get device object.");
+ return -1;
+ }
+
t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
if (!t) {
pa_log("Transport %s no longer available", u->transport);
@@ -390,6 +414,20 @@ static int bt_transport_acquire(struct userdata *u, pa_bool_t start) {
return -1;
}
+ if (!start) {
+ /* 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 (get_profile_audio_state(u, d) < PA_BT_AUDIO_STATE_PLAYING) {
+ pa_log_info("Failed optional acquire of transport %s", u->transport);
+ return -1;
+ }
+ }
+
u->stream_fd = pa_bluetooth_transport_acquire(t, accesstype, &u->read_link_mtu, &u->write_link_mtu);
if (u->stream_fd < 0) {
if (start)