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

Commit 76a718d2 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Fix start stream after reconfiguration

When group is in Configured state, ASE can be either activated (if
reconfiguration was in process) or inactivated if remote gets into
Configured state autonomusly after stream is stopped.
This should be taken into account when starting stream for the
configured group.

Bug: 250460929
Test: atest BluetoothInstrumentationTests
Test: atest --host bluetooth_le_audio_test
Tag: #feature
Merged-In: I65e7aa6ae71e06378d70b6883e94886329fd2a32
Change-Id: I65e7aa6ae71e06378d70b6883e94886329fd2a32
(cherry picked from commit 1485ae95)
parent e6cd07eb
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -2435,8 +2435,7 @@ bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {


  LOG_INFO(" Configuring device %s", address_.ToString().c_str());
  LOG_INFO(" Configuring device %s", address_.ToString().c_str());
  for (auto& ase : ases_) {
  for (auto& ase : ases_) {
    if (!ase.active &&
    if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
        ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
        ase.configured_for_context_type == context_type) {
        ase.configured_for_context_type == context_type) {
      LOG_INFO(
      LOG_INFO(
          " conn_id: %d, ase id %d, cis id %d, cis_handle 0x%04x is activated.",
          " conn_id: %d, ase id %d, cis id %d, cis_handle 0x%04x is activated.",
+149 −0
Original line number Original line Diff line number Diff line
@@ -2775,5 +2775,154 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStream) {
  ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
  ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
}
}


TEST_F(StateMachineTest, StartStreamAfterConfigure) {
  const auto context_type = kContextTypeMedia;
  const auto leaudio_group_id = 6;
  const auto num_devices = 2;

  ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);

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

  PrepareConfigureCodecHandler(group, 0, true);
  PrepareConfigureQosHandler(group);
  PrepareEnableHandler(group);
  PrepareDisableHandler(group);
  PrepareReleaseHandler(group);

  InjectInitialIdleNotification(group);

  auto* leAudioDevice = group->GetFirstDevice();
  auto expected_devices_written = 0;
  while (leAudioDevice) {
    /* Three Writes:
     * 1. Codec configure
     * 2: Codec QoS
     * 3: Enabling
     */
    EXPECT_CALL(gatt_queue,
                WriteCharacteristic(leAudioDevice->conn_id_,
                                    leAudioDevice->ctp_hdls_.val_hdl, _,
                                    GATT_WRITE_NO_RSP, _, _))
        .Times(3);
    expected_devices_written++;
    leAudioDevice = group->GetNextDevice(leAudioDevice);
  }
  ASSERT_EQ(expected_devices_written, num_devices);

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

  // Start the configuration and stream Media content
  group->SetPendingConfiguration();
  LeAudioGroupStateMachine::Get()->ConfigureStream(
      group, static_cast<types::LeAudioContextType>(context_type),
      context_type);

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

  group->ClearPendingConfiguration();
  // Validate GroupStreamStatus
  EXPECT_CALL(
      mock_callbacks_,
      StatusReportCb(leaudio_group_id,
                     bluetooth::le_audio::GroupStreamStatus::STREAMING));

  // Start the configuration and stream Media content
  LeAudioGroupStateMachine::Get()->StartStream(
      group, static_cast<types::LeAudioContextType>(context_type),
      context_type);

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

TEST_F(StateMachineTest, StartStreamCachedConfig) {
  const auto context_type = kContextTypeMedia;
  const auto leaudio_group_id = 6;
  const auto num_devices = 2;

  ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);

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

  PrepareConfigureCodecHandler(group, 0, true);
  PrepareConfigureQosHandler(group);
  PrepareEnableHandler(group);
  PrepareDisableHandler(group);
  PrepareReleaseHandler(group);

  InjectInitialIdleNotification(group);

  auto* leAudioDevice = group->GetFirstDevice();
  auto expected_devices_written = 0;
  while (leAudioDevice) {
    /* Three Writes:
     * 1: Codec config
     * 2: Codec QoS (+1 after restart)
     * 3: Enabling (+1 after restart)
     * 4: Release (1)
     */
    EXPECT_CALL(gatt_queue,
                WriteCharacteristic(leAudioDevice->conn_id_,
                                    leAudioDevice->ctp_hdls_.val_hdl, _,
                                    GATT_WRITE_NO_RSP, _, _))
        .Times(6);
    expected_devices_written++;
    leAudioDevice = group->GetNextDevice(leAudioDevice);
  }
  ASSERT_EQ(expected_devices_written, num_devices);

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

  // Start the configuration and stream Media content
  LeAudioGroupStateMachine::Get()->StartStream(
      group, static_cast<types::LeAudioContextType>(context_type),
      context_type);

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

  // 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::CONFIGURED_AUTONOMOUS));
  // Start the configuration and stream Media content
  LeAudioGroupStateMachine::Get()->StopStream(group);

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

  // Restart stream
  EXPECT_CALL(
      mock_callbacks_,
      StatusReportCb(leaudio_group_id,
                     bluetooth::le_audio::GroupStreamStatus::STREAMING));

  // Start the configuration and stream Media content
  LeAudioGroupStateMachine::Get()->StartStream(
      group, static_cast<types::LeAudioContextType>(context_type),
      context_type);

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

}  // namespace internal
}  // namespace internal
}  // namespace le_audio
}  // namespace le_audio