From 2986404e1f1324c8f798b1085751824ca21491de Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Fri, 3 May 2013 12:39:56 +0300 Subject: [PATCH] audio: Don't create an avctp session on avrcp disconnect If a paired and connected audio device is disconnected, the avrcp_disconnect() could create a new avctp session that will keep a reference to the corresponding btd_device, preventing it to be removed as explained below. This fix prevents avrcp_disconnect() to create a new and disconnected avctp session when it doesn't exists. Calling org.bluez.Device1.Disconnect on an audio device like the "Monster ClarityHD" will cause first a a2dp_sink_disconnect() call, and then a sink_disconnect() call. This will change the state of the existing avdtp session to AVCTP_STATE_DISCONNECTED triggering a series of callback calls. Among those, the avdtp_set_state() function will call the registered avdtp_callbacks, including avdtp_state_callback() which in turns updates the disconnected state using sink_set_state(). This function will call the registered sink_callbacks, including device_sink_cb(). By this point, the device_sink_cb() will attempt a avrcp_disconnect() over a session that was already disconnected before by the device's diconnect_cb(). This new avrcp_disconnect() causes the avctp_get() to create a new avctp session that holds a reference to the disconnecting btd_device. Steps to reproduce using bluetoothctl: 1. Pair and Connect a Monter ClarityHD audio device. 2. Play some music on it. 3. Disconnect the device. 4. Remove the device. The "remove" command succeeds, but bluetoothd does not sends a removal signal ([DEL] message) for that device. --- profiles/audio/device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/profiles/audio/device.c b/profiles/audio/device.c index 11e145552..54236451a 100644 --- a/profiles/audio/device.c +++ b/profiles/audio/device.c @@ -172,7 +172,7 @@ static void disconnect_cb(struct btd_device *btd_dev, gboolean removal, device_remove_control_timer(dev); - if (dev->control) + if (dev->control && priv->avctp_state != AVCTP_STATE_DISCONNECTED) avrcp_disconnect(dev); if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) @@ -243,7 +243,8 @@ static void device_sink_cb(struct audio_device *dev, case SINK_STATE_DISCONNECTED: if (dev->control) { device_remove_control_timer(dev); - avrcp_disconnect(dev); + if (priv->avctp_state != AVCTP_STATE_DISCONNECTED) + avrcp_disconnect(dev); } device_set_state(dev, AUDIO_STATE_DISCONNECTED); -- 2.47.3