diff --git a/subsys/bluetooth/audio/aics_client.c b/subsys/bluetooth/audio/aics_client.c index 412bdbcb741..943f6475a38 100644 --- a/subsys/bluetooth/audio/aics_client.c +++ b/subsys/bluetooth/audio/aics_client.c @@ -618,6 +618,8 @@ static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_att */ sub_params->ccc_handle = attr->handle + 2; sub_params->notify = aics_client_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { LOG_ERR("Failed to subscribe: %d", err); @@ -651,16 +653,6 @@ static void aics_client_reset(struct bt_aics *inst) if (inst->cli.conn != NULL) { struct bt_conn *conn = inst->cli.conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &inst->cli.state_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->cli.status_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->cli.desc_sub_params); - bt_conn_unref(conn); inst->cli.conn = NULL; } @@ -711,7 +703,6 @@ int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, (void)memset(&inst->cli.discover_params, 0, sizeof(inst->cli.discover_params)); - inst->cli.conn = bt_conn_ref(conn); inst->cli.discover_params.start_handle = param->start_handle; inst->cli.discover_params.end_handle = param->end_handle; inst->cli.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; @@ -722,6 +713,7 @@ int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, LOG_DBG("Discover failed (err %d)", err); } else { inst->cli.busy = true; + inst->cli.conn = bt_conn_ref(conn); } return err; diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index c96462db8ab..b2047998ce8 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(bt_bap_broadcast_assistant, CONFIG_BT_BAP_BROADCAST_ASSISTAN #define MINIMUM_RECV_STATE_LEN 15 struct bap_broadcast_assistant_instance { - bool discovering; + struct bt_conn *conn; bool scanning; uint8_t pa_sync; uint8_t recv_state_cnt; @@ -61,7 +61,6 @@ struct bap_broadcast_assistant_instance { struct bt_gatt_discover_params disc_params; struct k_work_delayable bap_read_work; - struct bt_conn *conn; uint16_t long_read_handle; }; @@ -431,8 +430,8 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, if (cb_err != 0) { LOG_DBG("err: %d", cb_err); - if (broadcast_assistant.discovering) { - broadcast_assistant.discovering = false; + if (broadcast_assistant.busy) { + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, @@ -447,8 +446,8 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, } } } else if (handle == last_handle) { - if (broadcast_assistant.discovering) { - broadcast_assistant.discovering = false; + if (broadcast_assistant.busy) { + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover( @@ -486,8 +485,6 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, static void discover_init(void) { - (void)memset(&broadcast_assistant, 0, sizeof(broadcast_assistant)); - k_work_init_delayable(&broadcast_assistant.bap_read_work, delayed_bap_read_handler); net_buf_simple_reset(&att_buf); @@ -512,7 +509,7 @@ static uint8_t char_discover_func(struct bt_conn *conn, err = bt_bap_broadcast_assistant_read_recv_state(conn, 0); if (err != 0) { - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, err, 0); @@ -552,13 +549,14 @@ static uint8_t char_discover_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = attr->handle + 1; sub_params->notify = notify_handler; - err = bt_gatt_subscribe(conn, sub_params); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - if (err != 0 && err != -EALREADY) { + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0) { LOG_DBG("Could not subscribe to handle 0x%04x: %d", sub_params->value_handle, err); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, @@ -585,7 +583,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, LOG_DBG("Could not discover BASS"); (void)memset(params, 0, sizeof(*params)); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { @@ -612,7 +610,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &broadcast_assistant.disc_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { @@ -759,16 +757,56 @@ static struct bt_le_scan_cb scan_cb = { static int broadcast_assistant_reset(struct bap_broadcast_assistant_instance *inst) { - broadcast_assistant.long_read_handle = 0; - (void)k_work_cancel_delayable(&broadcast_assistant.bap_read_work); + inst->busy = false; + inst->scanning = false; + inst->pa_sync = 0U; + inst->recv_state_cnt = 0U; + inst->start_handle = 0U; + inst->end_handle = 0U; + inst->cp_handle = 0U; + inst->long_read_handle = 0; + (void)k_work_cancel_delayable(&inst->bap_read_work); + + for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT; i++) { + inst->src_ids[i] = 0U; + inst->past_avail[i] = false; + inst->recv_state_handles[i] = 0U; + } if (inst->conn != NULL) { struct bt_conn *conn = inst->conn; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + return err; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + for (size_t i = 0U; i < ARRAY_SIZE(inst->recv_state_sub_params); i++) { + /* It's okay if this fail with -EINVAL as that means that they are + * not currently subscribed + */ + err = bt_gatt_unsubscribe(conn, &inst->recv_state_sub_params[i]); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to state: %d", err); + + return err; + } + } + } bt_conn_unref(conn); inst->conn = NULL; } + /* The subscribe parameters must remain instact so they can get cleaned up by GATT */ + memset(&inst->disc_params, 0, sizeof(inst->disc_params)); + memset(&inst->recv_state_disc_params, 0, sizeof(inst->recv_state_disc_params)); + memset(&inst->read_params, 0, sizeof(inst->read_params)); + memset(&inst->write_params, 0, sizeof(inst->write_params)); + return 0; } @@ -817,7 +855,7 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn) return err; } - broadcast_assistant.discovering = true; + broadcast_assistant.busy = true; broadcast_assistant.conn = bt_conn_ref(conn); return 0; diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index e27725ec2c5..14e89b4da60 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -1611,6 +1611,7 @@ static uint8_t unicast_client_ep_notify(struct bt_conn *conn, static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *ep) { struct bt_bap_unicast_client_ep *client_ep; + int err; client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep); @@ -1628,7 +1629,12 @@ static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *e client_ep->subscribe.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(client_ep->subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(conn, &client_ep->subscribe); + err = bt_gatt_subscribe(conn, &client_ep->subscribe); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static void pac_record_cb(struct bt_conn *conn, const struct bt_audio_codec_cap *codec_cap) @@ -1718,7 +1724,7 @@ static void unicast_client_ep_set_cp(struct bt_conn *conn, uint16_t handle) atomic_set_bit(client->cp_subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, &client->cp_subscribe); - if (err != 0) { + if (err != 0 && err != -EALREADY) { LOG_DBG("Failed to subscribe: %d", err); discover_cb(conn, err); @@ -3510,6 +3516,7 @@ static uint8_t unicast_client_pacs_avail_ctx_discover_cb(struct bt_conn *conn, sub_params->disc_params = &uni_cli_insts[index].avail_ctx_cc_disc; sub_params->notify = unicast_client_pacs_avail_ctx_notify_cb; sub_params->value = BT_GATT_CCC_NOTIFY; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { @@ -3708,6 +3715,7 @@ static uint8_t unicast_client_pacs_location_discover_cb(struct bt_conn *conn, sub_params->disc_params = &uni_cli_insts[index].loc_cc_disc; sub_params->notify = unicast_client_pacs_location_notify_cb; sub_params->value = BT_GATT_CCC_NOTIFY; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index 4c5faefd13a..e0fdb8a6084 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -747,6 +747,7 @@ static uint8_t discover_func(struct bt_conn *conn, sub_params->end_handle = cur_inst->end_handle; sub_params->value_handle = chrc->value_handle; sub_params->notify = notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { @@ -1342,20 +1343,6 @@ static void csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst *inst if (svc_inst->conn != NULL) { struct bt_conn *conn = svc_inst->conn; - /* It's okay if these fail. In case of disconnect, - * we can't unsubscribe and they will just fail. - * In case that we reset due to another call of the - * discover function, we will unsubscribe (regardless of - * bonding state) to accommodate the new discovery - * values. - */ - (void)bt_gatt_unsubscribe(conn, - &svc_inst->sirk_sub_params); - (void)bt_gatt_unsubscribe(conn, - &svc_inst->size_sub_params); - (void)bt_gatt_unsubscribe(conn, - &svc_inst->lock_sub_params); - bt_conn_unref(conn); svc_inst->conn = NULL; } diff --git a/subsys/bluetooth/audio/has_client.c b/subsys/bluetooth/audio/has_client.c index 437fa425e21..9ac33139a96 100644 --- a/subsys/bluetooth/audio/has_client.c +++ b/subsys/bluetooth/audio/has_client.c @@ -425,6 +425,8 @@ static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_handle) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->active_index_subscription.notify = active_preset_notify_cb; @@ -436,7 +438,12 @@ static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_han inst->active_index_subscription.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(inst->active_index_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(inst->conn, &inst->active_index_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->active_index_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, @@ -520,6 +527,8 @@ fail: static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_handle, uint8_t properties) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->control_point_subscription.notify = control_point_notify_cb; @@ -536,7 +545,12 @@ static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_ha inst->control_point_subscription.value = BT_GATT_CCC_INDICATE; } - return bt_gatt_subscribe(inst->conn, &inst->control_point_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->control_point_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -709,6 +723,8 @@ static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->features_subscription.notify = features_notify_cb; @@ -720,7 +736,12 @@ static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle) inst->features_subscription.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(inst->features_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(inst->conn, &inst->features_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->features_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, diff --git a/subsys/bluetooth/audio/mcc.c b/subsys/bluetooth/audio/mcc.c index 909ce19a3cb..e192c0352db 100644 --- a/subsys/bluetooth/audio/mcc.c +++ b/subsys/bluetooth/audio/mcc.c @@ -1156,77 +1156,215 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } -static void reset_mcs_inst(struct mcs_instance_t *mcs_inst, struct bt_conn *conn) +static int reset_mcs_inst(struct mcs_instance_t *mcs_inst) { - (void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, busy)); + if (mcs_inst->conn != NULL) { + struct bt_conn *conn = mcs_inst->conn; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + return err; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + /* It's okay if these fail with -EINVAL as that means that they are + * not currently subscribed + */ + err = bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to name: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track change: %d", err); + + return err; + } - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track title: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ + #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track duration: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ + #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track position: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ + #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to playback speed: %d", err); + + return err; + } #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ + #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to seeking speed: %d", err); + + return err; + } #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ + #ifdef CONFIG_BT_MCC_OTS - (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to current track object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to next track object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to parent group object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to current group object: %d", err); + + return err; + } + #endif /* CONFIG_BT_MCC_OTS */ #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to playing order: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ + #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to media state: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ - (void)bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); + + err = bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to control point: %d", err); + + return err; + } + #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) - (void)bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to supported opcodes: %d", err); + + return err; + } #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ + #ifdef CONFIG_BT_MCC_OTS - (void)bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to search control point: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to search results: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to oacp: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to olcp: %d", err); + + return err; + } +#endif /* CONFIG_BT_MCC_OTS */ + } + + bt_conn_unref(conn); + mcs_inst->conn = NULL; + } + + (void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, busy)); +#ifdef CONFIG_BT_MCC_OTS + /* Reset OTC instance as well if supported */ + (void)memset(&mcs_inst->otc, 0, offsetof(struct bt_ots_client, oacp_sub_params)); #endif /* CONFIG_BT_MCC_OTS */ - /* Reset OTC instance as well if supported */ -#ifdef CONFIG_BT_MCC_OTS - (void)memset(&mcs_inst->otc, 0, - offsetof(struct bt_ots_client, oacp_sub_params)); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params); -#endif /* CONFIG_BT_MCC_OTS */ + return 0; } +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + struct mcs_instance_t *mcs_inst; + + mcs_inst = lookup_inst_by_conn(conn); + if (mcs_inst != NULL) { + (void)reset_mcs_inst(mcs_inst); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected_cb, +}; + /* Called when discovery is completed - successfully or with error */ static void discovery_complete(struct bt_conn *conn, int err) { + struct mcs_instance_t *mcs_inst; + LOG_DBG("Discovery completed, err: %d", err); - /* TODO: Handle resets of instance, and re-discovery. - * For now, reset instance on error. - */ - if (err) { - struct mcs_instance_t *mcs_inst; - - mcs_inst = lookup_inst_by_conn(conn); - if (mcs_inst != NULL) { - reset_mcs_inst(mcs_inst, conn); + mcs_inst = lookup_inst_by_conn(conn); + if (mcs_inst != NULL) { + mcs_inst->busy = false; + if (err != 0) { + (void)reset_mcs_inst(mcs_inst); } } @@ -1296,6 +1434,7 @@ static uint8_t discover_otc_char_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_INDICATE; sub_params->value_handle = chrc->value_handle; sub_params->notify = bt_ots_client_indicate_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0) { @@ -1463,7 +1602,7 @@ static int do_subscribe(struct mcs_instance_t *mcs_inst, struct bt_conn *conn, sub_params->subscribe = subscribe_mcs_char_func; /* disc_params pointer is also used as subscription flag */ sub_params->disc_params = &mcs_inst->discover_params; - atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_NO_RESUB); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); LOG_DBG("Subscring to handle %d", handle); return bt_gatt_subscribe(conn, sub_params); @@ -1945,6 +2084,7 @@ int bt_mcc_init(struct bt_mcc_cb *cb) int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) { struct mcs_instance_t *mcs_inst; + int err; CHECKIF(!conn) { return -EINVAL; @@ -1961,7 +2101,12 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) } subscribe_all = subscribe; - reset_mcs_inst(mcs_inst, conn); + err = reset_mcs_inst(mcs_inst); + if (err != 0) { + LOG_DBG("Failed to reset MCS instance %p: %d", mcs_inst, err); + + return err; + } (void)memcpy(&uuid, BT_UUID_GMCS, sizeof(uuid)); mcs_inst->discover_params.func = discover_primary_func; @@ -1971,7 +2116,15 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) mcs_inst->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; LOG_DBG("start discovery of GMCS primary service"); - return bt_gatt_discover(conn, &mcs_inst->discover_params); + err = bt_gatt_discover(conn, &mcs_inst->discover_params); + if (err != 0) { + return err; + } + + mcs_inst->conn = bt_conn_ref(conn); + mcs_inst->busy = true; + + return 0; } int bt_mcc_read_player_name(struct bt_conn *conn) diff --git a/subsys/bluetooth/audio/mcc_internal.h b/subsys/bluetooth/audio/mcc_internal.h index 2d005d1fbee..2838e53ba35 100644 --- a/subsys/bluetooth/audio/mcc_internal.h +++ b/subsys/bluetooth/audio/mcc_internal.h @@ -19,6 +19,7 @@ struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn); struct mcs_instance_t { + struct bt_conn *conn; uint16_t start_handle; uint16_t end_handle; uint16_t player_name_handle; diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 974c1ba8124..8232d664dce 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -409,9 +409,10 @@ static uint8_t micp_discover_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = chrc->value_handle; sub_params->notify = mute_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); - if (err == 0) { + if (err == 0 || err == -EALREADY) { LOG_DBG("Subscribed to handle 0x%04X", attr->handle); } else { LOG_DBG("Could not subscribe to handle 0x%04X: %d", attr->handle, @@ -480,14 +481,6 @@ static void micp_mic_ctlr_reset(struct bt_micp_mic_ctlr *mic_ctlr) if (mic_ctlr->conn != NULL) { struct bt_conn *conn = mic_ctlr->conn; - /* It's okay if this fails. In case of disconnect, we can't - * unsubscribe and it will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &mic_ctlr->mute_sub_params); - bt_conn_unref(conn); mic_ctlr->conn = NULL; } diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 9ef759c3c1e..564db2a667c 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -1539,8 +1539,9 @@ static uint8_t discover_func(struct bt_conn *conn, sub_params->end_handle = current_inst->end_handle; sub_params->notify = notify_handler; atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); - if (err != 0) { + if (err != 0 && err != -EALREADY) { LOG_DBG("Could not subscribe to " "characterstic at handle 0x%04X" "(%d)", diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index 6f41f61ec90..d0f9075dafe 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -449,8 +449,10 @@ static uint8_t vcs_discover_func(struct bt_conn *conn, sub_params->ccc_handle = 0; sub_params->end_handle = vol_ctlr->end_handle; sub_params->notify = vcp_vol_ctlr_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); - if (err == 0) { + if (err == 0 || err == -EALREADY) { LOG_DBG("Subscribed to handle 0x%04X", attr->handle); } else { @@ -817,15 +819,6 @@ static void vcp_vol_ctlr_reset(struct bt_vcp_vol_ctlr *vol_ctlr) if (vol_ctlr->conn != NULL) { struct bt_conn *conn = vol_ctlr->conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &vol_ctlr->state_sub_params); - (void)bt_gatt_unsubscribe(conn, &vol_ctlr->flag_sub_params); - bt_conn_unref(conn); vol_ctlr->conn = NULL; } diff --git a/subsys/bluetooth/audio/vocs_client.c b/subsys/bluetooth/audio/vocs_client.c index 4f88d647ad8..e39b8ac69f6 100644 --- a/subsys/bluetooth/audio/vocs_client.c +++ b/subsys/bluetooth/audio/vocs_client.c @@ -411,9 +411,15 @@ static uint8_t vocs_discover_func(struct bt_conn *conn, const struct bt_gatt_att */ sub_params->ccc_handle = attr->handle + 2; sub_params->notify = vocs_client_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + err = bt_gatt_subscribe(conn, sub_params); - if (err) { + if (err != 0 && err != -EALREADY) { LOG_WRN("Could not subscribe to handle %u", sub_params->ccc_handle); + + inst->cb->discover(&inst->vocs, err); + + return BT_GATT_ITER_STOP; } } } @@ -687,16 +693,6 @@ static void vocs_client_reset(struct bt_vocs_client *inst) if (inst->conn != NULL) { struct bt_conn *conn = inst->conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &inst->state_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->location_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->desc_sub_params); - bt_conn_unref(conn); inst->conn = NULL; } diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c index 3980fe963ab..32b68af76ff 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c @@ -307,6 +307,16 @@ static void test_bass_discover(void) return; } + WAIT_FOR_FLAG(flag_discovery_complete); + + /* Verify that we can discover again */ + flag_discovery_complete = false; + err = bt_bap_broadcast_assistant_discover(default_conn); + if (err != 0) { + FAIL("Failed to discover BASS for the second time: %d\n", err); + return; + } + WAIT_FOR_FLAG(flag_discovery_complete); printk("Discovery complete\n"); } diff --git a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c index 8be4a3e34c5..9a4e69d5625 100644 --- a/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c +++ b/tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c @@ -832,6 +832,16 @@ static void test_discover(void) } WAIT_FOR_COND(g_discovery_complete); + + /* Verify that we can discover again */ + g_discovery_complete = false; + err = bt_vcp_vol_ctlr_discover(default_conn, &vol_ctlr); + if (err != 0) { + FAIL("Failed to discover VCP for the second time: %d\n", err); + return; + } + + WAIT_FOR_COND(g_discovery_complete); } static void test_included_get(void) diff --git a/tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh b/tests/bsim/bluetooth/audio/test_scripts/_csip_notify.sh similarity index 100% rename from tests/bsim/bluetooth/audio/test_scripts/csip_notify.sh rename to tests/bsim/bluetooth/audio/test_scripts/_csip_notify.sh