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

Commit 27ddab37 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Fix device being not in allow list when group connected

This patch makes sure that when 1 group member connects, the others will
be added to allow list.

Also when all devices got disconnected, all of them will go back to
default reconnection mode.

Bug: 294615104
Test: atest bluetooth_le_audio_client_test
Tag: #feature
Change-Id: I3d9dfac11d85559172e3e054e5255c66e35c71e9
parent 4e3cc3ba
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -2067,8 +2067,15 @@ class LeAudioClientImpl : public LeAudioClient {
     * announcements)
     */
    auto group = aseGroups_.FindById(group_id);
    if (group == nullptr || !group->IsAnyDeviceConnected()) {
      LOG_INFO("Group %d is not streaming", group_id);
    if (group == nullptr) {
      LOG_INFO("Group %d is destroyed.", group_id);
      return;
    }

    if (!group->IsAnyDeviceConnected()) {
      LOG_INFO("Group %d is not connected", group_id);
      /* Make sure all devices are in the default reconnection mode */
      group->ApplyReconnectionMode(gatt_if_, reconnection_mode_);
      return;
    }

@@ -2290,16 +2297,14 @@ class LeAudioClientImpl : public LeAudioClient {

    /* In other disconnect resons we act based on the autoconnect_flag_ */
    if (leAudioDevice->autoconnect_flag_) {
      leAudioDevice->SetConnectionState(
          DeviceConnectState::CONNECTING_AUTOCONNECT);

      BTA_GATTC_Open(gatt_if_, address, reconnection_mode_, false);
      if (group->IsAnyDeviceConnected()) {
        /* If all set is disconnecting, let's give it some time.
         * If not all get disconnected, and there will be group member
         * connected we want to put disconnected devices to allow list
         */
        scheduleGroupConnectedCheck(leAudioDevice->group_id_);
      } else {
        group->ApplyReconnectionMode(gatt_if_, reconnection_mode_);
      }
    }
  }
@@ -2996,6 +3001,13 @@ class LeAudioClientImpl : public LeAudioClient {
        UpdateLocationsAndContextsAvailability(group);
      }
      AttachToStreamingGroupIfNeeded(leAudioDevice);

      if (reconnection_mode_ == BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS) {
        /* Add other devices to allow list if there are any not yet connected
         * from the group
         */
        group->AddToAllowListNotConnectedGroupMembers(gatt_if_);
      }
    }
  }

@@ -5120,10 +5132,6 @@ class LeAudioClientImpl : public LeAudioClient {
              std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal,
                        weak_factory_.GetWeakPtr(), std::placeholders::_1,
                        std::placeholders::_2));
          if (reconnection_mode_ ==
              BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS) {
            group->AddToAllowListNotConnectedGroupMembers(gatt_if_);
          }
        }

        if (audio_sender_state_ == AudioState::READY_TO_START)
+14 −0
Original line number Diff line number Diff line
@@ -2068,6 +2068,20 @@ void LeAudioDeviceGroup::AddToAllowListNotConnectedGroupMembers(int gatt_if) {
  }
}

void LeAudioDeviceGroup::ApplyReconnectionMode(
    int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode) {
  for (const auto& device_iter : leAudioDevices_) {
    BTA_GATTC_CancelOpen(gatt_if, device_iter.lock()->address_, false);
    BTA_GATTC_Open(gatt_if, device_iter.lock()->address_, reconnection_mode,
                   false);
    LOG_INFO("Group %d in state %s. Adding %s to default reconnection mode ",
             group_id_, bluetooth::common::ToString(GetState()).c_str(),
             ADDRESS_TO_LOGGABLE_CSTR(device_iter.lock()->address_));
    device_iter.lock()->SetConnectionState(
        DeviceConnectState::CONNECTING_AUTOCONNECT);
  }
}

