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

Commit 507f4b51 authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk
Browse files

le_audio: Split AudioStreamDataPath to Data Path and CIS state

There is possibility to have more different states than covered by
AudioStreamDataPath. CIS state is not strictly related to DATA PATH
state. There is also a possiblity to have disconnected CIS and
configured data path.

as per Bluetooth Core v5.4, 7.7.5 Disconnection Complete event,

"If Connection_Handle identifies a CIS on the Central, the handle
and the associated data paths of that CIS shall remain valid
(irrespective of whether the disconnection was successful or not)"

Bug: 278621595
Tag: #feature
Test: atest bluetooth_le_audio_test
Change-Id: I9b363484ba881ce6f94017a2a72b7bb6cb826d9e
parent 50d371f3
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -89,8 +89,8 @@ using le_audio::types::ase;
using le_audio::types::AseState;
using le_audio::types::AudioContexts;
using le_audio::types::AudioLocations;
using le_audio::types::AudioStreamDataPathState;
using le_audio::types::BidirectionalPair;
using le_audio::types::DataPathState;
using le_audio::types::hdl_pair;
using le_audio::types::kDefaultScanDurationS;
using le_audio::types::kLeAudioContextAllBidir;
@@ -3002,8 +3002,7 @@ class LeAudioClientImpl : public LeAudioClient {
  bool IsAseAcceptingAudioData(struct ase* ase) {
    if (ase == nullptr) return false;
    if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) return false;
    if (ase->data_path_state != AudioStreamDataPathState::DATA_PATH_ESTABLISHED)
      return false;
    if (ase->data_path_state != DataPathState::CONFIGURED) return false;

    return true;
  }
+64 −54
Original line number Diff line number Diff line
@@ -51,9 +51,10 @@ using le_audio::types::ase;
using le_audio::types::AseState;
using le_audio::types::AudioContexts;
using le_audio::types::AudioLocations;
using le_audio::types::AudioStreamDataPathState;
using le_audio::types::BidirectionalPair;
using le_audio::types::CisState;
using le_audio::types::CisType;
using le_audio::types::DataPathState;
using le_audio::types::LeAudioCodecId;
using le_audio::types::LeAudioContextType;
using le_audio::types::LeAudioLc3Config;
@@ -467,17 +468,18 @@ LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice(
  return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
}

LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByDataPathState(
    AudioStreamDataPathState data_path_state) const {
  auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
                           [&data_path_state](auto& d) {
LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByCisAndDataPathState(
    CisState cis_state, DataPathState data_path_state) const {
  auto iter =
      std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
                   [&data_path_state, &cis_state](auto& d) {
                     if (d.expired()) {
                       return false;
                     }

                     return (((d.lock()).get())
                                         ->GetFirstActiveAseByDataPathState(
                                             data_path_state) != nullptr);
                                 ->GetFirstActiveAseByCisAndDataPathState(
                                     cis_state, data_path_state) != nullptr);
                   });

  if (iter == leAudioDevices_.end()) {
@@ -487,9 +489,9 @@ LeAudioDevice* LeAudioDeviceGroup::GetFirstActiveDeviceByDataPathState(
  return iter->lock().get();
}

LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByDataPathState(
    LeAudioDevice* leAudioDevice,
    AudioStreamDataPathState data_path_state) const {
LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByCisAndDataPathState(
    LeAudioDevice* leAudioDevice, CisState cis_state,
    DataPathState data_path_state) const {
  auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
                           [&leAudioDevice](auto& d) {
                             if (d.expired()) {
@@ -503,15 +505,15 @@ LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByDataPathState(
    return nullptr;
  }

  iter = std::find_if(
      std::next(iter, 1), leAudioDevices_.end(), [&data_path_state](auto& d) {
  iter = std::find_if(std::next(iter, 1), leAudioDevices_.end(),
                      [&cis_state, &data_path_state](auto& d) {
                        if (d.expired()) {
                          return false;
                        }

                        return (((d.lock()).get())
                    ->GetFirstActiveAseByDataPathState(data_path_state) !=
                nullptr);
                                    ->GetFirstActiveAseByCisAndDataPathState(
                                        cis_state, data_path_state) != nullptr);
                      });

  if (iter == leAudioDevices_.end()) {
@@ -1208,25 +1210,25 @@ void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses(

  /* Assign all CIS connection handles to ases */
  struct le_audio::types::ase* ase =
      leAudioDevice->GetFirstActiveAseByDataPathState(
          AudioStreamDataPathState::IDLE);
      leAudioDevice->GetFirstActiveAseByCisAndDataPathState(
          CisState::IDLE, DataPathState::IDLE);
  if (!ase) {
    LOG_WARN("No active ASE with AudioStreamDataPathState IDLE");
    LOG_WARN("No active ASE with Cis and Data path state set to IDLE");
    return;
  }

  for (; ase != nullptr; ase = leAudioDevice->GetFirstActiveAseByDataPathState(
                             AudioStreamDataPathState::IDLE)) {
  for (; ase != nullptr;
       ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(
           CisState::IDLE, DataPathState::IDLE)) {
    auto ases_pair = leAudioDevice->GetAsesByCisId(ase->cis_id);

    if (ases_pair.sink && ases_pair.sink->active) {
      ases_pair.sink->cis_conn_hdl = cises_[ase->cis_id].conn_handle;
      ases_pair.sink->data_path_state = AudioStreamDataPathState::CIS_ASSIGNED;
      ases_pair.sink->cis_state = CisState::ASSIGNED;
    }
    if (ases_pair.source && ases_pair.source->active) {
      ases_pair.source->cis_conn_hdl = cises_[ase->cis_id].conn_handle;
      ases_pair.source->data_path_state =
          AudioStreamDataPathState::CIS_ASSIGNED;
      ases_pair.source->cis_state = CisState::ASSIGNED;
    }
  }
}
@@ -2436,11 +2438,13 @@ struct ase* LeAudioDevice::GetNextActiveAseWithDifferentDirection(
  return &(*iter);
}

struct ase* LeAudioDevice::GetFirstActiveAseByDataPathState(
    types::AudioStreamDataPathState state) {
  auto iter =
      std::find_if(ases_.begin(), ases_.end(), [state](const auto& ase) {
        return (ase.active && (ase.data_path_state == state));
struct ase* LeAudioDevice::GetFirstActiveAseByCisAndDataPathState(
    types::CisState cis_state, types::DataPathState data_path_state) {
  auto iter = std::find_if(ases_.begin(), ases_.end(),
                           [cis_state, data_path_state](const auto& ase) {
                             return (ase.active &&
                                     (ase.data_path_state == data_path_state) &&
                                     (ase.cis_state == cis_state));
                           });

  return (iter == ases_.end()) ? nullptr : &(*iter);
@@ -2555,9 +2559,12 @@ bool LeAudioDevice::HaveAnyUnconfiguredAses(void) {
}

bool LeAudioDevice::HaveAllActiveAsesSameState(AseState state) {
  auto iter = std::find_if(
      ases_.begin(), ases_.end(),
      [&state](const auto& ase) { return ase.active && (ase.state != state); });
  auto iter =
      std::find_if(ases_.begin(), ases_.end(), [&state](const auto& ase) {
        LOG_INFO("id: %d, active: %d, state: %d", ase.id, ase.active,
                 (int)ase.state);
        return ase.active && (ase.state != state);
      });

  return iter == ases_.end();
}
@@ -2609,8 +2616,7 @@ bool LeAudioDevice::HaveAllActiveAsesCisEst(void) {
  }

  auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) {
    return ase.active &&
           (ase.data_path_state != AudioStreamDataPathState::CIS_ESTABLISHED);
    return ase.active && (ase.cis_state != CisState::CONNECTED);
  });

  return iter == ases_.end();
@@ -2619,8 +2625,8 @@ bool LeAudioDevice::HaveAllActiveAsesCisEst(void) {
bool LeAudioDevice::HaveAnyCisConnected(void) {
  /* Pending and Disconnecting is considered as connected in this function */
  for (auto const ase : ases_) {
    if (ase.data_path_state != AudioStreamDataPathState::CIS_ASSIGNED &&
        ase.data_path_state != AudioStreamDataPathState::IDLE) {
    if (ase.cis_state != CisState::ASSIGNED &&
        ase.cis_state != CisState::IDLE) {
      return true;
    }
  }
@@ -2754,7 +2760,9 @@ void LeAudioDevice::PrintDebugState(void) {
                << (ase.direction == types::kLeAudioDirectionSink ? "sink"
                                                                  : "source")
                << ", cis_id: " << +ase.cis_id
                << ", cis_handle: " << +ase.cis_conn_hdl << ", state: "
                << ", cis_handle: " << +ase.cis_conn_hdl
                << ", state: " << bluetooth::common::ToString(ase.cis_state)
                << ", data_path_state: "
                << bluetooth::common::ToString(ase.data_path_state)
                << "\n ase max_latency: " << +ase.max_transport_latency
                << ", rtn: " << +ase.retrans_nb
@@ -2829,8 +2837,8 @@ void LeAudioDevice::Dump(int fd) {

  if (ases_.size() > 0) {
    stream << "\n\t== ASEs == \n\t";
    stream
        << "id  active dir     cis_id  cis_handle  sdu  latency rtn  state";
    stream << "id  active dir     cis_id  cis_handle  sdu  latency rtn  "
              "cis_state data_path_state";
    for (auto& ase : ases_) {
      stream << std::setfill('\x20') << "\n\t" << std::left << std::setw(4)
             << static_cast<int>(ase.id) << std::left << std::setw(7)
@@ -2841,7 +2849,8 @@ void LeAudioDevice::Dump(int fd) {
             << std::left << std::setw(12) << ase.cis_conn_hdl << std::left
             << std::setw(5) << ase.max_sdu_size << std::left << std::setw(8)
             << ase.max_transport_latency << std::left << std::setw(5)
             << static_cast<int>(ase.retrans_nb) << std::left << std::setw(12)
             << static_cast<int>(ase.retrans_nb) << std::left << std::setw(10)
             << bluetooth::common::ToString(ase.cis_state) << std::setw(12)
             << bluetooth::common::ToString(ase.data_path_state);
    }
  }
@@ -2902,17 +2911,18 @@ bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {

void LeAudioDevice::DeactivateAllAses(void) {
  for (auto& ase : ases_) {
    if (ase.active == false &&
        ase.data_path_state != AudioStreamDataPathState::IDLE) {
    if (ase.active == false && ase.cis_state != CisState::IDLE &&
        ase.data_path_state != DataPathState::IDLE) {
      LOG_WARN(
          " %s, ase_id: %d, ase.cis_id: %d, cis_handle: 0x%02x, "
          "ase.data_path=%s",
          "ase.cis_state=%s, ase.data_path_state=%s",
          ADDRESS_TO_LOGGABLE_CSTR(address_), ase.id, ase.cis_id,
          ase.cis_conn_hdl,
          ase.cis_conn_hdl, bluetooth::common::ToString(ase.cis_state).c_str(),
          bluetooth::common::ToString(ase.data_path_state).c_str());
    }
    ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
    ase.data_path_state = AudioStreamDataPathState::IDLE;
    ase.cis_state = CisState::IDLE;
    ase.data_path_state = DataPathState::IDLE;
    ase.active = false;
    ase.cis_id = le_audio::kInvalidCisId;
    ase.cis_conn_hdl = 0;
+7 −7
Original line number Diff line number Diff line
@@ -149,8 +149,8 @@ class LeAudioDevice {
      struct types::ase* base_ase);
  struct types::ase* GetNextActiveAseWithDifferentDirection(
      struct types::ase* base_ase);
  struct types::ase* GetFirstActiveAseByDataPathState(
      types::AudioStreamDataPathState state);
  struct types::ase* GetFirstActiveAseByCisAndDataPathState(
      types::CisState cis_state, types::DataPathState data_path_state);
  struct types::ase* GetFirstInactiveAse(uint8_t direction,
                                         bool reconnect = false);
  struct types::ase* GetFirstAseWithState(uint8_t direction,
@@ -347,11 +347,11 @@ class LeAudioDeviceGroup {
      types::LeAudioContextType context_type) const;
  LeAudioDevice* GetFirstActiveDevice(void) const;
  LeAudioDevice* GetNextActiveDevice(LeAudioDevice* leAudioDevice) const;
  LeAudioDevice* GetFirstActiveDeviceByDataPathState(
      types::AudioStreamDataPathState data_path_state) const;
  LeAudioDevice* GetNextActiveDeviceByDataPathState(
      LeAudioDevice* leAudioDevice,
      types::AudioStreamDataPathState data_path_state) const;
  LeAudioDevice* GetFirstActiveDeviceByCisAndDataPathState(
      types::CisState cis_state, types::DataPathState data_path_state) const;
  LeAudioDevice* GetNextActiveDeviceByCisAndDataPathState(
      LeAudioDevice* leAudioDevice, types::CisState cis_state,
      types::DataPathState data_path_state) const;
  bool IsDeviceInTheGroup(LeAudioDevice* leAudioDevice) const;
  bool HaveAllActiveDevicesAsesTheSameState(types::AseState state) const;
  bool HaveAnyActiveDeviceInUnconfiguredState() const;
+13 −13
Original line number Diff line number Diff line
@@ -758,7 +758,8 @@ class UnicastTestNoInit : public Test {
              for (LeAudioDevice* device = group->GetFirstDevice();
                   device != nullptr; device = group->GetNextDevice(device)) {
                for (auto& ase : device->ases_) {
                  ase.data_path_state = types::AudioStreamDataPathState::IDLE;
                  ase.cis_state = types::CisState::IDLE;
                  ase.data_path_state = types::DataPathState::IDLE;
                  ase.active = false;
                  ase.state =
                      types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
@@ -806,8 +807,8 @@ class UnicastTestNoInit : public Test {

            // And also skip the ase establishment procedure which should
            // be tested as part of the state machine unit tests
            ase.data_path_state =
                types::AudioStreamDataPathState::DATA_PATH_ESTABLISHED;
            ase.cis_state = types::CisState::CONNECTED;
            ase.data_path_state = types::DataPathState::CONFIGURED;
            ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;

            uint16_t cis_conn_hdl = ase.cis_conn_hdl;
@@ -936,8 +937,8 @@ class UnicastTestNoInit : public Test {

              // And also skip the ase establishment procedure which should
              // be tested as part of the state machine unit tests
              ase.data_path_state =
                  types::AudioStreamDataPathState::DATA_PATH_ESTABLISHED;
              ase.cis_state = types::CisState::CONNECTED;
              ase.data_path_state = types::DataPathState::CONFIGURED;
              ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;
              ase.pres_delay_min = 2500;
              ase.pres_delay_max = 2500;
@@ -1130,8 +1131,7 @@ class UnicastTestNoInit : public Test {
          for (LeAudioDevice* device = group->GetFirstDevice();
               device != nullptr; device = group->GetNextDevice(device)) {
            for (auto& ase : device->ases_) {
              ase.data_path_state =
                  types::AudioStreamDataPathState::CIS_ESTABLISHED;
              ase.cis_state = types::CisState::CONNECTED;
              ase.active = false;
              ase.state =
                  types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED;
@@ -1214,14 +1214,12 @@ class UnicastTestNoInit : public Test {
              auto ases_pair =
                  leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl);
              if (ases_pair.sink) {
                ases_pair.sink->data_path_state =
                    types::AudioStreamDataPathState::CIS_ASSIGNED;
                ases_pair.sink->cis_state = types::CisState::ASSIGNED;
                ases_pair.sink->active = false;
              }
              if (ases_pair.source) {
                ases_pair.source->active = false;
                ases_pair.source->data_path_state =
                    types::AudioStreamDataPathState::CIS_ASSIGNED;
                ases_pair.source->cis_state = types::CisState::ASSIGNED;
              }
              /* Invalidate stream configuration if needed */
              auto* stream_conf = &group->stream_conf;
@@ -1357,7 +1355,8 @@ class UnicastTestNoInit : public Test {
            group->CigUnassignCis(device);

            for (auto& ase : device->ases_) {
              ase.data_path_state = types::AudioStreamDataPathState::IDLE;
              ase.cis_state = types::CisState::IDLE;
              ase.data_path_state = types::DataPathState::IDLE;
              ase.active = false;
              ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
              ase.cis_id = 0;
@@ -4672,7 +4671,8 @@ TEST_F(UnicastTest, SpeakerStreamingAutonomousRelease) {
  for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr;
       device = group->GetNextDevice(device)) {
    for (auto& ase : device->ases_) {
      ase.data_path_state = types::AudioStreamDataPathState::IDLE;
      ase.cis_state = types::CisState::IDLE;
      ase.data_path_state = types::DataPathState::IDLE;
      ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
      InjectCisDisconnected(group_id, ase.cis_conn_hdl);
    }
+12 −9
Original line number Diff line number Diff line
@@ -770,15 +770,18 @@ uint8_t GetMaxCodecFramesPerSduFromPac(const acs_ac_record* pac) {
}

namespace types {
std::ostream& operator<<(std::ostream& os,
                         const AudioStreamDataPathState& state) {
  static const char* char_value_[7] = {"IDLE",
                                       "CIS_DISCONNECTING",
                                       "CIS_ASSIGNED",
                                       "CIS_PENDING",
                                       "CIS_ESTABLISHED",
                                       "DATA_PATH_ESTABLISHED",
                                       "DATA_PATH_REMOVING"};
std::ostream& operator<<(std::ostream& os, const CisState& state) {
  static const char* char_value_[5] = {"IDLE", "ASSIGNED", "CONNECTING",
                                       "CONNECTED", "DISCONNECTING"};

  os << char_value_[static_cast<uint8_t>(state)] << " ("
     << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
     << ")";
  return os;
}
std::ostream& operator<<(std::ostream& os, const DataPathState& state) {
  static const char* char_value_[4] = {"IDLE", "CONFIGURING", "CONFIGURED",
                                       "REMOVING"};

  os << char_value_[static_cast<uint8_t>(state)] << " ("
     << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
Loading