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

Commit 94ebd4ec authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "broadcaster: Handle suspend request before controller setup" into main

parents bf5a39fb 9f1832e4
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -1307,6 +1307,13 @@ private:
      if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
      if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) {
        instance->UpdateAudioActiveStateInPublicAnnouncement();
        instance->UpdateAudioActiveStateInPublicAnnouncement();
        instance->setBroadcastTimers();
        instance->setBroadcastTimers();

        for (auto& broadcast_pair : instance->broadcasts_) {
          auto& broadcast = broadcast_pair.second;
          if (broadcast->GetState() == BroadcastStateMachine::State::CONFIGURED) {
            broadcast->ProcessMessage(BroadcastStateMachine::Message::SUSPEND, nullptr);
          }
        }
      }
      }
    }
    }


+72 −0
Original line number Original line Diff line number Diff line
@@ -65,6 +65,7 @@ using bluetooth::le_audio::DsaMode;
using bluetooth::le_audio::LeAudioCodecConfiguration;
using bluetooth::le_audio::LeAudioCodecConfiguration;
using bluetooth::le_audio::LeAudioSourceAudioHalClient;
using bluetooth::le_audio::LeAudioSourceAudioHalClient;
using bluetooth::le_audio::broadcaster::BigConfig;
using bluetooth::le_audio::broadcaster::BigConfig;
using bluetooth::le_audio::broadcaster::BroadcastStateMachine;
using bluetooth::le_audio::broadcaster::BroadcastSubgroupCodecConfig;
using bluetooth::le_audio::broadcaster::BroadcastSubgroupCodecConfig;


// Disables most likely false-positives from base::SplitString()
// Disables most likely false-positives from base::SplitString()
@@ -1423,6 +1424,77 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) {
  ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr);
}
}


TEST_F(BroadcasterTest, AudioSuspendBeforeBigCreateCallback) {
  com::android::bluetooth::flags::provider_->leaudio_big_depends_on_audio_state(true);

  // Timers created
  ASSERT_TRUE(big_terminate_timer_ != nullptr);
  ASSERT_TRUE(broadcast_stop_timer_ != nullptr);

  auto broadcast_id = InstantiateBroadcast();
  LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
  EXPECT_CALL(*mock_audio_source_, Start)
          .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)))
          .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_broadcaster_callbacks_,
              OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING))
          .Times(1);
  // Timers not started
  ASSERT_TRUE(big_terminate_timer_->cb == nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr);

  // Start Broadcast
  LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
  // Timers started
  ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop"));
  ASSERT_TRUE(big_terminate_timer_->cb != nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr);
  ASSERT_NE(audio_receiver, nullptr);

  // First onAudioResume when BIG already created, not cause any state change
  EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0);
  audio_receiver->OnAudioResume();
  // Timers cancelled
  ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
  ASSERT_TRUE(big_terminate_timer_->cb == nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr);

  audio_receiver->OnAudioSuspend();
  ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop"));
  ASSERT_TRUE(big_terminate_timer_->cb != nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr);

  // BIG termination timer execution, state machine go to CONFIGURED state so BIG terminated
  EXPECT_CALL(mock_broadcaster_callbacks_,
              OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED))
          .Times(1);
  // Imitate execution of BIG termination timer
  big_terminate_timer_->cb(big_terminate_timer_->data);

  auto mock_state_machine = MockBroadcastStateMachine::GetLastInstance();
  /* Prepare method that would not proceed BIG created event */
  EXPECT_CALL(*mock_state_machine, ProcessMessage(BroadcastStateMachine::Message::START, _))
          .WillOnce(Return());

  // onAudioResume cause state machine go to STREAMING state so BIG creation
  EXPECT_CALL(mock_broadcaster_callbacks_,
              OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING))
          .Times(0);
  audio_receiver->OnAudioResume();
  // Timers Cancelled
  ASSERT_EQ(4, get_func_call_count("alarm_cancel"));
  ASSERT_TRUE(big_terminate_timer_->cb == nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr);

  // OnAudioSuspend cause starting the BIG termination timer
  EXPECT_CALL(*mock_state_machine, ProcessMessage(BroadcastStateMachine::Message::SUSPEND, _))
          .WillOnce(Return());
  audio_receiver->OnAudioSuspend();
  ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop"));
  ASSERT_TRUE(big_terminate_timer_->cb != nullptr);
  ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr);
}

// TODO: Add tests for:
// TODO: Add tests for:
// ToRawPacket(BasicAudioAnnouncementData const& in, std::vector<uint8_t>& data)
// ToRawPacket(BasicAudioAnnouncementData const& in, std::vector<uint8_t>& data)


