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

Commit 0ee25801 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "leaudio: Handle seamless streaming during late join or drop of member...

Merge "leaudio: Handle seamless streaming during late join or drop of member devices" into tm-qpr-dev
parents a56322c2 d572cc91
Loading
Loading
Loading
Loading
+18 −56
Original line number Diff line number Diff line
@@ -2051,54 +2051,15 @@ class LeAudioClientImpl : public LeAudioClient {
    auto num_of_devices =
        get_num_of_devices_in_configuration(stream_conf->conf);

    if (num_of_devices < group->NumOfConnected()) {
      /* Second device got just paired. We need to reconfigure CIG */
    if (num_of_devices < group->NumOfConnected() &&
        !group->IsConfigurationSupported(leAudioDevice, stream_conf->conf)) {
      /* Reconfigure if newly connected member device cannot support current
       * codec configuration */
      group->SetPendingConfiguration();
      groupStateMachine_->StopStream(group);
      return;
    }

    /* Second device got reconnect. Try to get it to the stream seamlessly */
    le_audio::types::AudioLocations sink_group_audio_locations = 0;
    uint8_t sink_num_of_active_ases = 0;

    for (auto [cis_handle, audio_location] : stream_conf->sink_streams) {
      sink_group_audio_locations |= audio_location;
      sink_num_of_active_ases++;
    }

    le_audio::types::AudioLocations source_group_audio_locations = 0;
    uint8_t source_num_of_active_ases = 0;

    for (auto [cis_handle, audio_location] : stream_conf->source_streams) {
      source_group_audio_locations |= audio_location;
      source_num_of_active_ases++;
    }

    for (auto& ent : stream_conf->conf->confs) {
      if (ent.direction == le_audio::types::kLeAudioDirectionSink) {
        /* Sink*/
        if (!leAudioDevice->ConfigureAses(ent, group->GetCurrentContextType(),
                                          &sink_num_of_active_ases,
                                          sink_group_audio_locations,
                                          source_group_audio_locations, true)) {
          LOG(INFO) << __func__ << " Could not set sink configuration of "
                    << stream_conf->conf->name;
          return;
        }
      } else {
        /* Source*/
        if (!leAudioDevice->ConfigureAses(ent, group->GetCurrentContextType(),
                                          &source_num_of_active_ases,
                                          sink_group_audio_locations,
                                          source_group_audio_locations, true)) {
          LOG(INFO) << __func__ << " Could not set source configuration of "
                    << stream_conf->conf->name;
          return;
        }
      }
    }

    groupStateMachine_->AttachToStream(group, leAudioDevice);
  }

@@ -2283,8 +2244,6 @@ class LeAudioClientImpl : public LeAudioClient {
  struct le_audio::stream_configuration* GetStreamConfigurationByDirection(
      LeAudioDeviceGroup* group, uint8_t direction) {
    struct le_audio::stream_configuration* stream_conf = &group->stream_conf;
    int num_of_devices = 0;
    int num_of_channels = 0;
    uint32_t sample_freq_hz = 0;
    uint32_t frame_duration_us = 0;
    uint32_t audio_channel_allocation = 0;
@@ -2300,17 +2259,11 @@ class LeAudioClientImpl : public LeAudioClient {
         device = group->GetNextActiveDevice(device)) {
      auto* ase = device->GetFirstActiveAseByDirection(direction);

      if (ase) {
        LOG(INFO) << __func__ << "device: " << device->address_;
        num_of_devices++;
      }

      for (; ase != nullptr;
           ase = device->GetNextActiveAseWithSameDirection(ase)) {
        streams.emplace_back(std::make_pair(
            ase->cis_conn_hdl, *ase->codec_config.audio_channel_allocation));
        audio_channel_allocation |= *ase->codec_config.audio_channel_allocation;
        num_of_channels += ase->codec_config.channel_count;
        if (sample_freq_hz == 0) {
          sample_freq_hz = ase->codec_config.GetSamplingFrequencyHz();
        } else {
@@ -2364,8 +2317,6 @@ class LeAudioClientImpl : public LeAudioClient {

    if (direction == le_audio::types::kLeAudioDirectionSource) {
      stream_conf->source_streams = std::move(streams);
      stream_conf->source_num_of_devices = num_of_devices;
      stream_conf->source_num_of_channels = num_of_channels;
      stream_conf->source_sample_frequency_hz = sample_freq_hz;
      stream_conf->source_frame_duration_us = frame_duration_us;
      stream_conf->source_audio_channel_allocation = audio_channel_allocation;
@@ -2374,8 +2325,6 @@ class LeAudioClientImpl : public LeAudioClient {
          codec_frames_blocks_per_sdu;
    } else if (direction == le_audio::types::kLeAudioDirectionSink) {
      stream_conf->sink_streams = std::move(streams);
      stream_conf->sink_num_of_devices = num_of_devices;
      stream_conf->sink_num_of_channels = num_of_channels;
      stream_conf->sink_sample_frequency_hz = sample_freq_hz;
      stream_conf->sink_frame_duration_us = frame_duration_us;
      stream_conf->sink_audio_channel_allocation = audio_channel_allocation;
@@ -2655,6 +2604,19 @@ class LeAudioClientImpl : public LeAudioClient {
      return false;
    }

    LOG_DEBUG("Sink stream config (#%d):\n",
              static_cast<int>(stream_conf->sink_streams.size()));
    for (auto stream : stream_conf->sink_streams) {
      LOG_DEBUG("Cis handle: 0x%02x, allocation 0x%04x\n", stream.first,
                stream.second);
    }
    LOG_DEBUG("Source stream config (#%d):\n",
              static_cast<int>(stream_conf->source_streams.size()));
    for (auto stream : stream_conf->source_streams) {
      LOG_DEBUG("Cis handle: 0x%02x, allocation 0x%04x\n", stream.first,
                stream.second);
    }

    uint16_t remote_delay_ms =
        group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink);
    if (CodecManager::GetInstance()->GetCodecLocation() ==
@@ -2829,7 +2791,7 @@ class LeAudioClientImpl : public LeAudioClient {
    dprintf(fd, "  ----------------\n ");
    dprintf(fd, "  LE Audio Groups:\n");
    aseGroups_.Dump(fd);
    dprintf(fd, "  Not grouped devices:\n");
    dprintf(fd, "\n  Not grouped devices:\n");
    leAudioDevices_.Dump(fd, bluetooth::groups::kGroupUnknown);
  }

+377 −15
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ using le_audio::types::AudioContexts;
using le_audio::types::AudioLocations;
using le_audio::types::AudioStreamDataPathState;
using le_audio::types::BidirectAsesPair;
using le_audio::types::CisType;
using le_audio::types::LeAudioCodecId;
using le_audio::types::LeAudioContextType;
using le_audio::types::LeAudioLc3Config;
@@ -105,6 +106,11 @@ int LeAudioDeviceGroup::NumOfConnected(types::LeAudioContextType context_type) {
      });
}

void LeAudioDeviceGroup::CigClearCis(void) {
  LOG_INFO("group_id: %d", group_id_);
  cises_.clear();
}

void LeAudioDeviceGroup::Cleanup(void) {
  /* Bluetooth is off while streaming - disconnect CISes and remove CIG */
  if (GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
@@ -140,6 +146,7 @@ void LeAudioDeviceGroup::Cleanup(void) {
   */

  leAudioDevices_.clear();
  this->CigClearCis();
}

void LeAudioDeviceGroup::Deactivate(void) {
@@ -152,12 +159,19 @@ void LeAudioDeviceGroup::Deactivate(void) {
  }
}

void LeAudioDeviceGroup::Activate(LeAudioContextType context_type) {
bool LeAudioDeviceGroup::Activate(LeAudioContextType context_type) {
  for (auto leAudioDevice : leAudioDevices_) {
    if (leAudioDevice.expired()) continue;

    leAudioDevice.lock()->ActivateConfiguredAses(context_type);
    bool activated = leAudioDevice.lock()->ActivateConfiguredAses(context_type);
    LOG_INFO("Device %s is activated now: ",
             leAudioDevice.lock().get()->address_.ToString().c_str());
    if (activated) {
      if (!CigAssignCisIds(leAudioDevice.lock().get())) return false;
    }
  }

  return true;
}

LeAudioDevice* LeAudioDeviceGroup::GetFirstDevice(void) {
@@ -299,6 +313,59 @@ LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDevice(
  return (iter == leAudioDevices_.end()) ? nullptr : (iter->lock()).get();
}

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

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

  if (iter == leAudioDevices_.end()) {
    return nullptr;
  }

  return iter->lock().get();
}

LeAudioDevice* LeAudioDeviceGroup::GetNextActiveDeviceByDataPathState(
    LeAudioDevice* leAudioDevice, AudioStreamDataPathState data_path_state) {
  auto iter = std::find_if(leAudioDevices_.begin(), leAudioDevices_.end(),
                           [&leAudioDevice](auto& d) {
                             if (d.expired()) {
                               return false;
                             }

                             return d.lock().get() == leAudioDevice;
                           });

  if (std::distance(iter, leAudioDevices_.end()) < 1) {
    return nullptr;
  }

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

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

  if (iter == leAudioDevices_.end()) {
    return nullptr;
  }

  return iter->lock().get();
}

bool LeAudioDeviceGroup::SetContextType(LeAudioContextType context_type) {
  /* XXX: group context policy ? / may it disallow to change type ?) */
  context_type_ = context_type;
@@ -761,6 +828,225 @@ uint8_t LeAudioDeviceGroup::GetFirstFreeCisId(void) {
  return kInvalidCisId;
}

uint8_t LeAudioDeviceGroup::GetFirstFreeCisId(CisType cis_type) {
  LOG_DEBUG("Group: %p, group_id: %d cis_type: %d", this, group_id_,
            static_cast<int>(cis_type));
  for (size_t id = 0; id < cises_.size(); id++) {
    if (cises_[id].addr.IsEmpty() && cises_[id].type == cis_type) {
      return id;
    }
  }
  return kInvalidCisId;
}

void LeAudioDeviceGroup::CigGenerateCisIds(
    types::LeAudioContextType context_type) {
  LOG_INFO("Group %p, group_id: %d, context_type: %s", this, group_id_,
           bluetooth::common::ToString(context_type).c_str());

  if (cises_.size() > 0) {
    LOG_INFO("CIS IDs already generated");
    return;
  }

  const set_configurations::AudioSetConfigurations* confs =
      AudioSetConfigurationProvider::Get()->GetConfigurations(context_type);

  uint8_t cis_count_bidir = 0;
  uint8_t cis_count_unidir_sink = 0;
  uint8_t cis_count_unidir_source = 0;
  get_cis_count(confs, &cis_count_bidir, &cis_count_unidir_sink,
                &cis_count_unidir_source);

  uint8_t idx = 0;
  while (cis_count_bidir > 0) {
    struct le_audio::types::cis cis_entry = {
        .id = idx,
        .addr = RawAddress::kEmpty,
        .type = CisType::CIS_TYPE_BIDIRECTIONAL,
        .conn_handle = 0,
    };

    cises_.push_back(cis_entry);
    cis_count_bidir--;
    idx++;
  }

  while (cis_count_unidir_sink > 0) {
    struct le_audio::types::cis cis_entry = {
        .id = idx,
        .addr = RawAddress::kEmpty,
        .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SINK,
        .conn_handle = 0,
    };
    cises_.push_back(cis_entry);
    cis_count_unidir_sink--;
    idx++;
  }

  while (cis_count_unidir_source > 0) {
    struct le_audio::types::cis cis_entry = {
        .id = idx,
        .addr = RawAddress::kEmpty,
        .type = CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE,
        .conn_handle = 0,
    };
    cises_.push_back(cis_entry);
    cis_count_unidir_source--;
    idx++;
  }
}

bool LeAudioDeviceGroup::CigAssignCisIds(LeAudioDevice* leAudioDevice) {
  ASSERT_LOG(leAudioDevice, "invalid device");
  LOG_INFO("device: %s", leAudioDevice->address_.ToString().c_str());

  struct ase* ase = leAudioDevice->GetFirstActiveAse();
  ASSERT_LOG(ase, " Shouldn't be called without an active ASE");

  for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) {
    uint8_t cis_id = kInvalidCisId;
    /* CIS ID already set */
    if (ase->cis_id != kInvalidCisId) {
      LOG_INFO("ASE ID: %d, is already assigned CIS ID: %d, type %d", ase->id,
               ase->cis_id, cises_[ase->cis_id].type);
      if (!cises_[ase->id].addr.IsEmpty()) {
        LOG_INFO("Bidirectional ASE already assigned");
        continue;
      }
      /* Reuse existing CIS ID if available*/
      cis_id = ase->cis_id;
    }

    /* First check if we have bidirectional ASEs. If so, assign same CIS ID.*/
    struct ase* matching_bidir_ase =
        leAudioDevice->GetNextActiveAseWithDifferentDirection(ase);

    if (matching_bidir_ase) {
      if (cis_id == kInvalidCisId) {
        cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
      }

      if (cis_id == kInvalidCisId) {
        LOG_ERROR(" Unable to get free Bi-Directional CIS ID");
        return false;
      }

      ase->cis_id = cis_id;
      matching_bidir_ase->cis_id = cis_id;
      cises_[cis_id].addr = leAudioDevice->address_;

      LOG_INFO(" ASE ID: %d and ASE ID: %d, assigned Bi-Directional CIS ID: %d",
               +ase->id, +matching_bidir_ase->id, +ase->cis_id);
      continue;
    }

    if (ase->direction == types::kLeAudioDirectionSink) {
      if (cis_id == kInvalidCisId) {
        cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SINK);
      }

      if (cis_id == kInvalidCisId) {
        LOG_ERROR(" Unable to get free Uni-Directional Sink CIS ID");
        return false;
      }

      ase->cis_id = cis_id;
      cises_[cis_id].addr = leAudioDevice->address_;
      LOG_INFO("ASE ID: %d, assigned Uni-Directional Sink CIS ID: %d", ase->id,
               ase->cis_id);
      continue;
    }

    /* Source direction */
    ASSERT_LOG(ase->direction == types::kLeAudioDirectionSource,
               "Expected Source direction, actual=%d", ase->direction);

    if (cis_id == kInvalidCisId) {
      cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_UNIDIRECTIONAL_SOURCE);
    }

    if (cis_id == kInvalidCisId) {
      LOG_ERROR("Unable to get free Uni-Directional Source CIS ID");
      return false;
    }

    ase->cis_id = cis_id;
    cises_[cis_id].addr = leAudioDevice->address_;
    LOG_INFO("ASE ID: %d, assigned Uni-Directional Source CIS ID: %d", ase->id,
             ase->cis_id);
  }

  return true;
}

void LeAudioDeviceGroup::CigAssignCisConnHandles(
    const std::vector<uint16_t>& conn_handles) {
  LOG_INFO("num of cis handles %d", static_cast<int>(conn_handles.size()));
  for (size_t i = 0; i < cises_.size(); i++) {
    cises_[i].conn_handle = conn_handles[i];
    LOG_INFO("assigning cis[%d] conn_handle: %d", cises_[i].id,
             cises_[i].conn_handle);
  }
}

void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses(
    LeAudioDevice* leAudioDevice) {
  ASSERT_LOG(leAudioDevice, "Invalid device");
  LOG_INFO("group: %p, group_id: %d, device: %s", this, group_id_,
           leAudioDevice->address_.ToString().c_str());

  /* Assign all CIS connection handles to ases */
  struct le_audio::types::ase* ase =
      leAudioDevice->GetFirstActiveAseByDataPathState(
          AudioStreamDataPathState::IDLE);
  if (!ase) {
    LOG_WARN("No active ASE with AudioStreamDataPathState IDLE");
    return;
  }

  for (; ase != nullptr; ase = leAudioDevice->GetFirstActiveAseByDataPathState(
                             AudioStreamDataPathState::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;
    }
    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;
    }
  }
}

void LeAudioDeviceGroup::CigAssignCisConnHandlesToAses(void) {
  LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
  ASSERT_LOG(leAudioDevice, "Shouldn't be called without an active device.");

  LOG_INFO("Group %p, group_id %d", this, group_id_);

  /* Assign all CIS connection handles to ases */
  for (; leAudioDevice != nullptr;
       leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
    CigAssignCisConnHandlesToAses(leAudioDevice);
  }
}

void LeAudioDeviceGroup::CigUnassignCis(LeAudioDevice* leAudioDevice) {
  ASSERT_LOG(leAudioDevice, "Invalid device");

  LOG_INFO("Group %p, group_id %d, device: %s", this, group_id_,
           leAudioDevice->address_.ToString().c_str());

  for (struct le_audio::types::cis& cis_entry : cises_) {
    if (cis_entry.addr == leAudioDevice->address_) {
      cis_entry.addr = RawAddress::kEmpty;
    }
  }
}

bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,
                              types::AudioLocations audio_locations,
                              uint8_t requested_channel_count,
@@ -1154,7 +1440,10 @@ bool LeAudioDeviceGroup::ConfigureAses(
         device != nullptr && required_device_cnt > 0;
         device = GetNextDeviceWithActiveContext(device, context_type)) {
      /* Skip if device has ASE configured in this direction already */
      if (device->GetFirstActiveAseByDirection(ent.direction)) continue;
      if (device->GetFirstActiveAseByDirection(ent.direction)) {
        required_device_cnt--;
        continue;
      }

      /* For the moment, we configure only connected devices. */
      if (device->conn_id_ == GATT_INVALID_CONN_ID) continue;
@@ -1270,6 +1559,26 @@ void LeAudioDeviceGroup::SetPendingConfiguration(void) {
  stream_conf.pending_configuration = true;
}

bool LeAudioDeviceGroup::IsConfigurationSupported(
    LeAudioDevice* leAudioDevice,
    const set_configurations::AudioSetConfiguration* audio_set_conf) {
  for (const auto& ent : (*audio_set_conf).confs) {
    LOG_INFO("Looking for requirements: %s - %s", audio_set_conf->name.c_str(),
             (ent.direction == 1 ? "snk" : "src"));
    auto pac = leAudioDevice->GetCodecConfigurationSupportedPac(ent.direction,
                                                                ent.codec);
    if (pac != nullptr) {
      LOG_INFO("Configuration is supported by device %s",
               leAudioDevice->address_.ToString().c_str());
      return true;
    }
  }

  LOG_INFO("Configuration is NOT supported by device %s",
           leAudioDevice->address_.ToString().c_str());
  return false;
}

const set_configurations::AudioSetConfiguration*
LeAudioDeviceGroup::FindFirstSupportedConfiguration(
    LeAudioContextType context_type) {
@@ -1362,11 +1671,22 @@ void LeAudioDeviceGroup::Dump(int fd) {
         << "      number of sources in the configuration "
         << stream_conf.source_num_of_devices << "\n"
         << "      number of source_streams connected: "
         << stream_conf.source_streams.size() << "\n";
         << stream_conf.source_streams.size() << "\n"
         << "      allocated CISes: " << static_cast<int>(cises_.size());

  if (cises_.size() > 0) {
    stream << "\n\t === CISes === ";
    for (auto cis : cises_) {
      stream << "\n\t cis id: " << static_cast<int>(cis.id)
             << ", type: " << static_cast<int>(cis.type)
             << ", conn_handle: " << static_cast<int>(cis.conn_handle)
             << ", addr: " << cis.addr;
    }
  }

  if (GetFirstActiveDevice() != nullptr) {
    uint32_t sink_delay;
    stream << "      presentation_delay for sink (speaker): ";
    stream << "\n      presentation_delay for sink (speaker): ";
    if (GetPresentationDelay(&sink_delay, le_audio::types::kLeAudioDirectionSink)) {
      stream << sink_delay << " us";
    }
@@ -1377,11 +1697,11 @@ void LeAudioDeviceGroup::Dump(int fd) {
    }
    stream << "\n";
  } else {
    stream << "      presentation_delay for sink (speaker):\n"
    stream << "\n      presentation_delay for sink (speaker):\n"
           << "      presentation_delay for source (microphone): \n";
  }

  stream << "      === devices: ===\n";
  stream << "      === devices: ===";

  dprintf(fd, "%s", stream.str().c_str());

@@ -1476,6 +1796,29 @@ struct ase* LeAudioDevice::GetNextActiveAseWithSameDirection(
  return (iter == ases_.end()) ? nullptr : &(*iter);
}

struct ase* LeAudioDevice::GetNextActiveAseWithDifferentDirection(
    struct ase* base_ase) {
  auto iter = std::find_if(ases_.begin(), ases_.end(),
                           [&base_ase](auto& ase) { return base_ase == &ase; });

  /* Invalid ase given */
  if (std::distance(iter, ases_.end()) < 1) {
    LOG_DEBUG("ASE %d does not use bidirectional CIS", base_ase->id);
    return nullptr;
  }

  iter =
      std::find_if(std::next(iter, 1), ases_.end(), [&iter](const auto& ase) {
        return ase.active && iter->direction != ase.direction;
      });

  if (iter == ases_.end()) {
    return nullptr;
  }

  return &(*iter);
}

struct ase* LeAudioDevice::GetFirstActiveAseByDataPathState(
    types::AudioStreamDataPathState state) {
  auto iter =
@@ -1771,18 +2114,30 @@ void LeAudioDevice::SetSupportedContexts(AudioContexts snk_contexts,
void LeAudioDevice::Dump(int fd) {
  std::stringstream stream;
  stream << std::boolalpha;
  stream << "\taddress: " << address_
  stream << "\n\taddress: " << address_
         << (conn_id_ == GATT_INVALID_CONN_ID ? "\n\t  Not connected "
                                              : "\n\t  Connected conn_id =")
         << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_))
         << "\n\t  set member: " << csis_member_
         << "\n\t  known_service_handles_: " << known_service_handles_
         << "\n\t  notify_connected_after_read_: " << notify_connected_after_read_
         << "\n\t  notify_connected_after_read_: "
         << notify_connected_after_read_
         << "\n\t  removing_device_: " << removing_device_
         << "\n\t  first_connection_: " << first_connection_
         << "\n\t  encrypted_: " << encrypted_
         << "\n\t  connecting_actively_: " << connecting_actively_
         << "\n";
         << "\n\t  number of ases_: " << static_cast<int>(ases_.size());

  if (ases_.size() > 0) {
    stream << "\n\t  == ASE == ";
    for (auto& ase : ases_) {
      stream << "\n\t  id: " << static_cast<int>(ase.id)
             << ", active: " << ase.active << ", direction: "
             << (ase.direction == types::kLeAudioDirectionSink ? "sink"
                                                               : "source")
             << ", allocated cis id: " << static_cast<int>(ase.cis_id);
    }
  }

  dprintf(fd, "%s", stream.str().c_str());
}
@@ -1823,21 +2178,28 @@ AudioContexts LeAudioDevice::SetAvailableContexts(AudioContexts snk_contexts,
  return updated_contexts;
}

void LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {
bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {
  if (conn_id_ == GATT_INVALID_CONN_ID) {
    LOG_DEBUG(" Device %s is not connected ", address_.ToString().c_str());
    return;
    LOG_WARN(" Device %s is not connected ", address_.ToString().c_str());
    return false;
  }

  LOG_DEBUG(" Configuring device %s", address_.ToString().c_str());
  bool ret = false;

  LOG_INFO(" Configuring device %s", address_.ToString().c_str());
  for (auto& ase : ases_) {
    if (!ase.active &&
        ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
        ase.configured_for_context_type == context_type) {
      LOG_DEBUG(" Ase id %d, cis id %d activated.", ase.id, ase.cis_id);
      LOG_INFO(
          " conn_id: %d, ase id %d, cis id %d, cis_handle 0x%04x is activated.",
          conn_id_, ase.id, ase.cis_id, ase.cis_conn_hdl);
      ase.active = true;
      ret = true;
    }
  }

  return ret;
}

void LeAudioDevice::DeactivateAllAses(void) {
+21 −2

File changed.

Preview size limit exceeded, changes collapsed.

+301 −31

File changed.

Preview size limit exceeded, changes collapsed.

+39 −0
Original line number Diff line number Diff line
@@ -69,6 +69,45 @@ static uint8_t min_req_devices_cnt(
  return curr_min_req_devices_cnt;
}

void get_cis_count(const AudioSetConfigurations* audio_set_confs,
                   uint8_t* cis_count_bidir, uint8_t* cis_count_unidir_sink,
                   uint8_t* cis_count_unidir_source) {
  for (auto audio_set_conf : *audio_set_confs) {
    std::pair<uint8_t /* sink */, uint8_t /* source */> snk_src_pair(0, 0);
    uint8_t bidir_count = 0;
    uint8_t unidir_sink_count = 0;
    uint8_t unidir_source_count = 0;

    for (auto ent : (*audio_set_conf).confs) {
      if (ent.direction == kLeAudioDirectionSink) {
        snk_src_pair.first += ent.device_cnt;
      }
      if (ent.direction == kLeAudioDirectionSource) {
        snk_src_pair.second += ent.device_cnt;
      }
    }

    bidir_count = std::min(snk_src_pair.first, snk_src_pair.second);
    unidir_sink_count = ((snk_src_pair.first - bidir_count) > 0)
                            ? (snk_src_pair.first - bidir_count)
                            : 0;
    unidir_source_count = ((snk_src_pair.second - bidir_count) > 0)
                              ? (snk_src_pair.second - bidir_count)
                              : 0;

    *cis_count_bidir = std::max(bidir_count, *cis_count_bidir);
    *cis_count_unidir_sink =
        std::max(unidir_sink_count, *cis_count_unidir_sink);
    *cis_count_unidir_source =
        std::max(unidir_source_count, *cis_count_unidir_source);
  }

  LOG_INFO(
      " Maximum CIS count, Bi-Directional: %d,"
      " Uni-Directional Sink: %d, Uni-Directional Source: %d",
      *cis_count_bidir, *cis_count_unidir_sink, *cis_count_unidir_source);
}

bool check_if_may_cover_scenario(const AudioSetConfigurations* audio_set_confs,
                                 uint8_t group_size) {
  if (!audio_set_confs) {
Loading