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

Commit c48d80ab authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Fix resume on LocalSink

Instead of checking if resume is expected, we should check if it is
allowed. That means, we should not expect configuration being already
cached for given context, but rather we should check if there is a
valid configuration for the give context.

Without the fix if metadata update is not sent before resume, we might
end up with stream being not establish as cache config might not exist
yet.

Note that if there was never MetadataUpdate called before the Resume,
stream still will not be created.

Bug: 303287030
Test: atest bluetooth_le_audio_client_test
Tag: #feature
Change-Id: I26042bdd292fc6f74c48b069f1cc0277fee2a8b5
parent 955aed8a
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -3842,7 +3842,7 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    /* Check if the device resume is expected */
    /* Check if the device resume is allowed */
    if (!group->GetCodecConfigurationByDirection(
            configuration_context_type_,
            le_audio::types::kLeAudioDirectionSink)) {
@@ -4098,8 +4098,8 @@ class LeAudioClientImpl : public LeAudioClient {
                                le_audio::types::kLeAudioDirectionSource);
    }

    /* Check if the device resume is expected */
    if (!group->GetCachedCodecConfigurationByDirection(
    /* Check if the device resume is allowed */
    if (!group->GetCodecConfigurationByDirection(
            configuration_context_type_,
            le_audio::types::kLeAudioDirectionSource)) {
      LOG(ERROR) << __func__ << ", invalid resume request for context type: "
+75 −0
Original line number Diff line number Diff line
@@ -3859,6 +3859,81 @@ TEST_F(UnicastTest, DoubleResumeFromAFOnLocalSink) {
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 0, 40);
}

TEST_F(UnicastTest, HandleResumeWithoutMetadataUpdateOnLocalSink) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;

  /**
   * In this test we want to make sure that if MetadataUpdate is
   * not called before Resume, but the context type is supported,
   * stream should be created
   */

  default_channel_cnt = 1;

  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/,
      true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/,
      0 /*rank*/);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
      .WillOnce(DoAll(SaveArg<1>(&group_id)));

  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);

  // Audio sessions are started only when device gets active
  EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
  EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
  LeAudioClient::Get()->GroupSetActive(group_id);
  SyncOnMainLoop();

  EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1);

  UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC);
  LocalAudioSinkResume();

  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_);
  Mock::VerifyAndClearExpectations(&mock_state_machine_);

  // Verify Data transfer on local audio sink which is started
  constexpr uint8_t cis_count_out = 0;
  constexpr uint8_t cis_count_in = 1;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 0, 40);

  SyncOnMainLoop();
  /* Clear cache by changing context types, this is required for the test
   * as setting active device actually generate cache
   */
  auto sink_available_context = types::kLeAudioContextAllRemoteSinkOnly;
  auto source_available_context = types::kLeAudioContextAllRemoteSource;
  InjectAvailableContextTypes(test_address0, 1, sink_available_context,
                              source_available_context);
  SyncOnMainLoop();

  StopStreaming(group_id, true);
  SyncOnMainLoop();

  // simulate suspend timeout passed, alarm executing
  fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
  SyncOnMainLoop();

  EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1);

  // Resume without metadata update while cached configuration is cleared
  LocalAudioSinkResume();
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_state_machine_);
}

TEST_F(UnicastTest, RemoveNodeWhileStreaming) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;