Those changes are mandatory to be able to connect to the same VCP renderer more than once without need to restart bluez. - use vcp_disconnect() to close client connection and reset vcs members - call bt_vcp_detach() the same way as bt_vcp_attach - from btd_profile callback - vcs members are cleared during disconnect, because they are expected to be null when connecting --- profiles/audio/vcp.c | 9 +++++++++ src/shared/vcp.c | 23 +++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/profiles/audio/vcp.c b/profiles/audio/vcp.c index 83e568f22..0203673bf 100644 --- a/profiles/audio/vcp.c +++ b/profiles/audio/vcp.c @@ -72,7 +72,16 @@ static void vcp_debug(const char *str, void *user_data) static int vcp_disconnect(struct btd_service *service) { + struct vcp_data *data = btd_service_get_user_data(service); DBG(""); + + if (!data) { + error("VCP service not handled by profile"); + return -EINVAL; + } + bt_vcp_detach(data->vcp); + + btd_service_disconnecting_complete(service, 0); return 0; } diff --git a/src/shared/vcp.c b/src/shared/vcp.c index 489cd2b97..c92eb00d4 100644 --- a/src/shared/vcp.c +++ b/src/shared/vcp.c @@ -389,13 +389,24 @@ static void vcp_detached(void *data, void *user_data) void bt_vcp_detach(struct bt_vcp *vcp) { + struct bt_vcs *vcs; if (!queue_remove(sessions, vcp)) return; - bt_gatt_client_unref(vcp->client); - vcp->client = NULL; + if (vcp->client) { + bt_gatt_client_unref(vcp->client); + vcp->client = NULL; + } - queue_foreach(vcp_cbs, vcp_detached, vcp); + if (vcp->rdb) { + vcs = vcp_get_vcs(vcp); + vcs->service = NULL; + vcs->vs = NULL; + vcs->vs_ccc = NULL; + vcs->vol_cp = NULL; + vcs->vf = NULL; + vcs->vf_ccc = NULL; + } } static void vcp_db_free(void *data) @@ -489,6 +500,7 @@ static void vcp_debug(struct bt_vcp *vcp, const char *format, ...) static void vcp_disconnected(int err, void *user_data) { + // called only when this device is acting a a server struct bt_vcp *vcp = user_data; DBG(vcp, "vcp %p disconnected err %d", vcp, err); @@ -508,12 +520,15 @@ static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db) return vcp; } + // called only when this device is acting a a server vcp = bt_vcp_new(db, NULL); vcp->att = att; bt_att_register_disconnect(att, vcp_disconnected, vcp, NULL); - bt_vcp_attach(vcp, NULL); + if (!sessions) + sessions = queue_new(); + queue_push_tail(sessions, vcp); return vcp; -- 2.34.1