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

Commit 320a306b authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Make sure to use 2M PHY if possible.

LeAudio service configure ACL for 2M PHY on each reconnection.
Unfortunatelly it might happen before stack reads the Remote Supported
Features.
With this patch if the first try did not succeed, we try again when
encryption is enabled.

Bug: 330481628
Test: atest bluetooth_le_audio_client_test
Flag: Exempt, regression tested with unit tests, new test added
Change-Id: If1424436b45b912dcce0369c99d45f3e7168bd0f
parent dbaa0af2
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -2183,6 +2183,17 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    /* If PHY update did not succeed after ACL connection, which can happen
     * when remote feature read was not that quick, lets try to change phy here
     * one more time
     */
    if (!leAudioDevice->acl_phy_update_done_ &&
        bluetooth::shim::GetController()->SupportsBle2mPhy()) {
      log::info("{} set preferred PHY to 2M",
                ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      BTM_BleSetPhy(address, PHY_LE_2M, PHY_LE_2M, 0);
    }

    changeMtuIfPossible(leAudioDevice);

    leAudioDevice->encrypted_ = true;
@@ -2368,6 +2379,7 @@ class LeAudioClientImpl : public LeAudioClient {
    leAudioDevice->mtu_ = 0;
    leAudioDevice->closing_stream_for_disconnection_ = false;
    leAudioDevice->encrypted_ = false;
    leAudioDevice->acl_phy_update_done_ = false;

    groupStateMachine_->ProcessHciNotifAclDisconnected(group, leAudioDevice);

@@ -2569,6 +2581,23 @@ class LeAudioClientImpl : public LeAudioClient {
    leAudioDevice->mtu_ = mtu;
  }

  void OnPhyUpdate(uint16_t conn_id, uint8_t tx_phy, uint8_t rx_phy,
                   tGATT_STATUS status) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByConnId(conn_id);
    if (leAudioDevice == nullptr) {
      log::debug("Unknown conn_id {:#x}", conn_id);
      return;
    }

    log::info("{}, tx_phy: {:#x}, rx_phy: {:#x} , status: {:#x}",
              ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), tx_phy, rx_phy,
              status);

    if (status == 0) {
      leAudioDevice->acl_phy_update_done_ = true;
    }
  }

  void OnGattServiceDiscoveryDone(const RawAddress& address) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address);
    if (!leAudioDevice || (leAudioDevice->conn_id_ == GATT_INVALID_CONN_ID)) {
@@ -5991,7 +6020,11 @@ void le_audio_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
    case BTA_GATTC_CFG_MTU_EVT:
      instance->OnMtuChanged(p_data->cfg_mtu.conn_id, p_data->cfg_mtu.mtu);
      break;

    case BTA_GATTC_PHY_UPDATE_EVT:
      instance->OnPhyUpdate(
          p_data->phy_update.conn_id, p_data->phy_update.tx_phy,
          p_data->phy_update.rx_phy, p_data->phy_update.status);
      break;
    default:
      break;
  }
+2 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ class LeAudioDevice {
  std::string model_name_;
  bool allowlist_flag_;
  bool acl_asymmetric_;
  bool acl_phy_update_done_;

  alarm_t* link_quality_timer;
  uint16_t link_quality_timer_data;
@@ -142,6 +143,7 @@ class LeAudioDevice {
        model_name_(""),
        allowlist_flag_(false),
        acl_asymmetric_(false),
        acl_phy_update_done_(false),
        link_quality_timer(nullptr),
        dsa_({{DsaMode::DISABLED},
              types::DataPathState::IDLE,
+78 −0
Original line number Diff line number Diff line
@@ -573,6 +573,26 @@ class UnicastTestNoInit : public Test {
            base::Unretained(this->gatt_callback), event_data));
  }

  void InjectPhyChangedEvent(uint16_t conn_id, uint8_t tx_phy, uint8_t rx_phy,
                             tGATT_STATUS status) {
    ASSERT_NE(conn_id, GATT_INVALID_CONN_ID);
    tBTA_GATTC_PHY_UPDATE event_data = {
        .conn_id = conn_id,
        .tx_phy = tx_phy,
        .rx_phy = rx_phy,
        .status = status,
    };

    do_in_main_thread(FROM_HERE,
                      base::BindOnce(
                          [](tBTA_GATTC_CBACK* gatt_callback,
                             tBTA_GATTC_PHY_UPDATE event_data) {
                            gatt_callback(BTA_GATTC_PHY_UPDATE_EVT,
                                          (tBTA_GATTC*)&event_data);
                          },
                          base::Unretained(this->gatt_callback), event_data));
  }

  void InjectSearchCompleteEvent(uint16_t conn_id) {
    ASSERT_NE(conn_id, GATT_INVALID_CONN_ID);
    tBTA_GATTC_SEARCH_CMPL event_data = {
@@ -1502,6 +1522,7 @@ class UnicastTestNoInit : public Test {
        .WillByDefault(Return(true));
    ON_CALL(controller_, SupportsBleConnectedIsochronousStreamPeripheral)
        .WillByDefault(Return(true));
    ON_CALL(controller_, SupportsBle2mPhy).WillByDefault(Return(true));
    bluetooth::hci::testing::mock_controller_ = &controller_;
    bluetooth::manager::SetMockBtmInterface(&mock_btm_interface_);
    gatt::SetMockBtaGattInterface(&mock_gatt_interface_);
@@ -2908,6 +2929,63 @@ TEST_F(UnicastTestNoInit, InitializeNoHal_2_1) {
      "disable LE Audio Profile, or update your HAL");
}

TEST_F(UnicastTest, ConnectAndSetupPhy) {
  const RawAddress test_address0 = GetTestAddress(0);
  uint16_t conn_id = 1;
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      default_ase_cnt /*add_ascs*/);

  EXPECT_CALL(mock_btm_interface_,
              BleSetPhy(test_address0, PHY_LE_2M, PHY_LE_2M, 0))
      .Times(1);
  ConnectLeAudio(test_address0, false);
  Mock::VerifyAndClearExpectations(&mock_btm_interface_);

  EXPECT_CALL(mock_btm_interface_,
              BleSetPhy(test_address0, PHY_LE_2M, PHY_LE_2M, 0))
      .Times(1);
  InjectPhyChangedEvent(conn_id, 0, 0, GATT_REQ_NOT_SUPPORTED);
  SyncOnMainLoop();
  ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _))
      .WillByDefault(DoAll(Return(true)));
  InjectEncryptionChangedEvent(test_address0);
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_btm_interface_);

  /* Make sure flag `acl_phy_update_done_` is cleared after disconnect.
   * Just repeat previous steps after reconnection
   */
  InjectDisconnectedEvent(conn_id);
  SyncOnMainLoop();

  EXPECT_CALL(mock_btm_interface_,
              BleSetPhy(test_address0, PHY_LE_2M, PHY_LE_2M, 0))
      .Times(1);

  ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _))
      .WillByDefault(DoAll(Return(false)));
  InjectConnectedEvent(test_address0, 1);
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_btm_interface_);

  EXPECT_CALL(mock_btm_interface_,
              BleSetPhy(test_address0, PHY_LE_2M, PHY_LE_2M, 0))
      .Times(1);
  InjectPhyChangedEvent(conn_id, 0, 0, GATT_REQ_NOT_SUPPORTED);
  SyncOnMainLoop();
  ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _))
      .WillByDefault(DoAll(Return(true)));
  InjectEncryptionChangedEvent(test_address0);
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_btm_interface_);
}

TEST_F(UnicastTest, ConnectOneEarbudEmpty) {
  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEmpty(1, test_address0);