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

Commit aa5e47af authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Fix handling invalid offloader behaviour

This fix handles scenario when offloader calles Resume while it was
already called.

BT stack in such case cleares audio_sender_state and
audio_receiver_state and should not continue with setting up stream when
state machine gets there.

Bug: 297846817
Test: atest bluetooth_le_audio_test
Tag: #feature
Change-Id: If113e23c9383e10c59fc4c409e3d3a12b2e35804
parent 2dcade2c
Loading
Loading
Loading
Loading
+41 −25
Original line number Original line Diff line number Diff line
@@ -5121,15 +5121,42 @@ class LeAudioClientImpl : public LeAudioClient {
        bluetooth::common::ToString(audio_receiver_state_).c_str());
        bluetooth::common::ToString(audio_receiver_state_).c_str());
    LeAudioDeviceGroup* group = aseGroups_.FindById(group_id);
    LeAudioDeviceGroup* group = aseGroups_.FindById(group_id);
    switch (status) {
    switch (status) {
      case GroupStreamStatus::STREAMING:
      case GroupStreamStatus::STREAMING: {
        ASSERT_LOG(group_id == active_group_id_, "invalid group id %d!=%d",
        ASSERT_LOG(group_id == active_group_id_, "invalid group id %d!=%d",
                   group_id, active_group_id_);
                   group_id, active_group_id_);


        take_stream_time();

        le_audio::MetricsCollector::Get()->OnStreamStarted(
            active_group_id_, configuration_context_type_);

        if (leAudioHealthStatus_) {
          leAudioHealthStatus_->AddStatisticForGroup(
              group_id, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS);
        }

        if (!group) {
          LOG_ERROR("Group %d does not exist anymore. This shall not happen ",
                    group_id);
          return;
        }

        if ((audio_sender_state_ == AudioState::IDLE) &&
            (audio_receiver_state_ == AudioState::IDLE)) {
          /* Audio Framework is not interested in the stream anymore.
           * Just stop streaming
           */
          LOG_WARN("Stopping stream for group %d as AF not interested.",
                   group_id);
          groupStateMachine_->StopStream(group);
          return;
        }

        /* It might happen that the configuration has already changed, while
        /* It might happen that the configuration has already changed, while
         * the group was in the ongoing reconfiguration. We should stop the
         * the group was in the ongoing reconfiguration. We should stop the
         * stream and reconfigure once again.
         * stream and reconfigure once again.
         */
         */
        if (group && group->GetConfigurationContextType() !=
        if (group->GetConfigurationContextType() !=
            configuration_context_type_) {
            configuration_context_type_) {
          LOG_DEBUG(
          LOG_DEBUG(
              "The configuration %s is no longer valid. Stopping the stream to"
              "The configuration %s is no longer valid. Stopping the stream to"
@@ -5143,7 +5170,6 @@ class LeAudioClientImpl : public LeAudioClient {
          return;
          return;
        }
        }


        if (group) {
        BidirectionalPair<uint16_t> delays_pair = {
        BidirectionalPair<uint16_t> delays_pair = {
            .sink =
            .sink =
                group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink),
                group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink),
@@ -5154,24 +5180,14 @@ class LeAudioClientImpl : public LeAudioClient {
            std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal,
            std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal,
                      weak_factory_.GetWeakPtr(), std::placeholders::_1,
                      weak_factory_.GetWeakPtr(), std::placeholders::_1,
                      std::placeholders::_2));
                      std::placeholders::_2));
        }


        if (audio_sender_state_ == AudioState::READY_TO_START)
        if (audio_sender_state_ == AudioState::READY_TO_START)
          StartSendingAudio(group_id);
          StartSendingAudio(group_id);
        if (audio_receiver_state_ == AudioState::READY_TO_START)
        if (audio_receiver_state_ == AudioState::READY_TO_START)
          StartReceivingAudio(group_id);
          StartReceivingAudio(group_id);


        take_stream_time();

        le_audio::MetricsCollector::Get()->OnStreamStarted(
            active_group_id_, configuration_context_type_);

        if (leAudioHealthStatus_) {
          leAudioHealthStatus_->AddStatisticForGroup(
              group_id, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS);
        }

        break;
        break;
      }
      case GroupStreamStatus::SUSPENDED:
      case GroupStreamStatus::SUSPENDED:
        stream_setup_end_timestamp_ = 0;
        stream_setup_end_timestamp_ = 0;
        stream_setup_start_timestamp_ = 0;
        stream_setup_start_timestamp_ = 0;
+76 −1
Original line number Original line Diff line number Diff line
@@ -1111,6 +1111,8 @@ class UnicastTestNoInit : public Test {
          /* Assume CIG is created */
          /* Assume CIG is created */
          group->cig_state_ = le_audio::types::CigState::CREATED;
          group->cig_state_ = le_audio::types::CigState::CREATED;


          if (block_streaming_state_callback) return true;

          do_in_main_thread(
          do_in_main_thread(
              FROM_HERE, base::BindOnce(
              FROM_HERE, base::BindOnce(
                             [](int group_id,
                             [](int group_id,
@@ -1412,10 +1414,13 @@ class UnicastTestNoInit : public Test {
    SetUpMockGatt();
    SetUpMockGatt();
    SetUpMockCodecManager(codec_location);
    SetUpMockCodecManager(codec_location);


    block_streaming_state_callback = false;

    available_snk_context_types_ = 0xffff;
    available_snk_context_types_ = 0xffff;
    available_src_context_types_ = 0xffff;
    available_src_context_types_ = 0xffff;
    supported_snk_context_types_ = 0xffff;
    supported_snk_context_types_ = 0xffff;
    supported_src_context_types_ = 0xffff;
    supported_src_context_types_ = 0xffff;

    le_audio::AudioSetConfigurationProvider::Initialize(codec_location);
    le_audio::AudioSetConfigurationProvider::Initialize(codec_location);
    ASSERT_FALSE(LeAudioClient::IsLeAudioClientRunning());
    ASSERT_FALSE(LeAudioClient::IsLeAudioClientRunning());
  }
  }
@@ -1809,12 +1814,19 @@ class UnicastTestNoInit : public Test {
    SyncOnMainLoop();
    SyncOnMainLoop();
  }
  }


  void LocalAudioSourceResume(bool expected_confirmation = true) {
  void LocalAudioSourceResume(bool expected_confirmation = true,
                              bool expected_cancel = false) {
    ASSERT_NE(nullptr, mock_le_audio_source_hal_client_);
    ASSERT_NE(nullptr, mock_le_audio_source_hal_client_);
    if (expected_confirmation) {
    if (expected_confirmation) {
      EXPECT_CALL(*mock_le_audio_source_hal_client_, ConfirmStreamingRequest())
      EXPECT_CALL(*mock_le_audio_source_hal_client_, ConfirmStreamingRequest())
          .Times(1);
          .Times(1);
    }
    }

    if (expected_cancel) {
      EXPECT_CALL(*mock_le_audio_source_hal_client_, CancelStreamingRequest())
          .Times(1);
    }

    do_in_main_thread(FROM_HERE,
    do_in_main_thread(FROM_HERE,
                      base::BindOnce(
                      base::BindOnce(
                          [](LeAudioSourceAudioHalClient::Callbacks* cb) {
                          [](LeAudioSourceAudioHalClient::Callbacks* cb) {
@@ -2512,6 +2524,7 @@ class UnicastTestNoInit : public Test {
  uint16_t global_conn_id = 1;
  uint16_t global_conn_id = 1;
  le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_;
  le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_;
  std::map<int, LeAudioDeviceGroup*> streaming_groups;
  std::map<int, LeAudioDeviceGroup*> streaming_groups;
  bool block_streaming_state_callback = false;


  bluetooth::hci::IsoManager* iso_manager_;
  bluetooth::hci::IsoManager* iso_manager_;
  MockIsoManager* mock_iso_manager_;
  MockIsoManager* mock_iso_manager_;
@@ -3713,6 +3726,68 @@ TEST_F(UnicastTest, GroupingAddRemove) {
  ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end());
  ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end());
}
}


TEST_F(UnicastTest, DoubleResumeFromAF) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;

  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);

  constexpr int gmcs_ccid = 1;
  constexpr int gtbs_ccid = 2;

  // Audio sessions are started only when device gets active
  EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
  EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
  LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */);
  LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */);
  LeAudioClient::Get()->GroupSetActive(group_id);
  SyncOnMainLoop();

  types::BidirectionalPair<std::vector<uint8_t>> ccids = {.sink = {gmcs_ccid},
                                                          .source = {}};
  EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1);

  block_streaming_state_callback = true;

  UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC);
  LocalAudioSourceResume(false);

  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_);

  LocalAudioSourceResume(false, true);

  EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1);

  do_in_main_thread(
      FROM_HERE,
      base::BindOnce(
          [](int group_id, le_audio::LeAudioGroupStateMachine::Callbacks*
                               state_machine_callbacks) {
            state_machine_callbacks->StatusReportCb(
                group_id, GroupStreamStatus::STREAMING);
          },
          group_id, base::Unretained(state_machine_callbacks_)));
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_state_machine_);
}

TEST_F(UnicastTest, RemoveNodeWhileStreaming) {
TEST_F(UnicastTest, RemoveNodeWhileStreaming) {
  const RawAddress test_address0 = GetTestAddress(0);
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
  int group_id = bluetooth::groups::kGroupUnknown;