Loading system/bta/le_audio/state_machine.cc +29 −4 Original line number Diff line number Diff line Loading @@ -2427,6 +2427,34 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } } void DisconnectCisIfNeeded(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, struct ase* ase) { LOG_DEBUG( "Group id: %d, %s, ase id: %d, cis_handle: 0x%04x, direction: %s, " "data_path_state: %s", group->group_id_, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id, ase->cis_conn_hdl, ase->direction == le_audio::types::kLeAudioDirectionSink ? "sink" : "source", bluetooth::common::ToString(ase->data_path_state).c_str()); auto bidirection_ase = leAudioDevice->GetAseToMatchBidirectionCis(ase); if (bidirection_ase != nullptr && bidirection_ase->data_path_state == AudioStreamDataPathState::CIS_ESTABLISHED && (bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING || bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)) { LOG_INFO("Still waiting for the bidirectional ase %d to be released (%s)", bidirection_ase->id, bluetooth::common::ToString(bidirection_ase->state).c_str()); return; } RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); } void AseStateMachineProcessReleasing( struct le_audio::client_parser::ascs::ase_rsp_hdr& arh, struct ase* ase, LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) { Loading Loading @@ -2468,10 +2496,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AudioStreamDataPathState::CIS_ESTABLISHED || ase->data_path_state == AudioStreamDataPathState::CIS_PENDING) { RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); DisconnectCisIfNeeded(group, leAudioDevice, ase); } else { DLOG(INFO) << __func__ << ", Nothing to do ase data path state: " << static_cast<int>(ase->data_path_state); Loading system/bta/le_audio/state_machine_test.cc +92 −1 Original line number Diff line number Diff line Loading @@ -173,6 +173,11 @@ class StateMachineTest : public Test { uint8_t channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel; uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz; /* Use to simulated error status on Cis creation */ bool overwrite_cis_status_; uint8_t overwrite_cis_status_idx_; std::vector<uint8_t> cis_status_; void SetUp() override { bluetooth::common::InitFlags::Load(test_flags); reset_mock_function_count_map(); Loading @@ -181,6 +186,10 @@ class StateMachineTest : public Test { gatt::SetMockBtaGattInterface(&gatt_interface); gatt::SetMockBtaGattQueue(&gatt_queue); overwrite_cis_status_idx_ = 0; overwrite_cis_status_ = false; cis_status_.clear(); ::le_audio::AudioSetConfigurationProvider::Initialize(); LeAudioGroupStateMachine::Initialize(&mock_callbacks_); Loading Loading @@ -369,7 +378,12 @@ class StateMachineTest : public Test { bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt; // Fill proper values if needed evt.status = 0x00; if (overwrite_cis_status_) { evt.status = cis_status_[overwrite_cis_status_idx_++]; } else { evt.status = 0; } evt.cig_id = group->group_id_; evt.cis_conn_hdl = pair.cis_conn_handle; evt.cig_sync_delay = 0; Loading Loading @@ -1644,6 +1658,83 @@ TEST_F(StateMachineTest, testStreamMultipleConversational) { ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); } TEST_F(StateMachineTest, testFailedStreamMultipleConversational) { /* Testing here CIS Failed to be established */ const auto context_type = kContextTypeConversational; const auto leaudio_group_id = 4; const auto num_devices = 2; overwrite_cis_status_ = true; cis_status_.resize(2); cis_status_[0] = 0x00; cis_status_[1] = 0x0e; // Failed to be established // 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); PrepareReceiverStartReady(group); PrepareReleaseHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); /* This check is the major one in this test, as we want to make sure, * it will not be called twice but only once (when both bidirectional ASEs are * not in the STREAMING or ENABLING state) */ EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); /* First device Control Point actions * Codec Config * QoS Config * Enable * Receiver ready * Release */ EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(5); leAudioDevice = group->GetNextDevice(leAudioDevice); /* Second device Control Point actions * Codec Config * QoS Config * Enable (failed on CIS established - therefore no Receiver Ready) * Release */ EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); /* Prepare DisconnectCis mock to not symulate CisDisconnection */ ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); // Start the configuration and stream Media content ASSERT_TRUE(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_IDLE); ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); } TEST_F(StateMachineTest, testStreamMultiple) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 4; Loading Loading
system/bta/le_audio/state_machine.cc +29 −4 Original line number Diff line number Diff line Loading @@ -2427,6 +2427,34 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } } void DisconnectCisIfNeeded(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, struct ase* ase) { LOG_DEBUG( "Group id: %d, %s, ase id: %d, cis_handle: 0x%04x, direction: %s, " "data_path_state: %s", group->group_id_, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id, ase->cis_conn_hdl, ase->direction == le_audio::types::kLeAudioDirectionSink ? "sink" : "source", bluetooth::common::ToString(ase->data_path_state).c_str()); auto bidirection_ase = leAudioDevice->GetAseToMatchBidirectionCis(ase); if (bidirection_ase != nullptr && bidirection_ase->data_path_state == AudioStreamDataPathState::CIS_ESTABLISHED && (bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING || bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)) { LOG_INFO("Still waiting for the bidirectional ase %d to be released (%s)", bidirection_ase->id, bluetooth::common::ToString(bidirection_ase->state).c_str()); return; } RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); } void AseStateMachineProcessReleasing( struct le_audio::client_parser::ascs::ase_rsp_hdr& arh, struct ase* ase, LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) { Loading Loading @@ -2468,10 +2496,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AudioStreamDataPathState::CIS_ESTABLISHED || ase->data_path_state == AudioStreamDataPathState::CIS_PENDING) { RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); DisconnectCisIfNeeded(group, leAudioDevice, ase); } else { DLOG(INFO) << __func__ << ", Nothing to do ase data path state: " << static_cast<int>(ase->data_path_state); Loading
system/bta/le_audio/state_machine_test.cc +92 −1 Original line number Diff line number Diff line Loading @@ -173,6 +173,11 @@ class StateMachineTest : public Test { uint8_t channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel; uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz; /* Use to simulated error status on Cis creation */ bool overwrite_cis_status_; uint8_t overwrite_cis_status_idx_; std::vector<uint8_t> cis_status_; void SetUp() override { bluetooth::common::InitFlags::Load(test_flags); reset_mock_function_count_map(); Loading @@ -181,6 +186,10 @@ class StateMachineTest : public Test { gatt::SetMockBtaGattInterface(&gatt_interface); gatt::SetMockBtaGattQueue(&gatt_queue); overwrite_cis_status_idx_ = 0; overwrite_cis_status_ = false; cis_status_.clear(); ::le_audio::AudioSetConfigurationProvider::Initialize(); LeAudioGroupStateMachine::Initialize(&mock_callbacks_); Loading Loading @@ -369,7 +378,12 @@ class StateMachineTest : public Test { bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt; // Fill proper values if needed evt.status = 0x00; if (overwrite_cis_status_) { evt.status = cis_status_[overwrite_cis_status_idx_++]; } else { evt.status = 0; } evt.cig_id = group->group_id_; evt.cis_conn_hdl = pair.cis_conn_handle; evt.cig_sync_delay = 0; Loading Loading @@ -1644,6 +1658,83 @@ TEST_F(StateMachineTest, testStreamMultipleConversational) { ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); } TEST_F(StateMachineTest, testFailedStreamMultipleConversational) { /* Testing here CIS Failed to be established */ const auto context_type = kContextTypeConversational; const auto leaudio_group_id = 4; const auto num_devices = 2; overwrite_cis_status_ = true; cis_status_.resize(2); cis_status_[0] = 0x00; cis_status_[1] = 0x0e; // Failed to be established // 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); PrepareReceiverStartReady(group); PrepareReleaseHandler(group); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); /* This check is the major one in this test, as we want to make sure, * it will not be called twice but only once (when both bidirectional ASEs are * not in the STREAMING or ENABLING state) */ EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); auto* leAudioDevice = group->GetFirstDevice(); /* First device Control Point actions * Codec Config * QoS Config * Enable * Receiver ready * Release */ EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(5); leAudioDevice = group->GetNextDevice(leAudioDevice); /* Second device Control Point actions * Codec Config * QoS Config * Enable (failed on CIS established - therefore no Receiver Ready) * Release */ EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); /* Prepare DisconnectCis mock to not symulate CisDisconnection */ ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return()); // Start the configuration and stream Media content ASSERT_TRUE(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_IDLE); ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]); } TEST_F(StateMachineTest, testStreamMultiple) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 4; Loading