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.
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)
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);