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

Commit a01b370f authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "le_audio: Handle late CIS connection event for joining device" am:...

Merge "le_audio: Handle late CIS connection event for joining device" am: 8ee4647c am: 6da43115 am: 02f1fd5c am: 786fbbe4

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/2523745



Change-Id: I1095e913c67237a9772766694d40777382c11e0d
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 0fdafb90 786fbbe4
Loading
Loading
Loading
Loading
+12 −2
Original line number Original line Diff line number Diff line
@@ -806,7 +806,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    /* Cis establishment may came after setting group state to streaming, e.g.
    /* Cis establishment may came after setting group state to streaming, e.g.
     * for autonomous scenario when ase is sink */
     * for autonomous scenario when ase is sink */
    if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
    if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
        group->IsGroupStreamReady()) {
        group->GetFirstActiveDeviceByDataPathState(
            AudioStreamDataPathState::CIS_ESTABLISHED)) {
      /* No more transition for group */
      /* No more transition for group */
      cancel_watchdog_if_needed(group->group_id_);
      cancel_watchdog_if_needed(group->group_id_);
      PrepareDataPath(group);
      PrepareDataPath(group);
@@ -2609,8 +2610,17 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
          return;
          return;
        }
        }


        /* This case may happen because of the reconnection device. */
        if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
        if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
          /* We are here because of the reconnection of the single device. */
          /* Not all CISes establish evens came */
          if (group->GetFirstActiveDeviceByDataPathState(
                  AudioStreamDataPathState::CIS_PENDING))
            return;

          /* Streaming status notification came after setting data path */
          if (!group->GetFirstActiveDeviceByDataPathState(
                  AudioStreamDataPathState::CIS_ESTABLISHED))
            return;
          PrepareDataPath(group);
          PrepareDataPath(group);
          return;
          return;
        }
        }
+120 −0
Original line number Original line Diff line number Diff line
@@ -177,6 +177,7 @@ class StateMachineTest : public Test {


  /* Use to simulated error status on Cis creation */
  /* Use to simulated error status on Cis creation */
  bool overwrite_cis_status_;
  bool overwrite_cis_status_;
  bool do_not_send_cis_establish_event_;
  uint8_t overwrite_cis_status_idx_;
  uint8_t overwrite_cis_status_idx_;
  std::vector<uint8_t> cis_status_;
  std::vector<uint8_t> cis_status_;


@@ -190,6 +191,7 @@ class StateMachineTest : public Test {


    overwrite_cis_status_idx_ = 0;
    overwrite_cis_status_idx_ = 0;
    overwrite_cis_status_ = false;
    overwrite_cis_status_ = false;
    do_not_send_cis_establish_event_ = false;
    cis_status_.clear();
    cis_status_.clear();


    ::le_audio::AudioSetConfigurationProvider::Initialize();
    ::le_audio::AudioSetConfigurationProvider::Initialize();
@@ -362,6 +364,11 @@ class StateMachineTest : public Test {
                                  conn_params) {
                                  conn_params) {
          DLOG(INFO) << "EstablishCis";
          DLOG(INFO) << "EstablishCis";


          if (do_not_send_cis_establish_event_) {
            DLOG(INFO) << "Don't send cis establish event";
            return;
          }

          for (auto& pair : conn_params.conn_pairs) {
          for (auto& pair : conn_params.conn_pairs) {
            auto dev_it = std::find_if(
            auto dev_it = std::find_if(
                le_audio_devices_.begin(), le_audio_devices_.end(),
                le_audio_devices_.begin(), le_audio_devices_.end(),
@@ -4348,5 +4355,118 @@ TEST_F(StateMachineTest, StreamStartWithDifferentContextFromConfiguredState) {


  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
}
}

TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) {
  const auto context_type = kContextTypeMedia;
  const auto leaudio_group_id = 6;
  const auto num_devices = 2;

  ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);

  // Prepare multiple fake connected devices in a group
  auto* group =
      PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
  ASSERT_EQ(group->Size(), num_devices);

  PrepareConfigureCodecHandler(group);
  PrepareConfigureQosHandler(group);
  PrepareEnableHandler(group);
  PrepareDisableHandler(group);
  PrepareReleaseHandler(group);

  auto* leAudioDevice = group->GetFirstDevice();
  LeAudioDevice* lastDevice;
  LeAudioDevice* fistDevice = leAudioDevice;

  auto expected_devices_written = 0;
  while (leAudioDevice) {
    /* Three Writes:
     * 1: Codec Config
     * 2: Codec QoS
     * 3: Enabling
     */
    lastDevice = leAudioDevice;
    EXPECT_CALL(gatt_queue,
                WriteCharacteristic(leAudioDevice->conn_id_,
                                    leAudioDevice->ctp_hdls_.val_hdl, _,
                                    GATT_WRITE_NO_RSP, _, _))
        .Times(AtLeast(3));
    expected_devices_written++;
    leAudioDevice = group->GetNextDevice(leAudioDevice);
  }
  ASSERT_EQ(expected_devices_written, num_devices);

  EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);

  InjectInitialIdleNotification(group);

  // Start the configuration and stream Media content
  LeAudioGroupStateMachine::Get()->StartStream(
      group, context_type,
      {.sink = types::AudioContexts(context_type),
       .source = types::AudioContexts(context_type)});

  // Check if group has transitioned to a proper state
  ASSERT_EQ(group->GetState(),
            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
  testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);

  // Inject CIS and ACL disconnection of first device
  InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
  InjectAclDisconnected(group, lastDevice);

  // Check if group keeps streaming
  ASSERT_EQ(group->GetState(),
            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);

  lastDevice->conn_id_ = 3;
  lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);

  group->UpdateAudioContextTypeAvailability();

  // Make sure ASE with disconnected CIS are not left in STREAMING
  ASSERT_EQ(lastDevice->GetFirstAseWithState(
                ::le_audio::types::kLeAudioDirectionSink,
                types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
            nullptr);
  ASSERT_EQ(lastDevice->GetFirstAseWithState(
                ::le_audio::types::kLeAudioDirectionSource,
                types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
            nullptr);

  EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
                                              lastDevice->ctp_hdls_.val_hdl, _,
                                              GATT_WRITE_NO_RSP, _, _))
      .Times(AtLeast(3));

  do_not_send_cis_establish_event_ = true;

  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
  LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice);

  // Check if group keeps streaming
  ASSERT_EQ(group->GetState(),
            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);

  // Verify that the joining device receives the right CCID list
  auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
  bool parsedOk = false;
  auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(),
                                                   lastMeta.size(), parsedOk);
  ASSERT_TRUE(parsedOk);

  auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList);
  ASSERT_TRUE(ccids.has_value());
  ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());

  /* Verify that ASE of first device are still good*/
  auto ase = fistDevice->GetFirstActiveAse();
  ASSERT_NE(ase->max_transport_latency, 0);
  ASSERT_NE(ase->retrans_nb, 0);
}

}  // namespace internal
}  // namespace internal
}  // namespace le_audio
}  // namespace le_audio