Loading system/bta/le_audio/client.cc +3 −3 Original line number Original line Diff line number Diff line Loading @@ -5818,10 +5818,10 @@ class LeAudioClientImpl : public LeAudioClient { case GroupStreamStatus::RELEASING: case GroupStreamStatus::RELEASING: case GroupStreamStatus::SUSPENDING: case GroupStreamStatus::SUSPENDING: if (active_group_id_ != bluetooth::groups::kGroupUnknown && if (active_group_id_ != bluetooth::groups::kGroupUnknown && (active_group_id_ == group->group_id_) && (active_group_id_ == group->group_id_) && !group->IsPendingConfiguration() && !group->IsPendingConfiguration() && (audio_sender_state_ == AudioState::STARTED || (audio_sender_state_ == AudioState::STARTED || audio_receiver_state_ == AudioState::STARTED)) { audio_receiver_state_ == AudioState::STARTED) && group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { /* If releasing state is happening but it was not initiated either by /* If releasing state is happening but it was not initiated either by * reconfiguration or Audio Framework actions either by the Active group change, * reconfiguration or Audio Framework actions either by the Active group change, * it means that it is some internal state machine error. This is very unlikely and * it means that it is some internal state machine error. This is very unlikely and Loading system/bta/le_audio/devices.cc +12 −0 Original line number Original line Diff line number Diff line Loading @@ -719,6 +719,18 @@ bool LeAudioDevice::HaveActiveAse(void) { return iter != ases_.end(); return iter != ases_.end(); } } bool LeAudioDevice::HaveAnyReleasingAse(void) { /* In configuring state when active in Idle or Configured and reconfigure */ auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { if (!ase.active) { return false; } return ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING; }); return iter != ases_.end(); } bool LeAudioDevice::HaveAnyStreamingAses(void) { bool LeAudioDevice::HaveAnyStreamingAses(void) { /* In configuring state when active in Idle or Configured and reconfigure */ /* In configuring state when active in Idle or Configured and reconfigure */ auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { Loading system/bta/le_audio/devices.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -166,6 +166,7 @@ class LeAudioDevice { bool HaveAllActiveAsesSameDataPathState(types::DataPathState state) const; bool HaveAllActiveAsesSameDataPathState(types::DataPathState state) const; bool HaveAnyUnconfiguredAses(void); bool HaveAnyUnconfiguredAses(void); bool HaveAnyStreamingAses(void); bool HaveAnyStreamingAses(void); bool HaveAnyReleasingAse(void); bool IsReadyToCreateStream(void); bool IsReadyToCreateStream(void); bool IsReadyToStream(void) const { bool IsReadyToStream(void) const { return HaveAllActiveAsesCisEst() && return HaveAllActiveAsesCisEst() && Loading system/bta/le_audio/state_machine.cc +17 −3 Original line number Original line Diff line number Diff line Loading @@ -1803,7 +1803,9 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* getDeviceTryingToAttachTheStream(LeAudioDeviceGroup* group) { LeAudioDevice* getDeviceTryingToAttachTheStream(LeAudioDeviceGroup* group) { /* Device which is attaching the stream is just an active device not in /* Device which is attaching the stream is just an active device not in * STREAMING state. the precondition is, that TargetState is Streaming */ * STREAMING state and NOT in the RELEASING state. * The precondition is, that TargetState is Streaming */ log::debug("group_id: {}, targetState: {}", group->group_id_, log::debug("group_id: {}, targetState: {}", group->group_id_, ToString(group->GetTargetState())); ToString(group->GetTargetState())); Loading @@ -1814,8 +1816,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { for (auto dev = group->GetFirstActiveDevice(); dev != nullptr; for (auto dev = group->GetFirstActiveDevice(); dev != nullptr; dev = group->GetNextActiveDevice(dev)) { dev = group->GetNextActiveDevice(dev)) { if (!dev->HaveAllActiveAsesSameState( if (!dev->HaveAllActiveAsesSameState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) && AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { !dev->HaveAnyReleasingAse()) { log::debug("Attaching device {} to group_id: {}", dev->address_, log::debug("Attaching device {} to group_id: {}", dev->address_, group->group_id_); group->group_id_); return dev; return dev; Loading Loading @@ -3189,6 +3191,18 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { log::debug("Nothing to do ase data path state: {}", log::debug("Nothing to do ase data path state: {}", static_cast<int>(ase->data_path_state)); static_cast<int>(ase->data_path_state)); } } if (group->HaveAllActiveDevicesAsesTheSameState( AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) { group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { log::info("Group {} is doing autonomous release", group->group_id_); SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::RELEASING); } } break; break; } } default: default: Loading system/bta/le_audio/state_machine_test.cc +122 −26 Original line number Original line Diff line number Diff line Loading @@ -747,26 +747,29 @@ class StateMachineTestBase : public Test { group, leAudioDevice); group, leAudioDevice); } } void InjectReleasingAndIdleState(LeAudioDeviceGroup* group, void InjectReleasingAndIdleState(LeAudioDeviceGroup* group, LeAudioDevice* device, LeAudioDevice* device) { bool release = true, bool idle = true) { for (auto& ase : device->ases_) { for (auto& ase : device->ases_) { if (ase.id == bluetooth::le_audio::types::ase::kAseIdInvalid) { if (ase.id == bluetooth::le_audio::types::ase::kAseIdInvalid) { continue; continue; } } // Simulate autonomus RELEASE and moving to IDLE state // Simulate autonomus RELEASE and moving to IDLE state InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, if (release) { nullptr); InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, nullptr); InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, } nullptr); if (idle) { InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, nullptr); } } } } } void InjectReleaseAndIdleStateForAGroup(LeAudioDeviceGroup* group) { void InjectReleaseAndIdleStateForAGroup(LeAudioDeviceGroup* group, bool release = true, bool idle = true) { auto leAudioDevice = group->GetFirstActiveDevice(); auto leAudioDevice = group->GetFirstActiveDevice(); while (leAudioDevice) { while (leAudioDevice) { log::info("Group : {}, dev: {}", group->group_id_, log::info("Group : {}, dev: {}", group->group_id_, leAudioDevice->address_); leAudioDevice->address_); InjectReleasingAndIdleState(group, leAudioDevice); InjectReleasingAndIdleState(group, leAudioDevice, release, idle); leAudioDevice = group->GetNextActiveDevice(leAudioDevice); leAudioDevice = group->GetNextActiveDevice(leAudioDevice); } } } } Loading Loading @@ -3996,6 +3999,117 @@ TEST_F(StateMachineTest, testReleaseMultiple) { ASSERT_EQ(1, get_func_call_count("alarm_cancel")); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } } static void InjectCisDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, uint8_t reason, bool first_cis_disconnect_only = false) { bluetooth::hci::iso_manager::cis_disconnected_evt event; for (auto const ase : leAudioDevice->ases_) { if (ase.cis_state != types::CisState::ASSIGNED && ase.cis_state != types::CisState::IDLE) { event.reason = reason; event.cig_id = group->group_id_; event.cis_conn_hdl = ase.cis_conn_hdl; LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(group, leAudioDevice, &event); if (first_cis_disconnect_only) { break; } } } } TEST_F(StateMachineTest, testAutonomousReleaseMultiple) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto num_devices = 2; // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* firstDevice = leAudioDevice; LeAudioDevice* secondDevice; /* * 1. Codec Config * 2. QoS Config * 3. Enable */ 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++; secondDevice = leAudioDevice; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)) .Times(1); // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream(group, context_type, {.sink = types::AudioContexts(context_type), .source = 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, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); // Validate GroupStreamStatus EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)) .Times(1); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::IDLE)) .Times(1); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)) .Times(0); // Do not take any actions on DisconnectCis. Later it will be injected. ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); log::info("Inject Release of all ASEs"); // Inject Release state from remove InjectReleaseAndIdleStateForAGroup(group, true, false); ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); log::info("Inject CIS Disconnected Event"); // Inject CIS Disconnection from remote InjectCisDisconnected(group, firstDevice, HCI_ERR_PEER_USER); InjectCisDisconnected(group, secondDevice, HCI_ERR_PEER_USER); // Inject Idle ASE InjectReleaseAndIdleStateForAGroup(group, false, true); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { const auto context_type = kContextTypeMedia; const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto leaudio_group_id = 6; Loading Loading @@ -4995,24 +5109,6 @@ TEST_F(StateMachineTestAdsp, testStreamConfigurationAdspDownMix) { // Note: The actual channel mixing is verified by the CodecManager unit tests. // Note: The actual channel mixing is verified by the CodecManager unit tests. } } static void InjectCisDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, uint8_t reason, bool first_cis_disconnect_only = false) { bluetooth::hci::iso_manager::cis_disconnected_evt event; for (auto const ase : leAudioDevice->ases_) { if (ase.cis_state != types::CisState::ASSIGNED && ase.cis_state != types::CisState::IDLE) { event.reason = reason; event.cig_id = group->group_id_; event.cis_conn_hdl = ase.cis_conn_hdl; LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected( group, leAudioDevice, &event); if (first_cis_disconnect_only) break; } } } TEST_F(StateMachineTest, testAttachDeviceToTheStream) { TEST_F(StateMachineTest, testAttachDeviceToTheStream) { const auto context_type = kContextTypeMedia; const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto leaudio_group_id = 6; Loading Loading
system/bta/le_audio/client.cc +3 −3 Original line number Original line Diff line number Diff line Loading @@ -5818,10 +5818,10 @@ class LeAudioClientImpl : public LeAudioClient { case GroupStreamStatus::RELEASING: case GroupStreamStatus::RELEASING: case GroupStreamStatus::SUSPENDING: case GroupStreamStatus::SUSPENDING: if (active_group_id_ != bluetooth::groups::kGroupUnknown && if (active_group_id_ != bluetooth::groups::kGroupUnknown && (active_group_id_ == group->group_id_) && (active_group_id_ == group->group_id_) && !group->IsPendingConfiguration() && !group->IsPendingConfiguration() && (audio_sender_state_ == AudioState::STARTED || (audio_sender_state_ == AudioState::STARTED || audio_receiver_state_ == AudioState::STARTED)) { audio_receiver_state_ == AudioState::STARTED) && group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { /* If releasing state is happening but it was not initiated either by /* If releasing state is happening but it was not initiated either by * reconfiguration or Audio Framework actions either by the Active group change, * reconfiguration or Audio Framework actions either by the Active group change, * it means that it is some internal state machine error. This is very unlikely and * it means that it is some internal state machine error. This is very unlikely and Loading
system/bta/le_audio/devices.cc +12 −0 Original line number Original line Diff line number Diff line Loading @@ -719,6 +719,18 @@ bool LeAudioDevice::HaveActiveAse(void) { return iter != ases_.end(); return iter != ases_.end(); } } bool LeAudioDevice::HaveAnyReleasingAse(void) { /* In configuring state when active in Idle or Configured and reconfigure */ auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { if (!ase.active) { return false; } return ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING; }); return iter != ases_.end(); } bool LeAudioDevice::HaveAnyStreamingAses(void) { bool LeAudioDevice::HaveAnyStreamingAses(void) { /* In configuring state when active in Idle or Configured and reconfigure */ /* In configuring state when active in Idle or Configured and reconfigure */ auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { auto iter = std::find_if(ases_.begin(), ases_.end(), [](const auto& ase) { Loading
system/bta/le_audio/devices.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -166,6 +166,7 @@ class LeAudioDevice { bool HaveAllActiveAsesSameDataPathState(types::DataPathState state) const; bool HaveAllActiveAsesSameDataPathState(types::DataPathState state) const; bool HaveAnyUnconfiguredAses(void); bool HaveAnyUnconfiguredAses(void); bool HaveAnyStreamingAses(void); bool HaveAnyStreamingAses(void); bool HaveAnyReleasingAse(void); bool IsReadyToCreateStream(void); bool IsReadyToCreateStream(void); bool IsReadyToStream(void) const { bool IsReadyToStream(void) const { return HaveAllActiveAsesCisEst() && return HaveAllActiveAsesCisEst() && Loading
system/bta/le_audio/state_machine.cc +17 −3 Original line number Original line Diff line number Diff line Loading @@ -1803,7 +1803,9 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* getDeviceTryingToAttachTheStream(LeAudioDeviceGroup* group) { LeAudioDevice* getDeviceTryingToAttachTheStream(LeAudioDeviceGroup* group) { /* Device which is attaching the stream is just an active device not in /* Device which is attaching the stream is just an active device not in * STREAMING state. the precondition is, that TargetState is Streaming */ * STREAMING state and NOT in the RELEASING state. * The precondition is, that TargetState is Streaming */ log::debug("group_id: {}, targetState: {}", group->group_id_, log::debug("group_id: {}, targetState: {}", group->group_id_, ToString(group->GetTargetState())); ToString(group->GetTargetState())); Loading @@ -1814,8 +1816,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { for (auto dev = group->GetFirstActiveDevice(); dev != nullptr; for (auto dev = group->GetFirstActiveDevice(); dev != nullptr; dev = group->GetNextActiveDevice(dev)) { dev = group->GetNextActiveDevice(dev)) { if (!dev->HaveAllActiveAsesSameState( if (!dev->HaveAllActiveAsesSameState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) && AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) { !dev->HaveAnyReleasingAse()) { log::debug("Attaching device {} to group_id: {}", dev->address_, log::debug("Attaching device {} to group_id: {}", dev->address_, group->group_id_); group->group_id_); return dev; return dev; Loading Loading @@ -3189,6 +3191,18 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { log::debug("Nothing to do ase data path state: {}", log::debug("Nothing to do ase data path state: {}", static_cast<int>(ase->data_path_state)); static_cast<int>(ase->data_path_state)); } } if (group->HaveAllActiveDevicesAsesTheSameState( AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) { group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { log::info("Group {} is doing autonomous release", group->group_id_); SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::RELEASING); } } break; break; } } default: default: Loading
system/bta/le_audio/state_machine_test.cc +122 −26 Original line number Original line Diff line number Diff line Loading @@ -747,26 +747,29 @@ class StateMachineTestBase : public Test { group, leAudioDevice); group, leAudioDevice); } } void InjectReleasingAndIdleState(LeAudioDeviceGroup* group, void InjectReleasingAndIdleState(LeAudioDeviceGroup* group, LeAudioDevice* device, LeAudioDevice* device) { bool release = true, bool idle = true) { for (auto& ase : device->ases_) { for (auto& ase : device->ases_) { if (ase.id == bluetooth::le_audio::types::ase::kAseIdInvalid) { if (ase.id == bluetooth::le_audio::types::ase::kAseIdInvalid) { continue; continue; } } // Simulate autonomus RELEASE and moving to IDLE state // Simulate autonomus RELEASE and moving to IDLE state InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, if (release) { nullptr); InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing, nullptr); InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, } nullptr); if (idle) { InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, nullptr); } } } } } void InjectReleaseAndIdleStateForAGroup(LeAudioDeviceGroup* group) { void InjectReleaseAndIdleStateForAGroup(LeAudioDeviceGroup* group, bool release = true, bool idle = true) { auto leAudioDevice = group->GetFirstActiveDevice(); auto leAudioDevice = group->GetFirstActiveDevice(); while (leAudioDevice) { while (leAudioDevice) { log::info("Group : {}, dev: {}", group->group_id_, log::info("Group : {}, dev: {}", group->group_id_, leAudioDevice->address_); leAudioDevice->address_); InjectReleasingAndIdleState(group, leAudioDevice); InjectReleasingAndIdleState(group, leAudioDevice, release, idle); leAudioDevice = group->GetNextActiveDevice(leAudioDevice); leAudioDevice = group->GetNextActiveDevice(leAudioDevice); } } } } Loading Loading @@ -3996,6 +3999,117 @@ TEST_F(StateMachineTest, testReleaseMultiple) { ASSERT_EQ(1, get_func_call_count("alarm_cancel")); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } } static void InjectCisDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, uint8_t reason, bool first_cis_disconnect_only = false) { bluetooth::hci::iso_manager::cis_disconnected_evt event; for (auto const ase : leAudioDevice->ases_) { if (ase.cis_state != types::CisState::ASSIGNED && ase.cis_state != types::CisState::IDLE) { event.reason = reason; event.cig_id = group->group_id_; event.cis_conn_hdl = ase.cis_conn_hdl; LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(group, leAudioDevice, &event); if (first_cis_disconnect_only) { break; } } } } TEST_F(StateMachineTest, testAutonomousReleaseMultiple) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto num_devices = 2; // Prepare multiple fake connected devices in a group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* firstDevice = leAudioDevice; LeAudioDevice* secondDevice; /* * 1. Codec Config * 2. QoS Config * 3. Enable */ 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++; secondDevice = leAudioDevice; leAudioDevice = group->GetNextDevice(leAudioDevice); } ASSERT_EQ(expected_devices_written, num_devices); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1); InjectInitialIdleNotification(group); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)) .Times(1); // Start the configuration and stream Media content LeAudioGroupStateMachine::Get()->StartStream(group, context_type, {.sink = types::AudioContexts(context_type), .source = 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, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); reset_mock_function_count_map(); // Validate GroupStreamStatus EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)) .Times(1); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::IDLE)) .Times(1); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)) .Times(0); // Do not take any actions on DisconnectCis. Later it will be injected. ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); log::info("Inject Release of all ASEs"); // Inject Release state from remove InjectReleaseAndIdleStateForAGroup(group, true, false); ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); log::info("Inject CIS Disconnected Event"); // Inject CIS Disconnection from remote InjectCisDisconnected(group, firstDevice, HCI_ERR_PEER_USER); InjectCisDisconnected(group, secondDevice, HCI_ERR_PEER_USER); // Inject Idle ASE InjectReleaseAndIdleStateForAGroup(group, false, true); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(1, get_func_call_count("alarm_cancel")); } TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) { const auto context_type = kContextTypeMedia; const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto leaudio_group_id = 6; Loading Loading @@ -4995,24 +5109,6 @@ TEST_F(StateMachineTestAdsp, testStreamConfigurationAdspDownMix) { // Note: The actual channel mixing is verified by the CodecManager unit tests. // Note: The actual channel mixing is verified by the CodecManager unit tests. } } static void InjectCisDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, uint8_t reason, bool first_cis_disconnect_only = false) { bluetooth::hci::iso_manager::cis_disconnected_evt event; for (auto const ase : leAudioDevice->ases_) { if (ase.cis_state != types::CisState::ASSIGNED && ase.cis_state != types::CisState::IDLE) { event.reason = reason; event.cig_id = group->group_id_; event.cis_conn_hdl = ase.cis_conn_hdl; LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected( group, leAudioDevice, &event); if (first_cis_disconnect_only) break; } } } TEST_F(StateMachineTest, testAttachDeviceToTheStream) { TEST_F(StateMachineTest, testAttachDeviceToTheStream) { const auto context_type = kContextTypeMedia; const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto leaudio_group_id = 6; Loading