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

Commit 1485ae95 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
Change-Id: I65e7aa6ae71e06378d70b6883e94886329fd2a32
parent e8e7f2e0
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -2417,8 +2417,7 @@ bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {

  LOG_INFO(" Configuring device %s", address_.ToString().c_str());
  for (auto& ase : ases_) {
    if (!ase.active &&
        ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
    if (ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
        ase.configured_for_context_type == context_type) {
      LOG_INFO(
          " conn_id: %d, ase id %d, cis id %d, cis_handle 0x%04x is activated.",
+149 −0
Original line number 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());
}

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 le_audio