Loading system/bta/le_audio/state_machine.cc +1 −0 Original line number Diff line number Diff line Loading @@ -837,6 +837,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } LOG_INFO("Lost all members from the group %d", group->group_id_); group->cises_.clear(); RemoveCigForGroup(group); group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); Loading system/bta/le_audio/state_machine_test.cc +130 −0 Original line number Diff line number Diff line Loading @@ -3814,5 +3814,135 @@ TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) { testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); } TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) { auto context_type = kContextTypeConversational; const auto leaudio_group_id = 4; const auto num_devices = 2; // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup( leaudio_group_id, context_type, num_devices, kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareReceiverStartReady(group); /* Prepare DisconnectCis mock to not symulate CisDisconnection */ ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; while (leAudioDevice) { EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(3); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content context_type = kContextTypeMedia; ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<LeAudioContextType>(context_type), types::AudioContexts(context_type))); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); testing::Mock::VerifyAndClearExpectations(&gatt_queue); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); // Device disconnects due to timeout of CIS leAudioDevice = group->GetFirstDevice(); while (leAudioDevice) { InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); // Disconnect device LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( group, leAudioDevice); leAudioDevice = group->GetNextDevice(leAudioDevice); } LOG(INFO) << "GK A1"; group->ReloadAudioLocations(); group->ReloadAudioDirections(); group->UpdateAudioContextTypeAvailability(); // Start conversational scenario leAudioDevice = group->GetFirstDevice(); int device_cnt = num_devices; while (leAudioDevice) { LOG(INFO) << "GK A11"; leAudioDevice->conn_id_ = device_cnt--; leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED); leAudioDevice = group->GetNextDevice(leAudioDevice); } LOG(INFO) << "GK A2"; InjectInitialIdleNotification(group); group->ReloadAudioLocations(); group->ReloadAudioDirections(); group->UpdateAudioContextTypeAvailability(kContextTypeConversational | kContextTypeMedia); leAudioDevice = group->GetFirstDevice(); expected_devices_written = 0; while (leAudioDevice) { EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Conversational content context_type = kContextTypeConversational; ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<LeAudioContextType>(context_type), types::AudioContexts(context_type))); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); ASSERT_EQ(2, mock_function_count_map["alarm_cancel"]); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); testing::Mock::VerifyAndClearExpectations(&gatt_queue); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } } // namespace internal } // namespace le_audio Loading
system/bta/le_audio/state_machine.cc +1 −0 Original line number Diff line number Diff line Loading @@ -837,6 +837,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } LOG_INFO("Lost all members from the group %d", group->group_id_); group->cises_.clear(); RemoveCigForGroup(group); group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); Loading
system/bta/le_audio/state_machine_test.cc +130 −0 Original line number Diff line number Diff line Loading @@ -3814,5 +3814,135 @@ TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) { testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); } TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) { auto context_type = kContextTypeConversational; const auto leaudio_group_id = 4; const auto num_devices = 2; // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup( leaudio_group_id, context_type, num_devices, kContextTypeConversational | kContextTypeMedia); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareReceiverStartReady(group); /* Prepare DisconnectCis mock to not symulate CisDisconnection */ ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); auto expected_devices_written = 0; while (leAudioDevice) { EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(3); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content context_type = kContextTypeMedia; ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<LeAudioContextType>(context_type), types::AudioContexts(context_type))); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); testing::Mock::VerifyAndClearExpectations(&gatt_queue); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); // Device disconnects due to timeout of CIS leAudioDevice = group->GetFirstDevice(); while (leAudioDevice) { InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); // Disconnect device LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected( group, leAudioDevice); leAudioDevice = group->GetNextDevice(leAudioDevice); } LOG(INFO) << "GK A1"; group->ReloadAudioLocations(); group->ReloadAudioDirections(); group->UpdateAudioContextTypeAvailability(); // Start conversational scenario leAudioDevice = group->GetFirstDevice(); int device_cnt = num_devices; while (leAudioDevice) { LOG(INFO) << "GK A11"; leAudioDevice->conn_id_ = device_cnt--; leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED); leAudioDevice = group->GetNextDevice(leAudioDevice); } LOG(INFO) << "GK A2"; InjectInitialIdleNotification(group); group->ReloadAudioLocations(); group->ReloadAudioDirections(); group->UpdateAudioContextTypeAvailability(kContextTypeConversational | kContextTypeMedia); leAudioDevice = group->GetFirstDevice(); expected_devices_written = 0; while (leAudioDevice) { EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); expected_devices_written++; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Conversational content context_type = kContextTypeConversational; ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<LeAudioContextType>(context_type), types::AudioContexts(context_type))); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); ASSERT_EQ(2, mock_function_count_map["alarm_cancel"]); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); testing::Mock::VerifyAndClearExpectations(&gatt_queue); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } } // namespace internal } // namespace le_audio