Some A2DP audio devices initiate audio sink state transitions over the Audio/Video Remote Control (AVRCP) profile. Specifically, trying to switch the A2DP sink into PLAYING state is problematic, because the Bluetooth device has no way of knowing when streaming is ready to start on the host side. If it is detected that the A2DP audio sink has already been set to PLAYING state by Bluez when PulseAudio is starting to transition the sink from IDLE to PLAYING, the transport will be released and re-acquired (in effect, making PulseAudio the initiator again.) This prevents audio loss at least with Jabra SP700. --- src/modules/bluetooth/module-bluetooth-device.c | 27 +++++++++++++++++++++- 1 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index b7945ed..e86c745 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -2356,7 +2356,30 @@ static int bt_transport_config(struct userdata *u) { } /* Run from main thread */ -static int bt_transport_open(struct userdata *u) { +/* This function is only called when a Bluetooth profile is initialized */ +static int bt_transport_initialize(struct userdata *u, const pa_bluetooth_device *device) { + pa_assert(u); + pa_assert(device); + + /* Some A2DP audio devices initiate audio sink state transitions over the + * Audio/Video Remote Control (AVRCP) profile. Specifically, trying to + * switch the A2DP sink into PLAYING state is problematic, because the + * Bluetooth device has no way of knowing when streaming is ready to start + * on the host side. If it is detected that the A2DP audio sink has already + * been set to PLAYING state by Bluez when PulseAudio is starting to + * transition the sink from IDLE to PLAYING, the transport will be released + * and re-acquired (in effect, making PulseAudio the initiator again.) + * This prevents audio loss at least with Jabra SP700. */ + if (u->profile == PROFILE_A2DP && device->audio_sink_state == PA_BT_AUDIO_STATE_PLAYING) { + pa_log_debug("The audio sink of device %s is already in PLAYING state. Release and re-acquire transport.", + device->name); + + if (bt_transport_acquire(u, FALSE) < 0) + return -1; + else + bt_transport_release(u); + } + if (bt_transport_acquire(u, FALSE) < 0) return -1; @@ -2406,7 +2429,7 @@ static int setup_bt(struct userdata *u) { t = pa_bluetooth_device_get_transport(d, u->profile); if (t) { u->transport = pa_xstrdup(t->path); - return bt_transport_open(u); + return bt_transport_initialize(u, d); } if (get_caps(u, 0) < 0) -- 1.7.0.4