Loading system/bta/le_audio/client.cc +74 −25 Original line number Diff line number Diff line Loading @@ -1961,7 +1961,8 @@ class LeAudioClientImpl : public LeAudioClient { le_audio::ConnectionStatus::FAILED); } void RegisterKnownNotifications(LeAudioDevice* leAudioDevice) { void RegisterKnownNotifications(LeAudioDevice* leAudioDevice, bool gatt_register, bool write_ccc) { LOG(INFO) << __func__ << " device: " << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_); Loading @@ -1973,49 +1974,45 @@ class LeAudioClientImpl : public LeAudioClient { return; } bool write_ccc = false; /* GATTC will ommit not registered previously handles */ for (auto pac_tuple : leAudioDevice->snk_pacs_) { subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), write_ccc); subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), gatt_register, write_ccc); } for (auto pac_tuple : leAudioDevice->src_pacs_) { subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), write_ccc); subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), gatt_register, write_ccc); } if (leAudioDevice->snk_audio_locations_hdls_.val_hdl != 0) subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->snk_audio_locations_hdls_, write_ccc); leAudioDevice->snk_audio_locations_hdls_, gatt_register, write_ccc); if (leAudioDevice->src_audio_locations_hdls_.val_hdl != 0) subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->src_audio_locations_hdls_, write_ccc); leAudioDevice->src_audio_locations_hdls_, gatt_register, write_ccc); if (leAudioDevice->audio_avail_hdls_.val_hdl != 0) subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->audio_avail_hdls_, write_ccc); subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->audio_avail_hdls_, gatt_register, write_ccc); if (leAudioDevice->audio_supp_cont_hdls_.val_hdl != 0) subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->audio_supp_cont_hdls_, write_ccc); leAudioDevice->audio_supp_cont_hdls_, gatt_register, write_ccc); for (struct ase& ase : leAudioDevice->ases_) subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, ase.hdls, write_ccc); leAudioDevice->address_, ase.hdls, gatt_register, write_ccc); /* Let's register only for control point on the reconnection time. * This is mainly to assure that the database did not changed on another * side */ subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->ctp_hdls_, true); leAudioDevice->ctp_hdls_, gatt_register, write_ccc); } void changeMtuIfPossible(LeAudioDevice* leAudioDevice) { Loading Loading @@ -2067,7 +2064,18 @@ class LeAudioClientImpl : public LeAudioClient { /* If we know services, register for notifications */ if (leAudioDevice->known_service_handles_) { RegisterKnownNotifications(leAudioDevice); /* This registration will do subscribtion in local GATT as we * assume remote device keeps bonded CCC values. */ RegisterKnownNotifications(leAudioDevice, true, false); /* Make sure remote keeps CCC values as per specification. * We read only ctp_ccc value. If that one is good, we assume * remote keeps CCC values correctly. */ BtaGattQueue::ReadCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.ccc_hdl, OnGattCtpCccReadRspStatic, NULL); } /* If we know services and read is not ongoing, this is reconnection and Loading Loading @@ -2339,15 +2347,17 @@ class LeAudioClientImpl : public LeAudioClient { bool subscribe_for_notification(uint16_t conn_id, const RawAddress& address, struct le_audio::types::hdl_pair handle_pair, bool gatt_register = true, bool write_ccc = true) { std::vector<uint8_t> value(2); uint8_t* ptr = value.data(); uint16_t handle = handle_pair.val_hdl; uint16_t ccc_handle = handle_pair.ccc_hdl; LOG_INFO("conn id %d", conn_id); if (BTA_GATTC_RegisterForNotifications(gatt_if_, address, handle) != GATT_SUCCESS) { LOG_INFO("conn id %d, gatt_register: %b, write_ccc: %b", conn_id, gatt_register, write_ccc); if (gatt_register && BTA_GATTC_RegisterForNotifications( gatt_if_, address, handle) != GATT_SUCCESS) { LOG(ERROR) << __func__ << ", cannot register for notification: " << static_cast<int>(handle); return false; Loading Loading @@ -4881,6 +4891,45 @@ class LeAudioClientImpl : public LeAudioClient { return false; } static void OnGattCtpCccReadRspStatic(uint16_t conn_id, tGATT_STATUS status, uint16_t hdl, uint16_t len, uint8_t* value, void* data) { if (!instance) return; LOG_DEBUG("conn_id: 0x%04x, status: 0x%02x", conn_id, status); LeAudioDevice* leAudioDevice = instance->leAudioDevices_.FindByConnId(conn_id); if (!leAudioDevice) { LOG_ERROR("LeAudioDevice not found"); return; } if (status == GATT_DATABASE_OUT_OF_SYNC) { LOG_INFO("Database out of sync for %s, re-discovering", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); instance->ClearDeviceInformationAndStartSearch(leAudioDevice); return; } if (status != GATT_SUCCESS || len != 2) { LOG_ERROR("Could not read CCC for %s, disconnecting", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); instance->Disconnect(leAudioDevice->address_); return; } uint16_t val = *(uint16_t*)value; if (val == 0) { LOG_INFO("%s forgot CCC values. Re-subscribing", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); instance->RegisterKnownNotifications(leAudioDevice, false, true); } else { instance->connectionReady(leAudioDevice); } } static void OnGattReadRspStatic(uint16_t conn_id, tGATT_STATUS status, uint16_t hdl, uint16_t len, uint8_t* value, void* data) { Loading system/bta/le_audio/le_audio_client_test.cc +109 −17 Original line number Diff line number Diff line Loading @@ -89,6 +89,9 @@ constexpr le_audio::types::LeAudioContextType kLeAudioDefaultConfigurationContext = le_audio::types::LeAudioContextType::UNSPECIFIED; static tGATT_STATUS gatt_read_ctp_ccc_status_ = GATT_SUCCESS; static uint8_t ccc_stored_byte_val_ = 0x01; static constexpr char kNotifyUpperLayerAboutGroupBeingInIdleDuringCall[] = "persist.bluetooth.leaudio.notify.idle.during.call"; const char* test_flags[] = { Loading Loading @@ -1399,6 +1402,9 @@ class UnicastTestNoInit : public Test { SupportsBleConnectedIsochronousStreamPeripheral) .WillByDefault(Return(true)); gatt_read_ctp_ccc_status_ = GATT_SUCCESS; ccc_stored_byte_val_ = 0x01; controller::SetMockControllerInterface(&controller_interface_); bluetooth::manager::SetMockBtmInterface(&mock_btm_interface_); gatt::SetMockBtaGattInterface(&mock_gatt_interface_); Loading Loading @@ -2414,6 +2420,14 @@ class UnicastTestNoInit : public Test { std::vector<uint8_t> value; bool is_ase_sink_request = false; bool is_ase_src_request = false; if (handle == ascs->ctp_ccc) { value = {ccc_stored_byte_val_, 00}; cb(conn_id, gatt_read_ctp_ccc_status_, handle, value.size(), value.data(), cb_data); return; } uint8_t idx; for (idx = 0; idx < max_num_of_ases; idx++) { if (handle == ascs->sink_ase_char[idx] + 1) { Loading Loading @@ -7638,25 +7652,12 @@ TEST_F(UnicastTest, HandleDatabaseOutOfSync) { InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); // default action for WriteDescriptor function call ON_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) .WillByDefault(Invoke([](uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data) -> void { if (cb) do_in_main_thread( FROM_HERE, base::BindOnce( [](GATT_WRITE_OP_CB cb, uint16_t conn_id, uint16_t handle, uint16_t len, uint8_t* value, void* cb_data) { cb(conn_id, GATT_DATABASE_OUT_OF_SYNC, handle, len, value, cb_data); }, cb, conn_id, handle, value.size(), value.data(), cb_data)); })); /* Simulate DATABASE OUT OF SYNC */ gatt_read_ctp_ccc_status_ = GATT_DATABASE_OUT_OF_SYNC; EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)).Times(0); ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) .WillByDefault(Return()); EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)); Loading @@ -7664,6 +7665,97 @@ TEST_F(UnicastTest, HandleDatabaseOutOfSync) { InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); } TEST_F(UnicastTest, TestRemoteDeviceKeepCccValues) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, 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); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); /* Simulate remote cache is good */ ccc_stored_byte_val_ = 0x01; EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)).Times(0); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } TEST_F(UnicastTest, TestRemoteDeviceForgetsCccValues) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, 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); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); /* Simulate remote cache is broken */ ccc_stored_byte_val_ = 0; EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) .Times(AtLeast(1)); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } TEST_F(UnicastTest, SpeakerStreamingTimeout) { Loading Loading
system/bta/le_audio/client.cc +74 −25 Original line number Diff line number Diff line Loading @@ -1961,7 +1961,8 @@ class LeAudioClientImpl : public LeAudioClient { le_audio::ConnectionStatus::FAILED); } void RegisterKnownNotifications(LeAudioDevice* leAudioDevice) { void RegisterKnownNotifications(LeAudioDevice* leAudioDevice, bool gatt_register, bool write_ccc) { LOG(INFO) << __func__ << " device: " << ADDRESS_TO_LOGGABLE_STR(leAudioDevice->address_); Loading @@ -1973,49 +1974,45 @@ class LeAudioClientImpl : public LeAudioClient { return; } bool write_ccc = false; /* GATTC will ommit not registered previously handles */ for (auto pac_tuple : leAudioDevice->snk_pacs_) { subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), write_ccc); subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), gatt_register, write_ccc); } for (auto pac_tuple : leAudioDevice->src_pacs_) { subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), write_ccc); subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, std::get<0>(pac_tuple), gatt_register, write_ccc); } if (leAudioDevice->snk_audio_locations_hdls_.val_hdl != 0) subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->snk_audio_locations_hdls_, write_ccc); leAudioDevice->snk_audio_locations_hdls_, gatt_register, write_ccc); if (leAudioDevice->src_audio_locations_hdls_.val_hdl != 0) subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->src_audio_locations_hdls_, write_ccc); leAudioDevice->src_audio_locations_hdls_, gatt_register, write_ccc); if (leAudioDevice->audio_avail_hdls_.val_hdl != 0) subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->audio_avail_hdls_, write_ccc); subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->audio_avail_hdls_, gatt_register, write_ccc); if (leAudioDevice->audio_supp_cont_hdls_.val_hdl != 0) subscribe_for_notification( leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->audio_supp_cont_hdls_, write_ccc); leAudioDevice->audio_supp_cont_hdls_, gatt_register, write_ccc); for (struct ase& ase : leAudioDevice->ases_) subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, ase.hdls, write_ccc); leAudioDevice->address_, ase.hdls, gatt_register, write_ccc); /* Let's register only for control point on the reconnection time. * This is mainly to assure that the database did not changed on another * side */ subscribe_for_notification(leAudioDevice->conn_id_, leAudioDevice->address_, leAudioDevice->ctp_hdls_, true); leAudioDevice->ctp_hdls_, gatt_register, write_ccc); } void changeMtuIfPossible(LeAudioDevice* leAudioDevice) { Loading Loading @@ -2067,7 +2064,18 @@ class LeAudioClientImpl : public LeAudioClient { /* If we know services, register for notifications */ if (leAudioDevice->known_service_handles_) { RegisterKnownNotifications(leAudioDevice); /* This registration will do subscribtion in local GATT as we * assume remote device keeps bonded CCC values. */ RegisterKnownNotifications(leAudioDevice, true, false); /* Make sure remote keeps CCC values as per specification. * We read only ctp_ccc value. If that one is good, we assume * remote keeps CCC values correctly. */ BtaGattQueue::ReadCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.ccc_hdl, OnGattCtpCccReadRspStatic, NULL); } /* If we know services and read is not ongoing, this is reconnection and Loading Loading @@ -2339,15 +2347,17 @@ class LeAudioClientImpl : public LeAudioClient { bool subscribe_for_notification(uint16_t conn_id, const RawAddress& address, struct le_audio::types::hdl_pair handle_pair, bool gatt_register = true, bool write_ccc = true) { std::vector<uint8_t> value(2); uint8_t* ptr = value.data(); uint16_t handle = handle_pair.val_hdl; uint16_t ccc_handle = handle_pair.ccc_hdl; LOG_INFO("conn id %d", conn_id); if (BTA_GATTC_RegisterForNotifications(gatt_if_, address, handle) != GATT_SUCCESS) { LOG_INFO("conn id %d, gatt_register: %b, write_ccc: %b", conn_id, gatt_register, write_ccc); if (gatt_register && BTA_GATTC_RegisterForNotifications( gatt_if_, address, handle) != GATT_SUCCESS) { LOG(ERROR) << __func__ << ", cannot register for notification: " << static_cast<int>(handle); return false; Loading Loading @@ -4881,6 +4891,45 @@ class LeAudioClientImpl : public LeAudioClient { return false; } static void OnGattCtpCccReadRspStatic(uint16_t conn_id, tGATT_STATUS status, uint16_t hdl, uint16_t len, uint8_t* value, void* data) { if (!instance) return; LOG_DEBUG("conn_id: 0x%04x, status: 0x%02x", conn_id, status); LeAudioDevice* leAudioDevice = instance->leAudioDevices_.FindByConnId(conn_id); if (!leAudioDevice) { LOG_ERROR("LeAudioDevice not found"); return; } if (status == GATT_DATABASE_OUT_OF_SYNC) { LOG_INFO("Database out of sync for %s, re-discovering", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); instance->ClearDeviceInformationAndStartSearch(leAudioDevice); return; } if (status != GATT_SUCCESS || len != 2) { LOG_ERROR("Could not read CCC for %s, disconnecting", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); instance->Disconnect(leAudioDevice->address_); return; } uint16_t val = *(uint16_t*)value; if (val == 0) { LOG_INFO("%s forgot CCC values. Re-subscribing", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_)); instance->RegisterKnownNotifications(leAudioDevice, false, true); } else { instance->connectionReady(leAudioDevice); } } static void OnGattReadRspStatic(uint16_t conn_id, tGATT_STATUS status, uint16_t hdl, uint16_t len, uint8_t* value, void* data) { Loading
system/bta/le_audio/le_audio_client_test.cc +109 −17 Original line number Diff line number Diff line Loading @@ -89,6 +89,9 @@ constexpr le_audio::types::LeAudioContextType kLeAudioDefaultConfigurationContext = le_audio::types::LeAudioContextType::UNSPECIFIED; static tGATT_STATUS gatt_read_ctp_ccc_status_ = GATT_SUCCESS; static uint8_t ccc_stored_byte_val_ = 0x01; static constexpr char kNotifyUpperLayerAboutGroupBeingInIdleDuringCall[] = "persist.bluetooth.leaudio.notify.idle.during.call"; const char* test_flags[] = { Loading Loading @@ -1399,6 +1402,9 @@ class UnicastTestNoInit : public Test { SupportsBleConnectedIsochronousStreamPeripheral) .WillByDefault(Return(true)); gatt_read_ctp_ccc_status_ = GATT_SUCCESS; ccc_stored_byte_val_ = 0x01; controller::SetMockControllerInterface(&controller_interface_); bluetooth::manager::SetMockBtmInterface(&mock_btm_interface_); gatt::SetMockBtaGattInterface(&mock_gatt_interface_); Loading Loading @@ -2414,6 +2420,14 @@ class UnicastTestNoInit : public Test { std::vector<uint8_t> value; bool is_ase_sink_request = false; bool is_ase_src_request = false; if (handle == ascs->ctp_ccc) { value = {ccc_stored_byte_val_, 00}; cb(conn_id, gatt_read_ctp_ccc_status_, handle, value.size(), value.data(), cb_data); return; } uint8_t idx; for (idx = 0; idx < max_num_of_ases; idx++) { if (handle == ascs->sink_ase_char[idx] + 1) { Loading Loading @@ -7638,25 +7652,12 @@ TEST_F(UnicastTest, HandleDatabaseOutOfSync) { InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); // default action for WriteDescriptor function call ON_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) .WillByDefault(Invoke([](uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data) -> void { if (cb) do_in_main_thread( FROM_HERE, base::BindOnce( [](GATT_WRITE_OP_CB cb, uint16_t conn_id, uint16_t handle, uint16_t len, uint8_t* value, void* cb_data) { cb(conn_id, GATT_DATABASE_OUT_OF_SYNC, handle, len, value, cb_data); }, cb, conn_id, handle, value.size(), value.data(), cb_data)); })); /* Simulate DATABASE OUT OF SYNC */ gatt_read_ctp_ccc_status_ = GATT_DATABASE_OUT_OF_SYNC; EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)).Times(0); ON_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)) .WillByDefault(Return()); EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(_, _)); Loading @@ -7664,6 +7665,97 @@ TEST_F(UnicastTest, HandleDatabaseOutOfSync) { InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_interface_); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); } TEST_F(UnicastTest, TestRemoteDeviceKeepCccValues) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, 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); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); /* Simulate remote cache is good */ ccc_stored_byte_val_ = 0x01; EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)).Times(0); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } TEST_F(UnicastTest, TestRemoteDeviceForgetsCccValues) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, 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); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, test_address0)) .Times(1); InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); /* Simulate remote cache is broken */ ccc_stored_byte_val_ = 0; EXPECT_CALL(mock_gatt_queue_, WriteDescriptor(_, _, _, _, _, _)) .Times(AtLeast(1)); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); InjectConnectedEvent(test_address0, 1); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_gatt_queue_); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); } TEST_F(UnicastTest, SpeakerStreamingTimeout) { Loading