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

Commit 90fcad2a authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Jakub Tyszkowski
Browse files

leaudio: Try to attach device which enable streaming contex type

If group is in the streaming state, and for some reason, non streaming
device received available context type witch match to streaming context
type, let's try to attach it to the stream.

Bug: 287089515
Test: atest bluetooth_le_audio_client_test
Tag: #feature
Change-Id: I345e9c64852eafd3024da958ae600f0ab125b00c
parent ca993c5a
Loading
Loading
Loading
Loading
+32 −5
Original line number Diff line number Diff line
@@ -1656,8 +1656,8 @@ class LeAudioClientImpl : public LeAudioClient {

    ase = leAudioDevice->GetAseByValHandle(hdl);

    if (ase) {
    LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);
    if (ase) {
      groupStateMachine_->ProcessGattNotifEvent(value, len, ase, leAudioDevice,
                                                group);

@@ -1680,7 +1680,6 @@ class LeAudioClientImpl : public LeAudioClient {
      /* Cached audio set configurations should be considered invalid when
       * PACs are updated.
       */
      LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);
      if (group) {
        group->InvalidateCachedConfigurations();
      }
@@ -1706,7 +1705,6 @@ class LeAudioClientImpl : public LeAudioClient {
      /* Cached audio set configurations should be considered invalid when
       * PACs are updated.
       */
      LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);
      if (group) {
        group->InvalidateCachedConfigurations();
      }
@@ -1781,11 +1779,40 @@ class LeAudioClientImpl : public LeAudioClient {
      UpdateLocationsAndContextsAvailability(leAudioDevice->group_id_);
    } else if (hdl == leAudioDevice->audio_avail_hdls_.val_hdl) {
      BidirectionalPair<AudioContexts> contexts;
      if (le_audio::client_parser::pacs::ParseAvailableAudioContexts(
      if (!le_audio::client_parser::pacs::ParseAvailableAudioContexts(
              contexts, len, value)) {
        return;
      }
        leAudioDevice->SetAvailableContexts(contexts);
        leAudioDevice->SetAvailableContexts(contexts);

        if (!group) {
        return;
        }

        /* Check if we should attach to stream this device */
        if (group->IsInTransition() || !group->IsStreaming()) {
        return;
        }

        if (leAudioDevice->HaveActiveAse()) {
        /* Do nothing, device is streaming */
        return;
        }

        if (leAudioDevice->GetConnectionState() !=
            DeviceConnectState::CONNECTED) {
        /* Do nothing, wait until device is connected */
        return;
        }

        auto group_metadata_contexts =
            get_bidirectional(group->GetMetadataContexts());
        auto device_available_contexts = leAudioDevice->GetAvailableContexts();
        if (group_metadata_contexts.test_any(device_available_contexts)) {
        AttachToStreamingGroupIfNeeded(leAudioDevice);
        }

    } else if (hdl == leAudioDevice->audio_supp_cont_hdls_.val_hdl) {
      BidirectionalPair<AudioContexts> supp_audio_contexts;
      if (le_audio::client_parser::pacs::ParseSupportedAudioContexts(
+95 −0
Original line number Diff line number Diff line
@@ -4784,6 +4784,101 @@ TEST_F(UnicastTest, TwoEarbuds2ndLateConnect) {
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);
}

TEST_F(UnicastTest, TwoEarbuds2ndReleaseAseRemoveAvailableContextAndBack) {
  uint8_t group_size = 2;
  int group_id = 2;

  /* Scenario
   * 1. Two devices A and B are streaming
   * 2. Device A Release ASE and removes all available context types
   * 3. Device B keeps streaming
   * 4. Device A sets available context types
   * 5. Device A should be attached to the stream
   */

  // Report working CSIS
  ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
      .WillByDefault(Return(true));

  const RawAddress test_address0 = GetTestAddress(0);
  const RawAddress test_address1 = GetTestAddress(1);

  // First earbud connects
  ConnectCsisDevice(test_address0, 1 /*conn_id*/,
                    codec_spec_conf::kLeAudioLocationFrontLeft,
                    codec_spec_conf::kLeAudioLocationFrontLeft, group_size,
                    group_id, 1 /* rank*/);

  // Second earbud connects
  ConnectCsisDevice(test_address1, 2 /*conn_id*/,
                    codec_spec_conf::kLeAudioLocationFrontRight,
                    codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                    group_id, 2 /* rank*/, true /*connect_through_csis*/);

  // Start streaming
  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);

  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
      .WillByDefault(Invoke([&](int group_id) { return 2; }));

  StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);

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

  // Expect two iso channel to be fed with data
  uint8_t cis_count_out = 2;
  uint8_t cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);

  /* Get group and Device A */
  auto group = streaming_groups.at(group_id);
  ASSERT_NE(group, nullptr);
  auto device = group->GetFirstDevice();

  /* Simulate available context type being cleared. 0x0074 is
   * pacs->avail_contexts_char + 1 */
  std::vector<uint8_t> cleared_avail_ctx = {0x00, 0x00, 0x00, 0x00};
  InjectNotificationEvent(device->address_, device->conn_id_, 0x0074,
                          cleared_avail_ctx);
  SyncOnMainLoop();

  /* Simulate ASE releasing and CIS Disconnection */
  for (auto& ase : device->ases_) {
    /* Releasing state */
    if (!ase.active) {
      continue;
    }

    std::vector<uint8_t> releasing_state = {
        ase.id, static_cast<uint8_t>(
                    types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)};
    InjectNotificationEvent(device->address_, device->conn_id_,
                            ase.hdls.val_hdl, releasing_state);
    SyncOnMainLoop();
    InjectCisDisconnected(group_id, ase.cis_conn_hdl);
    SyncOnMainLoop();
  }

  cis_count_out = 1;
  cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);

  /* Bring back available context types */
  std::vector<uint8_t> avail_ctx = {0xff, 0x00, 0xff, 0x00};
  InjectNotificationEvent(device->address_, device->conn_id_, 0x0074,
                          avail_ctx);
  SyncOnMainLoop();

  /* Check both devices are streaming */
  cis_count_out = 2;
  cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);
}

TEST_F(UnicastTest, TwoEarbuds2ndDisconnected) {
  uint8_t group_size = 2;
  int group_id = 2;