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

Commit 0ca5d01b authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Fix double iso data path removal

When phone call ends and Sink ASE and Sink Source goes to Releasing
state, Host will remove data path. This patch makes sure it is sent only
once.

Bug: 290801282
Test: atest --host bluetooth_le_audio_test
Test: atest BluetoothInstrumentationTests
Tag: #feature
Change-Id: If261faea30a19c425ca0dea6932e5c889c6132a0
parent 9ee9098a
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -787,9 +787,13 @@ uint32_t AdjustAllocationForOffloader(uint32_t allocation) {
namespace types {
std::ostream& operator<<(std::ostream& os,
                         const AudioStreamDataPathState& state) {
  static const char* char_value_[6] = {
      "IDLE",        "CIS_DISCONNECTING", "CIS_ASSIGNED",
      "CIS_PENDING", "CIS_ESTABLISHED",   "DATA_PATH_ESTABLISHED"};
  static const char* char_value_[7] = {"IDLE",
                                       "CIS_DISCONNECTING",
                                       "CIS_ASSIGNED",
                                       "CIS_PENDING",
                                       "CIS_ESTABLISHED",
                                       "DATA_PATH_ESTABLISHED",
                                       "DATA_PATH_REMOVING"};

  os << char_value_[static_cast<uint8_t>(state)] << " ("
     << "0x" << std::setfill('0') << std::setw(2) << static_cast<int>(state)
+1 −0
Original line number Diff line number Diff line
@@ -350,6 +350,7 @@ enum class AudioStreamDataPathState {
  CIS_PENDING,
  CIS_ESTABLISHED,
  DATA_PATH_ESTABLISHED,
  DATA_PATH_REMOVING,
};

enum class CisType {
+7 −4
Original line number Diff line number Diff line
@@ -568,15 +568,14 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {

    auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(conn_hdl);
    if (ases_pair.sink && (ases_pair.sink->data_path_state ==
                           AudioStreamDataPathState::DATA_PATH_ESTABLISHED)) {
                           AudioStreamDataPathState::DATA_PATH_REMOVING)) {
      ases_pair.sink->data_path_state =
          AudioStreamDataPathState::CIS_DISCONNECTING;
      do_disconnect = true;
    }

    if (ases_pair.source &&
        ases_pair.source->data_path_state ==
            AudioStreamDataPathState::DATA_PATH_ESTABLISHED) {
    if (ases_pair.source && ases_pair.source->data_path_state ==
                                AudioStreamDataPathState::DATA_PATH_REMOVING) {
      ases_pair.source->data_path_state =
          AudioStreamDataPathState::CIS_DISCONNECTING;
      do_disconnect = true;
@@ -862,12 +861,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    if (ases_pair.sink && ases_pair.sink->data_path_state ==
                              AudioStreamDataPathState::DATA_PATH_ESTABLISHED) {
      value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
      ases_pair.sink->data_path_state =
          AudioStreamDataPathState::DATA_PATH_REMOVING;
    }

    if (ases_pair.source &&
        ases_pair.source->data_path_state ==
            AudioStreamDataPathState::DATA_PATH_ESTABLISHED) {
      value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput;
      ases_pair.source->data_path_state =
          AudioStreamDataPathState::DATA_PATH_REMOVING;
    }

    if (value == 0) {
+70 −0
Original line number Diff line number Diff line
@@ -4538,6 +4538,76 @@ TEST_F(StateMachineTest, StreamClearAfterReleaseAndConnectionTimeout) {
  testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
}

TEST_F(StateMachineTest, VerifyThereIsNoDoubleDataPathRemoval) {
  auto context_type = kContextTypeConversational;
  const auto leaudio_group_id = 4;
  const auto num_devices = 1;

  /* Symulate banded headphonse */
  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
                   kLeAudioCodecLC3ChannelCountTwoChannel;

  /* Scenario
  1. Phone call to 1 device
  2. Stop the stream
  3. Get both ASE sink and Source to releasing
  4. Verify only 1 RemoveDataPath is called
  */

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

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

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

  /*Test ends before full clean*/
  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::STREAMING));

  ASSERT_TRUE(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);
  ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);

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

  /* Do not trigger any action on removeIsoData path.*/
  ON_CALL(*mock_iso_manager_, RemoveIsoDataPath).WillByDefault(Return());

  LeAudioGroupStateMachine::Get()->StopStream(group);

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

TEST_F(StateMachineTest, StreamStartWithDifferentContextFromConfiguredState) {
  auto context_type = kContextTypeConversational;
  const auto leaudio_group_id = 6;