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

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

Merge "leaudio: Fix invalid state machine timeout" into main am: 283ddc9e

parents 5d0a61f6 283ddc9e
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -955,17 +955,6 @@ public:
      return;
    }

    if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {
      if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {
        log::warn("group {} was about to stream, but got canceled: {}", group_id,
                  ToString(group->GetTargetState()));
        group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
      } else {
        log::warn(", group {} already stopped: {}", group_id, ToString(group->GetState()));
      }
      return;
    }

    groupStateMachine_->StopStream(group);
  }

+9 −2
Original line number Diff line number Diff line
@@ -1065,8 +1065,15 @@ bool LeAudioDeviceGroup::IsStreaming(void) const {
}

bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const {
  return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) ||
         (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
  /* If target state is IDLE then for sure group is either releasing or idle.
   * Otherwise, we have "idle states" - Idle or Configured when caching is
   * supported on the remote side. In both cases to check it is to make sure
   * group is not in transition.
   */
  return target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE ||
         ((current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE ||
           current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) &&
          !in_transition_);
}

bool LeAudioDeviceGroup::IsGroupStreamReady(void) const {
+51 −0
Original line number Diff line number Diff line
@@ -1191,6 +1191,11 @@ protected:
              // Inject the state
              group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
              if (block_qos_config) {
                return true;
              }
              group->SetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
              streaming_groups[group->group_id_] = group;
@@ -1432,6 +1437,7 @@ protected:
    SetUpMockCodecManager(codec_location);
    block_streaming_state_callback = false;
    block_qos_config = false;
    available_snk_context_types_ = 0xffff;
    available_src_context_types_ = 0xffff;
@@ -2654,6 +2660,7 @@ protected:
  bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_;
  std::map<int, LeAudioDeviceGroup*> streaming_groups;
  bool block_streaming_state_callback = false;
  bool block_qos_config = false;
  bool attach_to_stream_scheduled = false;
@@ -4788,6 +4795,50 @@ TEST_F(UnicastTest, GroupSetActive_SourcePacksEmpty) {
  Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
}
TEST_F(UnicastTest, GroupSetActive_and_InactiveDuringStreamConfiguration) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
  empty_source_pack_ = true;
  /**
   * In this test we want to make sure that StopStream is called when group is set to inactive
   * while being between IDLE and CONFIGURED state
   */
  default_channel_cnt = 1;
  SetSampleDatabaseEarbudsValid(
          1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
          codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004,
          /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/,
          default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, 0 /*rank*/);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
          .Times(1);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
          .WillOnce(DoAll(SaveArg<1>(&group_id)));
  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);
  EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1);
  block_qos_config = true;
  LeAudioClient::Get()->GroupSetActive(group_id);
  StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, AUDIO_SOURCE_INVALID, false,
                 false);
  SyncOnMainLoop();
  EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1);
  LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown);
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_state_machine_);
}
TEST_F(UnicastTest, ChangeAvailableContextTypeWhenInCodecConfigured) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
+2 −1
Original line number Diff line number Diff line
@@ -314,7 +314,8 @@ public:

  void StopStream(LeAudioDeviceGroup* group) override {
    if (group->IsReleasingOrIdle()) {
      log::info("group: {} already in releasing process", group->group_id_);
      log::info("group: {} in_transition: {}, current_state {}", group->group_id_,
                group->IsInTransition(), ToString(group->GetState()));
      return;
    }

+55 −0
Original line number Diff line number Diff line
@@ -8474,5 +8474,60 @@ TEST_F(StateMachineTest, testAutonomousDisable_GoToIdle) {
  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
}

TEST_F(StateMachineTest, testStopStreamBeforeCodecConfigureIsArrived) {
  /* Device is banded headphones with 1x snk + 0x src ase
   * (1xunidirectional CIS with channel count 2 for stereo)
   */
  const auto context_type = kContextTypeRingtone;
  const int leaudio_group_id = 4;
  channel_count_ = kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel;

  // Prepare fake connected device group
  auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);

  auto* leAudioDevice = group->GetFirstDevice();

  /*
   * 1 - Configure ASE
   * 2 - Release ASE
   */
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _))
          .Times(2);

  EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0);
  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
  EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);

  InjectInitialIdleNotification(group);

  // Validate GroupStreamStatus
  EXPECT_CALL(mock_callbacks_,
              StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING));
  EXPECT_CALL(mock_callbacks_,
              StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::IDLE));

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

  // Stop the stream before Codec Configured arrived
  LeAudioGroupStateMachine::Get()->StopStream(group);

  testing::Mock::VerifyAndClearExpectations(&gatt_queue);

  InjectCachedConfigurationForActiveAses(group, leAudioDevice);
  InjectReleaseAndIdleStateForAGroup(group);

  // Check if group has transitioned to a proper state
  ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
  ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
}

}  // namespace internal
}  // namespace bluetooth::le_audio