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

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

Merge "leaudio: Fix bad state on remote not going to Configured State" into main am: f23ca6fe

parents 7ae9d8d4 f23ca6fe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -177,6 +177,7 @@ void LeAudioDeviceGroup::Deactivate(void) {
    for (auto* ase = leAudioDevice->GetFirstActiveAse(); ase;
         ase = leAudioDevice->GetNextActiveAse(ase)) {
      ase->active = false;
      ase->reconfigure = 0;
    }
  }
}
+5 −2
Original line number Diff line number Diff line
@@ -796,9 +796,10 @@ void LeAudioDevice::PrintDebugState(void) {
      debug_str
          << "\n  id: " << +ase.id << ", active: " << ase.active << ", dir: "
          << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source")
          << ", state: " << bluetooth::common::ToString(ase.state)
          << ", cis_id: " << +ase.cis_id
          << ", cis_handle: " << +ase.cis_conn_hdl
          << ", state: " << bluetooth::common::ToString(ase.cis_state)
          << ", cis_state: " << bluetooth::common::ToString(ase.cis_state)
          << ", data_path_state: "
          << bluetooth::common::ToString(ase.data_path_state)
          << "\n ase max_latency: " << +ase.qos_config.max_transport_latency
@@ -808,7 +809,8 @@ void LeAudioDevice::PrintDebugState(void) {
          << ", presentation_delay: " << +ase.qos_config.presentation_delay
          << ", framing: " << +ase.qos_config.framing
          << ", phy: " << +ase.qos_config.phy
          << ", target latency: " << +ase.target_latency;
          << ", target latency: " << +ase.target_latency
          << ", reconfigure: " << ase.reconfigure << "\n";
    }
  }

@@ -1022,6 +1024,7 @@ void LeAudioDevice::DeactivateAllAses(void) {
    ase.cis_state = CisState::IDLE;
    ase.data_path_state = DataPathState::IDLE;
    ase.active = false;
    ase.reconfigure = 0;
    ase.cis_id = bluetooth::le_audio::kInvalidCisId;
    ase.cis_conn_hdl = 0;
  }
+174 −0
Original line number Diff line number Diff line
@@ -890,6 +890,19 @@ class StateMachineTestBase : public Test {
    }
  }

  void InjectInitialConfiguredNotification(LeAudioDeviceGroup* group) {
    for (auto* device = group->GetFirstDevice(); device != nullptr;
         device = group->GetNextDevice(device)) {
      for (auto& ase : device->ases_) {
        client_parser::ascs::ase_codec_configured_state_params
            codec_configured_state_params;
        InjectAseStateNotification(&ase, device, group,
                                   ascs::kAseStateCodecConfigured,
                                   &codec_configured_state_params);
      }
    }
  }

  void InjectInitialIdleAndConfiguredNotification(LeAudioDeviceGroup* group) {
    for (auto* device = group->GetFirstDevice(); device != nullptr;
         device = group->GetNextDevice(device)) {
@@ -4355,6 +4368,167 @@ TEST_F(StateMachineTest, testStateTransitionTimeout) {
  ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
}

TEST_F(StateMachineTest,
       testStateTransitionTimeoutAndDisconnectWhenConfigured) {
  const auto context_type = kContextTypeMedia;
  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();
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
                                  GATT_WRITE_NO_RSP, _, _))
      .Times(1);

  InjectInitialConfiguredNotification(group);

  group->PrintDebugState();

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

  group->PrintDebugState();

  // Check if timeout is fired
  EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));

  // simulate timeout seconds passed, alarm executing
  fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
  ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));

  LOG_INFO("OnStateTransitionTimeout");

  /* Simulate On State timeout */
  group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
  group->ClearAllCises();
  group->PrintDebugState();

  InjectAclDisconnected(group, leAudioDevice);

  /* Verify that all ASEs are inactive and reconfiguration flag is cleared.*/
  for (const auto& ase : leAudioDevice->ases_) {
    ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
    ASSERT_EQ(ase.cis_state, types::CisState::IDLE);
    ASSERT_EQ(ase.data_path_state, types::DataPathState::IDLE);
    ASSERT_EQ(ase.reconfigure, 0);
  }
}

TEST_F(StateMachineTest,
       testStateTransitionTimeoutAndDisconnectWhenQoSConfigured) {
  const auto context_type = kContextTypeMedia;
  const int leaudio_group_id = 4;
  channel_count_ = kLeAudioCodecChannelCountSingleChannel |
                   kLeAudioCodecChannelCountTwoChannel;

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

  auto* leAudioDevice = group->GetFirstDevice();
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
                                  GATT_WRITE_NO_RSP, _, _))
      .Times(2);

  InjectInitialConfiguredNotification(group);

  group->PrintDebugState();

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

  group->PrintDebugState();

  // Check if timeout is fired
  EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));

  // simulate timeout seconds passed, alarm executing
  fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
  ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));

  LOG_INFO("OnStateTransitionTimeout");

  /* Simulate On State timeout */
  group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
  group->ClearAllCises();
  group->PrintDebugState();

  InjectAclDisconnected(group, leAudioDevice);

  /* Verify that all ASEs are inactive and reconfiguration flag is cleared.*/
  for (const auto& ase : leAudioDevice->ases_) {
    ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
    ASSERT_EQ(ase.cis_state, types::CisState::IDLE);
    ASSERT_EQ(ase.data_path_state, types::DataPathState::IDLE);
    ASSERT_EQ(ase.reconfigure, 0);
  }
}

TEST_F(StateMachineTest, testStateTransitionTimeoutAndDisconnectWhenEnabling) {
  const auto context_type = kContextTypeMedia;
  const int leaudio_group_id = 4;
  channel_count_ = kLeAudioCodecChannelCountSingleChannel |
                   kLeAudioCodecChannelCountTwoChannel;

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

  auto* leAudioDevice = group->GetFirstDevice();
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
                                  GATT_WRITE_NO_RSP, _, _))
      .Times(3);

  InjectInitialConfiguredNotification(group);

  group->PrintDebugState();

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

  group->PrintDebugState();

  // Check if timeout is fired
  EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));

  // simulate timeout seconds passed, alarm executing
  fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
  ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));

  LOG_INFO("OnStateTransitionTimeout");

  /* Simulate On State timeout */
  group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
  group->ClearAllCises();
  group->PrintDebugState();

  InjectAclDisconnected(group, leAudioDevice);

  /* Verify that all ASEs are inactive and reconfiguration flag is cleared.*/
  for (const auto& ase : leAudioDevice->ases_) {
    ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
    ASSERT_EQ(ase.cis_state, types::CisState::IDLE);
    ASSERT_EQ(ase.data_path_state, types::DataPathState::IDLE);
    ASSERT_EQ(ase.reconfigure, 0);
  }
}

MATCHER_P(dataPathIsEq, expected, "") { return (arg.data_path_id == expected); }

TEST_F(StateMachineTest, testConfigureDataPathForHost) {