Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b18b09d authored by Sal Savage's avatar Sal Savage Committed by Automerger Merge Worker
Browse files

Merge "Make transaction labels per device" am: 037cf136

Original change: https://android-review.googlesource.com/c/platform/system/bt/+/1692652

Change-Id: I36f8681f585987d6f829c88e648b765de117f3b4
parents dbfd00a2 037cf136
Loading
Loading
Loading
Loading
+137 −151
Original line number Diff line number Diff line
@@ -168,6 +168,19 @@ typedef struct {
  btrc_player_app_ext_attr_t ext_attrs[AVRC_MAX_APP_ATTR_SIZE];
} btif_rc_player_app_settings_t;

typedef struct {
  bool in_use;
  uint8_t lbl;
  uint8_t handle;
  btif_rc_timer_context_t txn_timer_context;
  alarm_t* txn_timer;
} rc_transaction_t;

typedef struct {
  std::recursive_mutex lbllock;
  rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
} rc_transaction_set_t;

/* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single
 * struct */
typedef struct {
@@ -189,6 +202,7 @@ typedef struct {
  bool rc_features_processed;
  uint64_t rc_playing_uid;
  bool rc_procedure_complete;
  rc_transaction_set_t transaction_set;
} btif_rc_device_cb_t;

typedef struct {
@@ -196,19 +210,6 @@ typedef struct {
  btif_rc_device_cb_t rc_multi_cb[BTIF_RC_NUM_CONN];
} rc_cb_t;

typedef struct {
  bool in_use;
  uint8_t lbl;
  uint8_t handle;
  btif_rc_timer_context_t txn_timer_context;
  alarm_t* txn_timer;
} rc_transaction_t;

typedef struct {
  std::recursive_mutex lbllock;
  rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
} rc_device_t;

typedef struct {
  uint8_t label;
  RawAddress rc_addr;
@@ -216,8 +217,6 @@ typedef struct {

typedef struct { uint8_t handle; } btif_rc_handle_t;

rc_device_t device;

static void sleep_ms(uint64_t timeout_ms);

/* Response status code - Unknown Error - this is changed to "reserved" */
@@ -252,6 +251,7 @@ static const uint8_t status_code_map[] = {
    AVRC_STS_ADDR_PLAYER_CHG, /* BTRC_STS_ADDR_PLAY_CHGD */
};

void initialize_device(btif_rc_device_cb_t* p_dev);
static void send_reject_response(uint8_t rc_handle, uint8_t label, uint8_t pdu,
                                 uint8_t status, uint8_t opcode);
static uint8_t opcode_from_pdu(uint8_t pdu);
@@ -259,11 +259,12 @@ static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index,
                             uint8_t label, tBTA_AV_CODE code,
                             tAVRC_RESPONSE* pmetamsg_resp);
static void register_volumechange(uint8_t label, btif_rc_device_cb_t* p_dev);
static void lbl_init();
static void init_all_transactions();
static bt_status_t get_transaction(rc_transaction_t** ptransaction);
static void release_transaction(uint8_t label);
static rc_transaction_t* get_transaction_by_lbl(uint8_t label);
static void init_all_transactions(btif_rc_device_cb_t* p_dev);
static bt_status_t get_transaction(btif_rc_device_cb_t* p_dev,
                                   rc_transaction_t** ptransaction);
static void release_transaction(btif_rc_device_cb_t* p_dev, uint8_t label);
static rc_transaction_t* get_transaction_by_lbl(btif_rc_device_cb_t* p_dev,
                                                uint8_t label);
static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
                                  btif_rc_device_cb_t* p_dev);

@@ -397,6 +398,41 @@ static btif_rc_device_cb_t* alloc_device() {
  return NULL;
}

void initialize_device(btif_rc_device_cb_t* p_dev) {
  if (p_dev == nullptr) return;

  p_dev->rc_connected = false;
  p_dev->br_connected = false;
  p_dev->rc_handle = 0;
  p_dev->rc_features = 0;
  p_dev->rc_cover_art_psm = 0;
  p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
  p_dev->rc_addr = RawAddress::kEmpty;
  p_dev->rc_pending_play = false;
  for (int i = 0; i < MAX_CMD_QUEUE_LEN; ++i) {
    p_dev->rc_pdu_info[i].ctype = 0;
    p_dev->rc_pdu_info[i].label = 0;
    p_dev->rc_pdu_info[i].is_rsp_pending = false;
  }
  if (p_dev->rc_supported_event_list != nullptr) {
    list_clear(p_dev->rc_supported_event_list);
  }
  p_dev->rc_supported_event_list = nullptr;
  p_dev->rc_volume = MAX_VOLUME;
  p_dev->rc_vol_label = MAX_LABEL;
  memset(&p_dev->rc_app_settings, 0, sizeof(btif_rc_player_app_settings_t));
  p_dev->rc_play_status_timer = nullptr;
  p_dev->rc_features_processed = false;
  p_dev->rc_playing_uid = 0;
  p_dev->rc_procedure_complete = false;

  // Leaving the value of the default constructor for the lbllock mutex is fine
  // but we still need to clear out the transaction label set
  memset(&p_dev->transaction_set.transaction, 0,
         sizeof(p_dev->transaction_set.transaction));
  init_all_transactions(p_dev);
}

static btif_rc_device_cb_t* get_connected_device(int index) {
  BTIF_TRACE_DEBUG("%s: index: %d", __func__, index);
  if (index > BTIF_RC_NUM_CONN) {
@@ -412,19 +448,6 @@ static btif_rc_device_cb_t* get_connected_device(int index) {
  return (&btif_rc_cb.rc_multi_cb[index]);
}

static int get_num_connected_devices() {
  int connected_devices = 0;
  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
    if (btif_rc_cb.rc_multi_cb[idx].rc_state ==
        BTRC_CONNECTION_STATE_CONNECTED) {
      connected_devices++;
    }
  }
  BTIF_TRACE_DEBUG("%s: returning connected_devices: %d", __func__,
                   connected_devices);
  return connected_devices;
}

btif_rc_device_cb_t* btif_rc_get_device_by_bda(const RawAddress& bd_addr) {
  VLOG(1) << __func__ << ": bd_addr: " << bd_addr;

@@ -597,16 +620,16 @@ void handle_rc_features(btif_rc_device_cb_t* p_dev) {
    rc_transaction_t* p_transaction = NULL;
    bt_status_t status = BT_STATUS_NOT_READY;
    if (MAX_LABEL == p_dev->rc_vol_label) {
      status = get_transaction(&p_transaction);
      status = get_transaction(p_dev, &p_transaction);
    } else {
      p_transaction = get_transaction_by_lbl(p_dev->rc_vol_label);
      p_transaction = get_transaction_by_lbl(p_dev, p_dev->rc_vol_label);
      if (NULL != p_transaction) {
        BTIF_TRACE_DEBUG(
            "%s: register_volumechange already in progress for label: %d",
            __func__, p_dev->rc_vol_label);
        return;
      }
      status = get_transaction(&p_transaction);
      status = get_transaction(p_dev, &p_transaction);
    }
    if (BT_STATUS_SUCCESS == status && NULL != p_transaction) {
      p_dev->rc_vol_label = p_transaction->lbl;
@@ -738,43 +761,17 @@ void handle_rc_disconnect(tBTA_AV_RC_CLOSE* p_rc_close) {
    BTIF_TRACE_ERROR("Got disconnect of unknown device");
    return;
  }
  /* report connection state if device is AVRCP target */

  /* Report connection state if device is AVRCP target */
  if (bt_rc_ctrl_callbacks != NULL) {
    do_in_jni_thread(
        FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, false,
                              false, p_dev->rc_addr));
  }
  /* Clean up AVRCP procedure flags */
  memset(&p_dev->rc_app_settings, 0, sizeof(btif_rc_player_app_settings_t));
  p_dev->rc_features_processed = false;
  p_dev->rc_procedure_complete = false;
  /* Check and clear the notification event list */
  if (p_dev->rc_supported_event_list != NULL) {
    list_clear(p_dev->rc_supported_event_list);
    p_dev->rc_supported_event_list = NULL;
  }

  /* check if there is another device connected */
  if (p_dev->rc_state == BTRC_CONNECTION_STATE_CONNECTED) {
    p_dev->rc_handle = 0;
    p_dev->rc_connected = false;
    p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;

    memset(p_dev->rc_notif, 0, sizeof(p_dev->rc_notif));

    p_dev->rc_features = 0;
    p_dev->rc_cover_art_psm = 0;
    p_dev->rc_vol_label = MAX_LABEL;
    p_dev->rc_volume = MAX_VOLUME;

    p_dev->rc_addr = RawAddress::kEmpty;
  }
  if (get_num_connected_devices() == 0) {
    BTIF_TRACE_DEBUG("%s: Closing all handles", __func__);
    init_all_transactions();
  }

  p_dev->rc_addr = RawAddress::kEmpty;
  // We'll re-initialize the device state back to what it looked like before
  // the connection
  initialize_device(p_dev);
}

/***************************************************************************
@@ -867,7 +864,7 @@ void handle_rc_passthrough_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) {
  BTIF_TRACE_DEBUG("%s: rc_id: %d state: %s", __func__, p_remote_rsp->rc_id,
                   status);

  release_transaction(p_remote_rsp->label);
  release_transaction(p_dev, p_remote_rsp->label);
  if (bt_rc_ctrl_callbacks != NULL) {
    do_in_jni_thread(
        FROM_HERE,
@@ -914,7 +911,7 @@ void handle_rc_vendorunique_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) {
    BTIF_TRACE_DEBUG("%s: vendor_id: %d status: %s", __func__, vendor_id,
                     status);

    release_transaction(p_remote_rsp->label);
    release_transaction(p_dev, p_remote_rsp->label);
    do_in_jni_thread(FROM_HERE,
                     base::Bind(bt_rc_ctrl_callbacks->groupnavigation_rsp_cb,
                                vendor_id, key_state));
@@ -973,7 +970,7 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) {
  if (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) {
    {
      rc_transaction_t* transaction = NULL;
      transaction = get_transaction_by_lbl(pmeta_msg->label);
      transaction = get_transaction_by_lbl(p_dev, pmeta_msg->label);
      if (transaction != NULL) {
        handle_rc_metamsg_rsp(pmeta_msg, p_dev);
      } else {
@@ -1796,13 +1793,8 @@ static bt_status_t init(btrc_callbacks_t* callbacks) {

  bt_rc_callbacks = callbacks;
  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
    memset(&btif_rc_cb.rc_multi_cb[idx], 0,
           sizeof(btif_rc_cb.rc_multi_cb[idx]));
    btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
    btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
    btif_rc_cb.rc_multi_cb[idx].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
    initialize_device(&btif_rc_cb.rc_multi_cb[idx]);
  }
  lbl_init();

  return result;
}
@@ -1824,13 +1816,8 @@ static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks) {

  bt_rc_ctrl_callbacks = callbacks;
  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
    memset(&btif_rc_cb.rc_multi_cb[idx], 0,
           sizeof(btif_rc_cb.rc_multi_cb[idx]));
    btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
    btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
    btif_rc_cb.rc_multi_cb[idx].rc_features_processed = FALSE;
    initialize_device(&btif_rc_cb.rc_multi_cb[idx]);
  }
  lbl_init();

  return result;
}
@@ -2592,27 +2579,28 @@ static bt_status_t set_volume(uint8_t volume) {
  tAVRC_STS status = BT_STATUS_UNSUPPORTED;

  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
    if (!btif_rc_cb.rc_multi_cb[idx].rc_connected) continue;
    btif_rc_device_cb_t* p_dev = &btif_rc_cb.rc_multi_cb[idx];
    if (!p_dev->rc_connected) continue;

    if (btif_rc_cb.rc_multi_cb[idx].rc_volume == volume) {
    if (p_dev->rc_volume == volume) {
      status = BT_STATUS_DONE;
      BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x", __func__,
                       volume);
      continue;
    }

    if ((btif_rc_cb.rc_multi_cb[idx].rc_volume == volume) ||
        btif_rc_cb.rc_multi_cb[idx].rc_state !=
    if ((p_dev->rc_volume == volume) ||
        p_dev->rc_state !=
            BTRC_CONNECTION_STATE_CONNECTED) {
      continue;
    }

    if ((btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_RCTG) == 0) {
    if ((p_dev->rc_features & BTA_AV_FEAT_RCTG) == 0) {
      status = BT_STATUS_NOT_READY;
      continue;
    }

    if (!(btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_ADV_CTRL))
    if (!(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL))
      continue;

    BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
@@ -2633,7 +2621,7 @@ static bt_status_t set_volume(uint8_t volume) {
    }

    rc_transaction_t* p_transaction = NULL;
    bt_status_t tran_status = get_transaction(&p_transaction);
    bt_status_t tran_status = get_transaction(p_dev, &p_transaction);

    if (tran_status != BT_STATUS_SUCCESS || !p_transaction) {
      osi_free_and_reset((void**)&p_msg);
@@ -2646,8 +2634,7 @@ static bt_status_t set_volume(uint8_t volume) {

    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
                     p_transaction->lbl);
    BTA_AvMetaCmd(btif_rc_cb.rc_multi_cb[idx].rc_handle, p_transaction->lbl,
                  AVRC_CMD_CTRL, p_msg);
    BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
    status = BT_STATUS_SUCCESS;
  }
  return (bt_status_t)status;
@@ -2679,7 +2666,7 @@ static void register_volumechange(uint8_t lbl, btif_rc_device_cb_t* p_dev) {

  BldResp = AVRC_BldCommand(&avrc_cmd, &p_msg);
  if (AVRC_STS_NO_ERROR == BldResp && p_msg) {
    p_transaction = get_transaction_by_lbl(lbl);
    p_transaction = get_transaction_by_lbl(p_dev, lbl);
    if (p_transaction != NULL) {
      BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_NOTIF,
                    p_msg);
@@ -2728,9 +2715,9 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
          AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
          p_dev->rc_vol_label == pmeta_msg->label) {
        p_dev->rc_vol_label = MAX_LABEL;
        release_transaction(p_dev->rc_vol_label);
        release_transaction(p_dev, p_dev->rc_vol_label);
      } else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu) {
        release_transaction(pmeta_msg->label);
        release_transaction(p_dev, pmeta_msg->label);
      }
      return;
    }
@@ -2771,7 +2758,7 @@ static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
    register_volumechange(p_dev->rc_vol_label, p_dev);
  } else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu) {
    /* free up the label here */
    release_transaction(pmeta_msg->label);
    release_transaction(p_dev, pmeta_msg->label);
  }

  BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s",
@@ -2941,7 +2928,7 @@ static void btif_rc_status_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
      handle_get_playstatus_response(&meta_msg, &avrc_response.get_play_status);
      break;
  }
  release_transaction(p_context->rc_status_cmd.label);
  release_transaction(p_dev, p_context->rc_status_cmd.label);
}

/***************************************************************************
@@ -2989,7 +2976,7 @@ static void btif_rc_control_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
      handle_set_app_attr_val_response(&meta_msg, &avrc_response.set_app_val);
      break;
  }
  release_transaction(p_context->rc_control_cmd.label);
  release_transaction(p_dev, p_context->rc_control_cmd.label);
}

/***************************************************************************
@@ -3022,7 +3009,7 @@ static void btif_rc_control_cmd_timer_timeout(void* data) {
static void register_for_event_notification(btif_rc_supported_event_t* p_event,
                                            btif_rc_device_cb_t* p_dev) {
  rc_transaction_t* p_transaction = NULL;
  bt_status_t status = get_transaction(&p_transaction);
  bt_status_t status = get_transaction(p_dev, &p_transaction);
  if (status != BT_STATUS_SUCCESS) {
    BTIF_TRACE_ERROR("%s: no more transaction labels: %d", __func__, status);
    return;
@@ -3037,7 +3024,7 @@ static void register_for_event_notification(btif_rc_supported_event_t* p_event,
  if (status != BT_STATUS_SUCCESS) {
    BTIF_TRACE_ERROR("%s: Error in Notification registration: %d", __func__,
                     status);
    release_transaction(p_transaction->lbl);
    release_transaction(p_dev, p_transaction->lbl);
    return;
  }

@@ -3084,7 +3071,7 @@ bt_status_t build_and_send_vendor_cmd(tAVRC_COMMAND* avrc_cmd,
                                      tBTA_AV_CODE cmd_code,
                                      btif_rc_device_cb_t* p_dev) {
  rc_transaction_t* p_transaction = NULL;
  bt_status_t tran_status = get_transaction(&p_transaction);
  bt_status_t tran_status = get_transaction(p_dev, &p_transaction);
  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;

  BT_HDR* p_msg = NULL;
@@ -3132,7 +3119,7 @@ static bt_status_t build_and_send_browsing_cmd(tAVRC_COMMAND* avrc_cmd,
  }

  rc_transaction_t* p_transaction = NULL;
  bt_status_t tran_status = get_transaction(&p_transaction);
  bt_status_t tran_status = get_transaction(p_dev, &p_transaction);

  if (tran_status != BT_STATUS_SUCCESS || p_transaction == NULL) {
    osi_free(p_msg);
@@ -4313,10 +4300,10 @@ static void handle_set_browsed_player_response(tBTA_AV_META_MSG* pmeta_msg,
 * Returns          None
 *
 **************************************************************************/
static void clear_cmd_timeout(uint8_t label) {
static void clear_cmd_timeout(btif_rc_device_cb_t* p_dev, uint8_t label) {
  rc_transaction_t* p_txn;

  p_txn = get_transaction_by_lbl(label);
  p_txn = get_transaction_by_lbl(p_dev, label);
  if (p_txn == NULL) {
    BTIF_TRACE_ERROR("%s: Error in transaction label lookup", __func__);
    return;
@@ -4339,10 +4326,12 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) {
  uint8_t scratch_buf[512] = {0};  // this variable is unused
  uint16_t buf_len;
  tAVRC_STS status;
  btif_rc_device_cb_t* p_dev = NULL;

  BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d  ", __func__,
                   pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);

  p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
  status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,
                                  &buf_len);
  if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) &&
@@ -4357,7 +4346,7 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) {
        handle_notification_response(pmeta_msg, &avrc_response.reg_notif);
        if (pmeta_msg->code == AVRC_RSP_INTERIM) {
          /* Don't free the transaction Id */
          clear_cmd_timeout(pmeta_msg->label);
          clear_cmd_timeout(p_dev, pmeta_msg->label);
          return;
        }
        break;
@@ -4431,8 +4420,8 @@ static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) {
        __func__, pmeta_msg->code, pmeta_msg->len);
    return;
  }
  BTIF_TRACE_DEBUG("XX __func__ release transaction %d", pmeta_msg->label);
  release_transaction(pmeta_msg->label);
  BTIF_TRACE_DEBUG("%s: release transaction %d", __func__, pmeta_msg->label);
  release_transaction(p_dev, pmeta_msg->label);
}