bool LeAudioDeviceGroup::IsConfiguredForContext(
    types::LeAudioContextType context_type) const {
  /* Check if all connected group members are configured */
+1 −0
Original line number Diff line number Diff line
@@ -400,6 +400,7 @@ class LeAudioDeviceGroup {
  void SetPendingConfiguration(void);
  void ClearPendingConfiguration(void);
  void AddToAllowListNotConnectedGroupMembers(int gatt_if);
  void ApplyReconnectionMode(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode);
  void Disable(int gatt_if);
  void Enable(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode);
  bool IsEnabled(void) const;
+145 −5
Original line number Diff line number Diff line
@@ -5798,11 +5798,9 @@ TEST_F(UnicastTest, TwoEarbuds2ndDisconnected) {
    InjectCisDisconnected(group_id, ase.cis_conn_hdl);
  }

  /* It is called twice. Once with BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS,
   * and then after delay with BTM_BLE_BKG_CONNECT_ALLOW_LIST
   */
  EXPECT_CALL(mock_gatt_interface_, Open(_, device->address_, _, false))
      .Times(2);
  EXPECT_CALL(mock_gatt_interface_,
              Open(_, device->address_, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false))
      .Times(1);

  // Record NumOfConnected when groupStateMachine_ gets notified about the
  // disconnection
@@ -6979,4 +6977,146 @@ TEST_F(UnicastTest, SpeakerStreamingTimeout) {
  auto group = streaming_groups.at(group_id);
  ASSERT_EQ(0, static_cast<int>(group->cises_.size()));
}

TEST_F(UnicastTest, AddMemberToAllowListWhenOneDeviceConnected) {
  uint8_t group_size = 2;
  int group_id = 2;
  int conn_id_dev_0 = 1;
  int conn_id_dev_1 = 2;

  /*Scenario to test
   * 1. Connect Device A and disconnect
   * 2. Connect Device B
   * 3. verify Device B is in the allow list.
   */
  // Report working CSIS
  ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
      .WillByDefault(Return(true));

  // First earbud
  const RawAddress test_address0 = GetTestAddress(0);
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true))
      .Times(1);

  ConnectCsisDevice(test_address0, conn_id_dev_0,
                    codec_spec_conf::kLeAudioLocationFrontLeft,
                    codec_spec_conf::kLeAudioLocationFrontLeft, group_size,
                    group_id, 1 /* rank*/);

  SyncOnMainLoop();

  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  InjectDisconnectedEvent(conn_id_dev_0);

  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  // Second earbud
  const RawAddress test_address1 = GetTestAddress(1);
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true))
      .Times(1);

  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _))
      .Times(1);

  ConnectCsisDevice(test_address1, conn_id_dev_1,
                    codec_spec_conf::kLeAudioLocationFrontRight,
                    codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                    group_id, 2 /* rank*/, true /*connect_through_csis*/);

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

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

TEST_F(UnicastTest, ResetToDefaultReconnectionMode) {
  uint8_t group_size = 2;
  int group_id = 2;
  int conn_id_dev_0 = 1;
  int conn_id_dev_1 = 2;

  /*Scenario to test
   * 1. Connect Device A and disconnect
   * 2. Connect Device B
   * 3. verify Device B is in the allow list.
   * 4. Disconnect B device
   * 5, Verify A and B device are back in targeted announcement reconnection
   * mode
   */
  // Report working CSIS
  ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
      .WillByDefault(Return(true));

  // First earbud
  const RawAddress test_address0 = GetTestAddress(0);
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true))
      .Times(1);

  ConnectCsisDevice(test_address0, conn_id_dev_0,
                    codec_spec_conf::kLeAudioLocationFrontLeft,
                    codec_spec_conf::kLeAudioLocationFrontLeft, group_size,
                    group_id, 1 /* rank*/);

  SyncOnMainLoop();

  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  InjectDisconnectedEvent(conn_id_dev_0);

  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  // Second earbud
  const RawAddress test_address1 = GetTestAddress(1);
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true))
      .Times(1);

  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _))
      .Times(1);

  ConnectCsisDevice(test_address1, conn_id_dev_1,
                    codec_spec_conf::kLeAudioLocationFrontRight,
                    codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                    group_id, 2 /* rank*/, true /*connect_through_csis*/);

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

  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  // Disconnect Device B, expect default reconnection mode
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address1, false))
      .Times(2);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address1,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  InjectDisconnectedEvent(conn_id_dev_1, GATT_CONN_TERMINATE_PEER_USER);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

}  // namespace le_audio