Loading system/bta/le_audio/client.cc +34 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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)) { Loading Loading @@ -5997,7 +6026,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; } Loading system/bta/le_audio/devices.h +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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, Loading system/bta/le_audio/le_audio_client_test.cc +78 −0 Original line number Diff line number Diff line Loading @@ -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 = { Loading Loading @@ -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_); Loading Loading @@ -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); Loading Loading
system/bta/le_audio/client.cc +34 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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)) { Loading Loading @@ -5997,7 +6026,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; } Loading
system/bta/le_audio/devices.h +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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, Loading
system/bta/le_audio/le_audio_client_test.cc +78 −0 Original line number Diff line number Diff line Loading @@ -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 = { Loading Loading @@ -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_); Loading Loading @@ -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); Loading