+16 −3
Original line number Original line Diff line number Diff line
@@ -282,7 +282,14 @@ private:
          /* in CONFIGURING state */
          /* in CONFIGURING state */
          [](const void*) { /* Do nothing */ },
          [](const void*) { /* Do nothing */ },
          /* in CONFIGURED state */
          /* in CONFIGURED state */
          [](const void*) { /* Already suspended */ },
          [this](const void*) {
            suspending_ = true;

            /* Terminate BIG if suspend happens before setting STREAMING state */
            if (active_config_ != std::nullopt) {
              TerminateBig();
            }
          },
          /* in STOPPING state */
          /* in STOPPING state */
          [](const void*) { /* Do nothing */ },
          [](const void*) { /* Do nothing */ },
          /* in STREAMING state */
          /* in STREAMING state */
@@ -530,8 +537,14 @@ private:
                  .iso_interval = evt->iso_interval,
                  .iso_interval = evt->iso_interval,
                  .connection_handles = evt->conn_handles,
                  .connection_handles = evt->conn_handles,
          };
          };

          if (suspending_) {
            log::info("Terminating BIG due to stream suspending, big_id={}", evt->big_id);
            TerminateBig();
          } else {
            callbacks_->OnBigCreated(evt->conn_handles);
            callbacks_->OnBigCreated(evt->conn_handles);
            TriggerIsoDatapathSetup(evt->conn_handles[0]);
            TriggerIsoDatapathSetup(evt->conn_handles[0]);
          }
        } else {
        } else {
          log::error("State={} Event={}. Unable to create big, big_id={}, status={}",
          log::error("State={} Event={}. Unable to create big, big_id={}, status={}",
                     ToString(GetState()), event, evt->big_id, evt->status);
                     ToString(GetState()), event, evt->big_id, evt->status);
+51 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ using bluetooth::hci::IsoManager;
using bluetooth::le_audio::BasicAudioAnnouncementData;
using bluetooth::le_audio::BasicAudioAnnouncementData;
using testing::_;
using testing::_;
using testing::Mock;
using testing::Mock;
using testing::Return;
using testing::SaveArg;
using testing::SaveArg;
using testing::Test;
using testing::Test;


@@ -644,6 +645,56 @@ TEST_F(StateMachineTest, ProcessMessageSuspendWhenConfigured) {
  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);
  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);
}
}


TEST_F(StateMachineTest, ProcessMessageSuspendWhenConfiguredLateBigCreateCompleteEvent) {
  EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)).Times(1);

  auto broadcast_id =
          InstantiateStateMachine(bluetooth::le_audio::types::LeAudioContextType::MEDIA);
  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);

  /* Hold start process on BIG create */
  EXPECT_CALL(*mock_iso_manager_, CreateBig(_, _)).WillOnce(Return());
  broadcasts_[broadcast_id]->ProcessMessage(BroadcastStateMachine::Message::START);

  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);

  EXPECT_CALL(*mock_iso_manager_, TerminateBig(_, _)).Times(1);
  broadcasts_[broadcast_id]->ProcessMessage(BroadcastStateMachine::Message::SUSPEND);

  /* Inject late BIG create complete event */
  big_create_cmpl_evt evt;
  evt.big_id = broadcasts_[broadcast_id]->GetAdvertisingSid();
  broadcasts_[broadcast_id]->HandleHciEvent(HCI_BLE_CREATE_BIG_CPL_EVT, &evt);

  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0);
  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0);
  EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(broadcast_id, _, _)).Times(0);
  // There shall be no change in state
  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);
}

TEST_F(StateMachineTest, ProcessMessageSuspendWhenConfiguredLateIsoDataPathSetUp) {
  EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineCreateStatus(_, true)).Times(1);

  auto broadcast_id =
          InstantiateStateMachine(bluetooth::le_audio::types::LeAudioContextType::MEDIA);
  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);

  /* Hold start process on Setup Iso Data Path BIG create */
  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).WillOnce(Return());
  broadcasts_[broadcast_id]->ProcessMessage(BroadcastStateMachine::Message::START);

  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);

  EXPECT_CALL(*mock_iso_manager_, TerminateBig(_, _)).Times(1);
  broadcasts_[broadcast_id]->ProcessMessage(BroadcastStateMachine::Message::SUSPEND);

  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath).Times(0);
  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath).Times(0);
  EXPECT_CALL(*(sm_callbacks_.get()), OnStateMachineEvent(broadcast_id, _, _)).Times(0);
  // There shall be no change in state
  ASSERT_EQ(broadcasts_[broadcast_id]->GetState(), BroadcastStateMachine::State::CONFIGURED);
}
TEST_F(StateMachineTest, ProcessMessageStartWhenStreaming) {
TEST_F(StateMachineTest, ProcessMessageStartWhenStreaming) {
  auto broadcast_id =
  auto broadcast_id =
          InstantiateStateMachine(bluetooth::le_audio::types::LeAudioContextType::MEDIA);
          InstantiateStateMachine(bluetooth::le_audio::types::LeAudioContextType::MEDIA);