/***************************************************************************
@@ -5240,7 +5229,7 @@ static bt_status_t send_groupnavigation_cmd(const RawAddress& bd_addr,
  CHECK_RC_CONNECTED(p_dev);

  if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
    bt_status_t tran_status = get_transaction(&p_transaction);
    bt_status_t tran_status = get_transaction(p_dev, &p_transaction);
    if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction)) {
      uint8_t buffer[AVRC_PASS_THRU_GROUP_LEN] = {0};
      uint8_t* start = buffer;
@@ -5286,7 +5275,7 @@ static bt_status_t send_passthrough_cmd(const RawAddress& bd_addr,
  BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code,
                   key_state);
  if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
    bt_status_t tran_status = get_transaction(&p_transaction);
    bt_status_t tran_status = get_transaction(p_dev, &p_transaction);
    if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) {
      BTA_AvRemoteCmd(p_dev->rc_handle, p_transaction->lbl,
                      (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
@@ -5384,28 +5373,18 @@ const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface(void) {
 *
 *      Returns          void
 ******************************************************************************/
static void initialize_transaction(int lbl) {
  std::unique_lock<std::recursive_mutex> lock(device.lbllock);
static void initialize_transaction(btif_rc_device_cb_t* p_dev, int lbl) {
  if (p_dev == nullptr) return;
  rc_transaction_set_t* transaction_set = &(p_dev->transaction_set);
  std::unique_lock<std::recursive_mutex> lock(transaction_set->lbllock);
  if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
    if (alarm_is_scheduled(device.transaction[lbl].txn_timer)) {
      clear_cmd_timeout(lbl);
    }
    device.transaction[lbl].lbl = lbl;
    device.transaction[lbl].in_use = false;
    device.transaction[lbl].handle = 0;
    if (alarm_is_scheduled(transaction_set->transaction[lbl].txn_timer)) {
      clear_cmd_timeout(p_dev, lbl);
    }
    transaction_set->transaction[lbl].lbl = lbl;
    transaction_set->transaction[lbl].in_use = false;
    transaction_set->transaction[lbl].handle = 0;
  }

/*******************************************************************************
 *      Function         lbl_init
 *
 *      Description    Initializes label structures and mutexes.
 *
 *      Returns         void
 ******************************************************************************/
void lbl_init() {
  memset(&device.transaction, 0, sizeof(device.transaction));
  init_all_transactions();
}

/*******************************************************************************
@@ -5416,10 +5395,10 @@ void lbl_init() {
 *
 * Returns          void
 ******************************************************************************/
void init_all_transactions() {
  uint8_t txn_indx = 0;
  for (txn_indx = 0; txn_indx < MAX_TRANSACTIONS_PER_SESSION; txn_indx++) {
    initialize_transaction(txn_indx);
void init_all_transactions(btif_rc_device_cb_t* p_dev) {
  if (p_dev == nullptr) return;
  for (auto i = 0; i < MAX_TRANSACTIONS_PER_SESSION; ++i) {
    initialize_transaction(p_dev, i);
  }
}

@@ -5432,20 +5411,22 @@ void init_all_transactions() {
 *
 * Returns          bt_status_t
 ******************************************************************************/
rc_transaction_t* get_transaction_by_lbl(uint8_t lbl) {
rc_transaction_t* get_transaction_by_lbl(btif_rc_device_cb_t* p_dev,
                                         uint8_t lbl) {
  if (p_dev == nullptr) return nullptr;

  rc_transaction_t* transaction = NULL;
  std::unique_lock<std::recursive_mutex> lock(device.lbllock);
  rc_transaction_set_t* transaction_set = &(p_dev->transaction_set);
  std::unique_lock<std::recursive_mutex> lock(transaction_set->lbllock);

  /* Determine if this is a valid label */
  if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
    if (!device.transaction[lbl].in_use) {
    if (!transaction_set->transaction[lbl].in_use) {
      transaction = NULL;
    } else {
      transaction = &(device.transaction[lbl]);
      BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__, lbl);
      transaction = &(transaction_set->transaction[lbl]);
    }
  }

  return transaction;
}

@@ -5457,20 +5438,24 @@ rc_transaction_t* get_transaction_by_lbl(uint8_t lbl) {
 *
 * Returns          bt_status_t
 ******************************************************************************/
static bt_status_t get_transaction(btif_rc_device_cb_t* p_dev,
                                   rc_transaction_t** ptransaction) {
  if (p_dev == NULL) return BT_STATUS_FAIL;
  rc_transaction_set_t* transaction_set = &(p_dev->transaction_set);
  std::unique_lock<std::recursive_mutex> lock(transaction_set->lbllock);

static bt_status_t get_transaction(rc_transaction_t** ptransaction) {
  std::unique_lock<std::recursive_mutex> lock(device.lbllock);

  // Check for unused transactions
  // Check for unused transactions in the device's transaction set
  for (uint8_t i = 0; i < MAX_TRANSACTIONS_PER_SESSION; i++) {
    if (!device.transaction[i].in_use) {
      BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__,
                       device.transaction[i].lbl);
      device.transaction[i].in_use = true;
      *ptransaction = &(device.transaction[i]);
    if (!transaction_set->transaction[i].in_use) {
      BTIF_TRACE_DEBUG("%s: p_dev=%s, label=%d, got free transaction!",
                       __func__, p_dev->rc_addr.ToString().c_str(), i);
      transaction_set->transaction[i].in_use = true;
      *ptransaction = &(transaction_set->transaction[i]);
      return BT_STATUS_SUCCESS;
    }
  }
  BTIF_TRACE_ERROR("%s: p_dev=%s, failed to find free transaction", __func__,
                   p_dev->rc_addr.ToString().c_str());
  return BT_STATUS_NOMEM;
}

@@ -5482,14 +5467,15 @@ static bt_status_t get_transaction(rc_transaction_t** ptransaction) {
 *
 * Returns          bt_status_t
 ******************************************************************************/
void release_transaction(uint8_t lbl) {
  BTIF_TRACE_DEBUG("%s %d", __func__, lbl);
  rc_transaction_t* transaction = get_transaction_by_lbl(lbl);
void release_transaction(btif_rc_device_cb_t* p_dev, uint8_t lbl) {
  BTIF_TRACE_DEBUG("%s: p_dev=%s, label=%d", __func__,
                   p_dev == NULL ? "null" : p_dev->rc_addr.ToString().c_str(),
                   lbl);
  rc_transaction_t* transaction = get_transaction_by_lbl(p_dev, lbl);

  /* If the transaction is in use... */
  if (transaction != NULL) {
    BTIF_TRACE_DEBUG("%s: lbl: %d", __func__, lbl);
    initialize_transaction(lbl);
    initialize_transaction(p_dev, lbl);
  }
}