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

Commit 0fee6691 authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Gerrit Code Review
Browse files

Merge "btm: Add BIS related code to Iso Manager"

parents 5c03584d 7f1ac0f2
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "btm_iso_impl.h"
#include "btu.h"

using bluetooth::hci::iso_manager::BigCallbacks;
using bluetooth::hci::iso_manager::CigCallbacks;
using bluetooth::hci::iso_manager::iso_impl;

@@ -52,6 +53,10 @@ void IsoManager::RegisterCigCallbacks(CigCallbacks* callbacks) const {
  pimpl_->iso_impl_->handle_register_cis_callbacks(callbacks);
}

void IsoManager::RegisterBigCallbacks(BigCallbacks* callbacks) const {
  pimpl_->iso_impl_->handle_register_big_callbacks(callbacks);
}

void IsoManager::CreateCig(uint8_t cig_id,
                           struct iso_manager::cig_create_params cig_params) {
  pimpl_->iso_impl_->create_cig(cig_id, std::move(cig_params));
@@ -89,6 +94,15 @@ void IsoManager::SendIsoData(uint16_t iso_handle, const uint8_t* data,
  pimpl_->iso_impl_->send_iso_data(iso_handle, data, data_len);
}

void IsoManager::CreateBig(uint8_t big_id,
                           struct iso_manager::big_create_params big_params) {
  pimpl_->iso_impl_->create_big(big_id, std::move(big_params));
}

void IsoManager::TerminateBig(uint8_t big_id, uint8_t reason) {
  pimpl_->iso_impl_->terminate_big(big_id, reason);
}

void IsoManager::HandleIsoData(void* p_msg) {
  if (pimpl_->IsRunning())
    pimpl_->iso_impl_->handle_iso_data(static_cast<BT_HDR*>(p_msg));
+142 −14
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static constexpr uint8_t kIsoHeaderWithoutTsLen = 8;
static constexpr uint8_t kStateFlagsNone = 0x00;
static constexpr uint8_t kStateFlagIsConnected = 0x01;
static constexpr uint8_t kStateFlagHasDataPathSet = 0x02;
static constexpr uint8_t kStateFlagIsBroadcast = 0x04;

struct iso_sync_info {
  uint32_t first_sync_ts;
@@ -48,7 +49,10 @@ struct iso_sync_info {
};

struct iso_base {
  union {
    uint8_t cig_id;
    uint8_t big_handle;
  };

  struct iso_sync_info sync_info;
  uint8_t state_flags;
@@ -56,6 +60,7 @@ struct iso_base {
};

typedef iso_base iso_cis;
typedef iso_base iso_bis;

struct iso_impl {
  iso_impl() {
@@ -70,6 +75,11 @@ struct iso_impl {
    cig_callbacks_ = callbacks;
  }

  void handle_register_big_callbacks(BigCallbacks* callbacks) {
    LOG_ASSERT(callbacks != nullptr) << "Invalid BIG callbacks";
    big_callbacks_ = callbacks;
  }

  void on_set_cig_params(uint8_t cig_id, uint32_t sdu_itv_mtos, uint8_t* stream,
                         uint16_t len) {
    uint8_t cis_cnt;
@@ -226,10 +236,14 @@ struct iso_impl {
    LOG_ASSERT(iso != nullptr) << "Invalid connection handle: " << +conn_handle;

    if (status == HCI_SUCCESS) iso->state_flags |= kStateFlagHasDataPathSet;

    if (iso->state_flags & kStateFlagIsBroadcast) {
      LOG_ASSERT(big_callbacks_ != nullptr) << "Invalid BIG callbacks";
      big_callbacks_->OnSetupIsoDataPath(status, conn_handle, iso->big_handle);
    } else {
      LOG_ASSERT(cig_callbacks_ != nullptr) << "Invalid CIG callbacks";
      cig_callbacks_->OnSetupIsoDataPath(status, conn_handle, iso->cig_id);
    }
  }

  void setup_iso_data_path(
      uint16_t conn_handle,
@@ -237,8 +251,10 @@ struct iso_impl {
    iso_base* iso = GetIsoIfKnown(conn_handle);
    LOG_ASSERT(iso != nullptr) << "No such iso connection: " << +conn_handle;

    if (!(iso->state_flags & kStateFlagIsBroadcast)) {
      LOG_ASSERT(iso->state_flags & kStateFlagIsConnected)
          << "CIS not established";
    }

    btsnd_hcic_setup_iso_data_path(
        conn_handle, path_params.data_path_dir, path_params.data_path_id,
@@ -261,9 +277,14 @@ struct iso_impl {

    if (status == HCI_SUCCESS) iso->state_flags &= ~kStateFlagHasDataPathSet;

    if (iso->state_flags & kStateFlagIsBroadcast) {
      LOG_ASSERT(big_callbacks_ != nullptr) << "Invalid BIG callbacks";
      big_callbacks_->OnRemoveIsoDataPath(status, conn_handle, iso->big_handle);
    } else {
      LOG_ASSERT(cig_callbacks_ != nullptr) << "Invalid CIG callbacks";
      cig_callbacks_->OnRemoveIsoDataPath(status, conn_handle, iso->cig_id);
    }
  }

  void remove_iso_data_path(uint16_t iso_handle, uint8_t data_path_dir) {
    iso_base* iso = GetIsoIfKnown(iso_handle);
@@ -314,8 +335,10 @@ struct iso_impl {
    LOG_ASSERT(iso != nullptr)
        << "No such iso connection handle: " << +iso_handle;

    if (!(iso->state_flags & kStateFlagIsBroadcast)) {
      LOG_ASSERT(iso->state_flags & kStateFlagIsConnected)
          << "CIS not established";
    }
    LOG_ASSERT(iso->state_flags & kStateFlagHasDataPathSet)
        << "Data path not set for handle: " << +iso_handle;

@@ -411,23 +434,109 @@ struct iso_impl {
      STREAM_TO_UINT16(handle, p);
      STREAM_TO_UINT16(num_sent, p);

      if (conn_hdl_to_cis_map_.find(handle) == conn_hdl_to_cis_map_.end())
      if ((conn_hdl_to_cis_map_.find(handle) == conn_hdl_to_cis_map_.end()) &&
          (conn_hdl_to_bis_map_.find(handle) == conn_hdl_to_bis_map_.end()))
        continue;

      iso_credits_ += num_sent;
    }
  }

  void process_create_big_cmpl_pkt(uint8_t len, uint8_t* data) {
    struct big_create_cmpl_evt evt;

    LOG_ASSERT(len >= 18) << "Invalid packet length";
    LOG_ASSERT(big_callbacks_ != nullptr) << "Invalid BIG callbacks";

    STREAM_TO_UINT8(evt.status, data);
    STREAM_TO_UINT8(evt.big_id, data);
    STREAM_TO_UINT24(evt.big_sync_delay, data);
    STREAM_TO_UINT24(evt.transport_latency_big, data);
    STREAM_TO_UINT8(evt.phy, data);
    STREAM_TO_UINT8(evt.nse, data);
    STREAM_TO_UINT8(evt.bn, data);
    STREAM_TO_UINT8(evt.pto, data);
    STREAM_TO_UINT8(evt.irc, data);
    STREAM_TO_UINT16(evt.max_pdu, data);
    STREAM_TO_UINT16(evt.iso_interval, data);

    uint8_t num_bis;
    STREAM_TO_UINT8(num_bis, data);

    LOG_ASSERT(num_bis != 0) << "Invalid bis count";
    LOG_ASSERT(len == (18 + num_bis * sizeof(uint16_t)))
        << "Invalid packet length";

    uint32_t ts = bluetooth::common::time_get_os_boottime_us();
    for (auto i = 0; i < num_bis; ++i) {
      uint16_t conn_handle;
      STREAM_TO_UINT16(conn_handle, data);
      evt.conn_handles.push_back(conn_handle);
      LOG_INFO(" received BIS conn_hdl %d", +conn_handle);

      if (evt.status == HCI_SUCCESS) {
        conn_hdl_to_bis_map_[conn_handle] = std::unique_ptr<iso_bis>(
            new iso_bis({.sync_info = {.first_sync_ts = ts, .seq_nb = 0},
                         .big_handle = evt.big_id,
                         .state_flags = kStateFlagIsBroadcast,
                         .sdu_itv = last_big_create_req_sdu_itv_}));
      }
    }

    big_callbacks_->OnBigEvent(kIsoEventBigOnCreateCmpl, &evt);
  }

  void process_terminate_big_cmpl_pkt(uint8_t len, uint8_t* data) {
    struct big_terminate_cmpl_evt evt;

    LOG_ASSERT(len == 2) << "Invalid packet length";
    LOG_ASSERT(big_callbacks_ != nullptr) << "Invalid BIG callbacks";

    STREAM_TO_UINT8(evt.big_id, data);
    STREAM_TO_UINT8(evt.reason, data);

    bool is_known_handle = false;
    auto bis_it = conn_hdl_to_bis_map_.cbegin();
    while (bis_it != conn_hdl_to_bis_map_.cend()) {
      if (bis_it->second->big_handle == evt.big_id) {
        bis_it = conn_hdl_to_bis_map_.erase(bis_it);
        is_known_handle = true;
      } else {
        ++bis_it;
      }
    }

    LOG_ASSERT(is_known_handle) << "No such big";
    big_callbacks_->OnBigEvent(kIsoEventBigOnTerminateCmpl, &evt);
  }

  void create_big(uint8_t big_id, struct big_create_params big_params) {
    LOG_ASSERT(!IsBigKnown(big_id)) << "Invalid big - already exists";

    last_big_create_req_sdu_itv_ = big_params.sdu_itv;
    btsnd_hcic_create_big(
        big_id, big_params.adv_handle, big_params.num_bis, big_params.sdu_itv,
        big_params.max_sdu_size, big_params.max_transport_latency,
        big_params.rtn, big_params.phy, big_params.packing, big_params.framing,
        big_params.enc, big_params.enc_code);
  }

  void terminate_big(uint8_t big_id, uint8_t reason) {
    LOG_ASSERT(IsBigKnown(big_id)) << "No such big";

    btsnd_hcic_term_big(big_id, reason);
  }

  void on_iso_event(uint8_t code, uint8_t* packet, uint16_t packet_len) {
    switch (code) {
      case HCI_BLE_CIS_EST_EVT:
        process_cis_est_pkt(packet_len, packet);
        break;
      case HCI_BLE_CREATE_BIG_CPL_EVT:
        /* TODO: Implement */
        process_create_big_cmpl_pkt(packet_len, packet);
        break;
      case HCI_BLE_TERM_BIG_CPL_EVT:
        /* TODO: Implement */
        process_terminate_big_cmpl_pkt(packet_len, packet);
        break;
      case HCI_BLE_CIS_REQ_EVT:
        /* Not supported */
@@ -503,8 +612,15 @@ struct iso_impl {
                                                  : nullptr;
  }

  iso_bis* GetBisIfKnown(uint16_t bis_conn_handle) {
    auto bis_it = conn_hdl_to_bis_map_.find(bis_conn_handle);
    return (bis_it != conn_hdl_to_bis_map_.end()) ? bis_it->second.get()
                                                  : nullptr;
  }

  iso_base* GetIsoIfKnown(uint16_t iso_handle) {
    return GetCisIfKnown(iso_handle);
    struct iso_base* iso = GetCisIfKnown(iso_handle);
    return (iso != nullptr) ? iso : GetBisIfKnown(iso_handle);
  }

  bool IsCigKnown(uint8_t cig_id) const {
@@ -516,12 +632,24 @@ struct iso_impl {
    return (cis_it != conn_hdl_to_cis_map_.cend());
  }

  bool IsBigKnown(uint8_t big_id) const {
    auto bis_it =
        std::find_if(conn_hdl_to_bis_map_.cbegin(), conn_hdl_to_bis_map_.cend(),
                     [&big_id](auto& kv_pair) {
                       return (kv_pair.second->big_handle == big_id);
                     });
    return (bis_it != conn_hdl_to_bis_map_.cend());
  }

  std::map<uint16_t, std::unique_ptr<iso_cis>> conn_hdl_to_cis_map_;
  std::map<uint16_t, std::unique_ptr<iso_bis>> conn_hdl_to_bis_map_;

  uint16_t iso_credits_;
  uint16_t iso_buffer_size_;
  uint32_t last_big_create_req_sdu_itv_;

  CigCallbacks* cig_callbacks_ = nullptr;
  BigCallbacks* big_callbacks_ = nullptr;
};

}  // namespace iso_manager
+40 −4
Original line number Diff line number Diff line
@@ -36,6 +36,16 @@ struct CigCallbacks {
  virtual void OnCisEvent(uint8_t event, void* data) = 0;
  virtual void OnCigEvent(uint8_t event, void* data) = 0;
};

struct BigCallbacks {
  virtual ~BigCallbacks() = default;
  virtual void OnSetupIsoDataPath(uint8_t status, uint16_t conn_handle,
                                  uint8_t big_id) = 0;
  virtual void OnRemoveIsoDataPath(uint8_t status, uint16_t conn_handle,
                                   uint8_t big_id) = 0;

  virtual void OnBigEvent(uint8_t event, void* data) = 0;
};
}  // namespace iso_manager

class IsoManager {
@@ -57,6 +67,15 @@ class IsoManager {
   */
  virtual void RegisterCigCallbacks(iso_manager::CigCallbacks* callbacks) const;

  /**
   * Set BIG related callbacks
   *
   * <p> Shall be set by the Le Audio Broadcaster implementation
   *
   * @param callbacks BigCallbacks implementation
   */
  virtual void RegisterBigCallbacks(iso_manager::BigCallbacks* callbacks) const;

  /**
   * Creates connected isochronous group (CIG) according to given params.
   *
@@ -102,7 +121,7 @@ class IsoManager {
   * Initiates creation of isochronous data path for connected isochronous
   * stream.
   *
   * @param conn_handle handle of CIS connection
   * @param conn_handle handle of BIS or CIS connection
   * @param path_params iso data path parameters
   */
  virtual void SetupIsoDataPath(
@@ -113,7 +132,7 @@ class IsoManager {
   * Initiates removement of isochronous data path for connected isochronous
   * stream.
   *
   * @param conn_handle handle of CIS connection
   * @param conn_handle handle of BIS or CIS connection
   * @param data_path_dir iso data path direction
   */
  virtual void RemoveIsoDataPath(uint16_t conn_handle, uint8_t data_path_dir);
@@ -121,13 +140,30 @@ class IsoManager {
  /**
   * Sends iso data to the controller
   *
   * @param conn_handle handle of CIS connection
   * @param conn_handle handle of BIS or CIS connection
   * @param data data buffer. The ownership of data is not being transferred.
   * @param data_len data buffer length
   */
  virtual void SendIsoData(uint16_t conn_handle, const uint8_t* data,
                           uint16_t data_len);

  /**
   * Creates the Broadcast Isochronous Group
   *
   * @param big_id host assigned BIG identifier
   * @param big_params BIG parameters
   */
  virtual void CreateBig(uint8_t big_id,
                         struct iso_manager::big_create_params big_params);

  /**
   * Terminates the Broadcast Isochronous Group
   *
   * @param big_id host assigned BIG identifier
   * @param reason termination reason data
   */
  virtual void TerminateBig(uint8_t big_id, uint8_t reason);

  /* Below are defined handlers called by the legacy code in btu_hcif.cc */

  /**
@@ -159,7 +195,7 @@ class IsoManager {
  virtual void HandleNumComplDataPkts(uint8_t* p, uint8_t evt_len);

  /**
   * Handle CIS related HCI events
   * Handle CIS and BIG related HCI events
   *
   * @param sub_code ble subcode for the HCI event
   * @param params raw packet buffer for the event. The ownership of params is
+37 −0
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@ constexpr uint8_t kIsoEventCigOnCreateCmpl = 0x00;
constexpr uint8_t kIsoEventCigOnReconfigureCmpl = 0x01;
constexpr uint8_t kIsoEventCigOnRemoveCmpl = 0x02;

constexpr uint8_t kIsoEventBigOnCreateCmpl = 0x00;
constexpr uint8_t kIsoEventBigOnTerminateCmpl = 0x01;

struct cig_create_params {
  uint32_t sdu_itv_mtos;
  uint32_t sdu_itv_stom;
@@ -107,6 +110,40 @@ struct cis_disconnected_evt {
  uint16_t cis_conn_hdl;
};

struct big_create_params {
  uint8_t adv_handle;
  uint8_t num_bis;
  uint32_t sdu_itv;
  uint16_t max_sdu_size;
  uint16_t max_transport_latency;
  uint8_t rtn;
  uint8_t phy;
  uint8_t packing;
  uint8_t framing;
  uint8_t enc;
  std::array<uint8_t, 16> enc_code;
};

struct big_create_cmpl_evt {
  uint8_t status;
  uint8_t big_id;
  uint32_t big_sync_delay;
  uint32_t transport_latency_big;
  uint8_t phy;
  uint8_t nse;
  uint8_t bn;
  uint8_t pto;
  uint8_t irc;
  uint16_t max_pdu;
  uint16_t iso_interval;
  std::vector<uint16_t> conn_handles;
};

struct big_terminate_cmpl_evt {
  uint8_t big_id;
  uint8_t reason;
};

struct iso_data_path_params {
  uint8_t data_path_dir;
  uint8_t data_path_id;
+631 −4

File changed.

Preview size limit exceeded, changes collapsed.

Loading