Loading system/bta/le_audio/devices.cc +90 −0 Original line number Diff line number Diff line Loading @@ -1821,6 +1821,20 @@ bool LeAudioDeviceGroup::IsMetadataChanged( return false; } bool LeAudioDeviceGroup::IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) { auto iter = std::find_if( stream_conf.sink_streams.begin(), stream_conf.sink_streams.end(), [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); if (iter != stream_conf.sink_streams.end()) return true; iter = std::find_if( stream_conf.source_streams.begin(), stream_conf.source_streams.end(), [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); return iter != stream_conf.sink_streams.end(); } void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) { if (direction == le_audio::types::kLeAudioDirectionSource) { stream_conf.source_is_initial = false; Loading @@ -1829,6 +1843,82 @@ void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) { } } void LeAudioDeviceGroup::RemoveCisFromStreamIfNeeded( LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) { LOG_INFO(" CIS Connection Handle: %d", cis_conn_hdl); if (!IsCisPartOfCurrentStream(cis_conn_hdl)) return; auto sink_channels = stream_conf.sink_num_of_channels; auto source_channels = stream_conf.source_num_of_channels; if (!stream_conf.sink_streams.empty() || !stream_conf.source_streams.empty()) { stream_conf.sink_streams.erase( std::remove_if( stream_conf.sink_streams.begin(), stream_conf.sink_streams.end(), [leAudioDevice, &cis_conn_hdl, this](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.sink && cis_conn_hdl == pair.first) { stream_conf.sink_num_of_devices--; stream_conf.sink_num_of_channels -= ases_pair.sink->codec_config.channel_count; stream_conf.sink_audio_channel_allocation &= ~pair.second; } return (ases_pair.sink && cis_conn_hdl == pair.first); }), stream_conf.sink_streams.end()); stream_conf.source_streams.erase( std::remove_if( stream_conf.source_streams.begin(), stream_conf.source_streams.end(), [leAudioDevice, &cis_conn_hdl, this](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.source && cis_conn_hdl == pair.first) { stream_conf.source_num_of_devices--; stream_conf.source_num_of_channels -= ases_pair.source->codec_config.channel_count; stream_conf.source_audio_channel_allocation &= ~pair.second; } return (ases_pair.source && cis_conn_hdl == pair.first); }), stream_conf.source_streams.end()); LOG_INFO( " Sink Number Of Devices: %d" ", Sink Number Of Channels: %d" ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", stream_conf.sink_num_of_devices, stream_conf.sink_num_of_channels, stream_conf.source_num_of_devices, stream_conf.source_num_of_channels); } if (stream_conf.sink_num_of_channels == 0) { ClearSinksFromConfiguration(); } if (stream_conf.source_num_of_channels == 0) { ClearSourcesFromConfiguration(); } /* Update offloader streams if needed */ if (sink_channels > stream_conf.sink_num_of_channels) { CreateStreamVectorForOffloader(le_audio::types::kLeAudioDirectionSink); } if (source_channels > stream_conf.source_num_of_channels) { CreateStreamVectorForOffloader(le_audio::types::kLeAudioDirectionSource); } CigUnassignCis(leAudioDevice); } void LeAudioDeviceGroup::CreateStreamVectorForOffloader(uint8_t direction) { if (CodecManager::GetInstance()->GetCodecLocation() != le_audio::types::CodecLocation::ADSP) { Loading system/bta/le_audio/devices.h +3 −0 Original line number Diff line number Diff line Loading @@ -385,6 +385,8 @@ class LeAudioDeviceGroup { void CreateStreamVectorForOffloader(uint8_t direction); void StreamOffloaderUpdated(uint8_t direction); bool IsConfiguredForContext(types::LeAudioContextType context_type); void RemoveCisFromStreamIfNeeded(LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl); inline types::AseState GetState(void) const { return current_state_; } void SetState(types::AseState state) { Loading Loading @@ -461,6 +463,7 @@ class LeAudioDeviceGroup { types::LeAudioContextType context_type, types::LeAudioConfigurationStrategy required_snk_strategy); uint32_t GetTransportLatencyUs(uint8_t direction); bool IsCisPartOfCurrentStream(uint16_t cis_conn_hdl); /* Current configuration and metadata context types */ types::LeAudioContextType configuration_context_type_; Loading system/bta/le_audio/state_machine.cc +13 −89 Original line number Diff line number Diff line Loading @@ -583,7 +583,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } if (do_disconnect) { RemoveCisFromStreamConfiguration(group, leAudioDevice, conn_hdl); group->RemoveCisFromStreamIfNeeded(leAudioDevice, conn_hdl); IsoManager::GetInstance()->DisconnectCis(conn_hdl, HCI_ERR_PEER_USER); log_history_->AddLogHistory( Loading Loading @@ -647,17 +647,24 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void ProcessHciNotifAclDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) { FreeLinkQualityReports(leAudioDevice); /* mark ASEs as not used. */ leAudioDevice->DeactivateAllAses(); if (!group) { LOG(ERROR) << __func__ << " group is null for device: " << ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_) << " group_id: " << leAudioDevice->group_id_; /* mark ASEs as not used. */ leAudioDevice->DeactivateAllAses(); return; } /* It is possible that ACL disconnection came before CIS disconnect event */ for (auto& ase : leAudioDevice->ases_) { group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase.cis_conn_hdl); } /* mark ASEs as not used. */ leAudioDevice->DeactivateAllAses(); /* If group is in Idle and not transitioning, update the current group * audio context availability which could change due to disconnected group * member. Loading Loading @@ -905,7 +912,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AudioStreamDataPathState::CIS_ASSIGNED; } RemoveCisFromStreamConfiguration(group, leAudioDevice, event->cis_conn_hdl); group->RemoveCisFromStreamIfNeeded(leAudioDevice, event->cis_conn_hdl); auto target_state = group->GetTargetState(); switch (target_state) { Loading Loading @@ -1230,89 +1237,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { group->CreateStreamVectorForOffloader(ase->direction); } void RemoveCisFromStreamConfiguration(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) { auto* stream_conf = &group->stream_conf; LOG_INFO(" CIS Connection Handle: %d", cis_conn_hdl); auto sink_channels = stream_conf->sink_num_of_channels; auto source_channels = stream_conf->source_num_of_channels; if (!stream_conf->sink_streams.empty() || !stream_conf->source_streams.empty()) { stream_conf->sink_streams.erase( std::remove_if( stream_conf->sink_streams.begin(), stream_conf->sink_streams.end(), [leAudioDevice, &cis_conn_hdl, &stream_conf](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.sink && cis_conn_hdl == pair.first) { stream_conf->sink_num_of_devices--; stream_conf->sink_num_of_channels -= ases_pair.sink->codec_config.channel_count; stream_conf->sink_audio_channel_allocation &= ~pair.second; } return (ases_pair.sink && cis_conn_hdl == pair.first); }), stream_conf->sink_streams.end()); stream_conf->source_streams.erase( std::remove_if( stream_conf->source_streams.begin(), stream_conf->source_streams.end(), [leAudioDevice, &cis_conn_hdl, &stream_conf](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.source && cis_conn_hdl == pair.first) { stream_conf->source_num_of_devices--; stream_conf->source_num_of_channels -= ases_pair.source->codec_config.channel_count; stream_conf->source_audio_channel_allocation &= ~pair.second; } return (ases_pair.source && cis_conn_hdl == pair.first); }), stream_conf->source_streams.end()); LOG_INFO( " Sink Number Of Devices: %d" ", Sink Number Of Channels: %d" ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", stream_conf->sink_num_of_devices, stream_conf->sink_num_of_channels, stream_conf->source_num_of_devices, stream_conf->source_num_of_channels); } if (stream_conf->sink_num_of_channels == 0) { group->ClearSinksFromConfiguration(); } if (stream_conf->source_num_of_channels == 0) { group->ClearSourcesFromConfiguration(); } /* Update offloader streams if needed */ if (sink_channels > stream_conf->sink_num_of_channels) { group->CreateStreamVectorForOffloader( le_audio::types::kLeAudioDirectionSink); } if (source_channels > stream_conf->source_num_of_channels) { group->CreateStreamVectorForOffloader( le_audio::types::kLeAudioDirectionSource); } group->CigUnassignCis(leAudioDevice); } bool CigCreate(LeAudioDeviceGroup* group) { uint32_t sdu_interval_mtos, sdu_interval_stom; uint16_t max_trans_lat_mtos, max_trans_lat_stom; Loading Loading @@ -2762,7 +2686,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); log_history_->AddLogHistory( Loading system/bta/le_audio/state_machine_test.cc +71 −0 Original line number Diff line number Diff line Loading @@ -4633,5 +4633,76 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) { ASSERT_NE(ase->retrans_nb, 0); } TEST_F(StateMachineTest, testAclDropWithoutApriorCisDisconnection) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto num_devices = 2; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // 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); PrepareDisableHandler(group); PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* firstDevice = leAudioDevice; LeAudioDevice* lastDevice = leAudioDevice; auto expected_devices_written = 0; while (leAudioDevice) { /* Three Writes: * 1: Codec Config * 2: Codec QoS * 3: Enabling */ lastDevice = leAudioDevice; EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(AtLeast(3)); expected_devices_written++; 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); InjectInitialIdleNotification(group); // 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); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); /* Separate CIS for dual CIS device is treated as sink device */ ASSERT_EQ(group->stream_conf.sink_num_of_devices, 2); ASSERT_EQ(group->stream_conf.sink_num_of_channels, 2); // Inject CIS and ACL disconnection of first device InjectAclDisconnected(group, firstDevice); InjectCisDisconnected(group, lastDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); InjectAclDisconnected(group, lastDevice); ASSERT_EQ(group->stream_conf.sink_num_of_devices, 0); ASSERT_EQ(group->stream_conf.sink_num_of_channels, 0); } } // namespace internal } // namespace le_audio Loading
system/bta/le_audio/devices.cc +90 −0 Original line number Diff line number Diff line Loading @@ -1821,6 +1821,20 @@ bool LeAudioDeviceGroup::IsMetadataChanged( return false; } bool LeAudioDeviceGroup::IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) { auto iter = std::find_if( stream_conf.sink_streams.begin(), stream_conf.sink_streams.end(), [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); if (iter != stream_conf.sink_streams.end()) return true; iter = std::find_if( stream_conf.source_streams.begin(), stream_conf.source_streams.end(), [cis_conn_hdl](auto& pair) { return cis_conn_hdl == pair.first; }); return iter != stream_conf.sink_streams.end(); } void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) { if (direction == le_audio::types::kLeAudioDirectionSource) { stream_conf.source_is_initial = false; Loading @@ -1829,6 +1843,82 @@ void LeAudioDeviceGroup::StreamOffloaderUpdated(uint8_t direction) { } } void LeAudioDeviceGroup::RemoveCisFromStreamIfNeeded( LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) { LOG_INFO(" CIS Connection Handle: %d", cis_conn_hdl); if (!IsCisPartOfCurrentStream(cis_conn_hdl)) return; auto sink_channels = stream_conf.sink_num_of_channels; auto source_channels = stream_conf.source_num_of_channels; if (!stream_conf.sink_streams.empty() || !stream_conf.source_streams.empty()) { stream_conf.sink_streams.erase( std::remove_if( stream_conf.sink_streams.begin(), stream_conf.sink_streams.end(), [leAudioDevice, &cis_conn_hdl, this](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.sink && cis_conn_hdl == pair.first) { stream_conf.sink_num_of_devices--; stream_conf.sink_num_of_channels -= ases_pair.sink->codec_config.channel_count; stream_conf.sink_audio_channel_allocation &= ~pair.second; } return (ases_pair.sink && cis_conn_hdl == pair.first); }), stream_conf.sink_streams.end()); stream_conf.source_streams.erase( std::remove_if( stream_conf.source_streams.begin(), stream_conf.source_streams.end(), [leAudioDevice, &cis_conn_hdl, this](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.source && cis_conn_hdl == pair.first) { stream_conf.source_num_of_devices--; stream_conf.source_num_of_channels -= ases_pair.source->codec_config.channel_count; stream_conf.source_audio_channel_allocation &= ~pair.second; } return (ases_pair.source && cis_conn_hdl == pair.first); }), stream_conf.source_streams.end()); LOG_INFO( " Sink Number Of Devices: %d" ", Sink Number Of Channels: %d" ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", stream_conf.sink_num_of_devices, stream_conf.sink_num_of_channels, stream_conf.source_num_of_devices, stream_conf.source_num_of_channels); } if (stream_conf.sink_num_of_channels == 0) { ClearSinksFromConfiguration(); } if (stream_conf.source_num_of_channels == 0) { ClearSourcesFromConfiguration(); } /* Update offloader streams if needed */ if (sink_channels > stream_conf.sink_num_of_channels) { CreateStreamVectorForOffloader(le_audio::types::kLeAudioDirectionSink); } if (source_channels > stream_conf.source_num_of_channels) { CreateStreamVectorForOffloader(le_audio::types::kLeAudioDirectionSource); } CigUnassignCis(leAudioDevice); } void LeAudioDeviceGroup::CreateStreamVectorForOffloader(uint8_t direction) { if (CodecManager::GetInstance()->GetCodecLocation() != le_audio::types::CodecLocation::ADSP) { Loading
system/bta/le_audio/devices.h +3 −0 Original line number Diff line number Diff line Loading @@ -385,6 +385,8 @@ class LeAudioDeviceGroup { void CreateStreamVectorForOffloader(uint8_t direction); void StreamOffloaderUpdated(uint8_t direction); bool IsConfiguredForContext(types::LeAudioContextType context_type); void RemoveCisFromStreamIfNeeded(LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl); inline types::AseState GetState(void) const { return current_state_; } void SetState(types::AseState state) { Loading Loading @@ -461,6 +463,7 @@ class LeAudioDeviceGroup { types::LeAudioContextType context_type, types::LeAudioConfigurationStrategy required_snk_strategy); uint32_t GetTransportLatencyUs(uint8_t direction); bool IsCisPartOfCurrentStream(uint16_t cis_conn_hdl); /* Current configuration and metadata context types */ types::LeAudioContextType configuration_context_type_; Loading
system/bta/le_audio/state_machine.cc +13 −89 Original line number Diff line number Diff line Loading @@ -583,7 +583,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } if (do_disconnect) { RemoveCisFromStreamConfiguration(group, leAudioDevice, conn_hdl); group->RemoveCisFromStreamIfNeeded(leAudioDevice, conn_hdl); IsoManager::GetInstance()->DisconnectCis(conn_hdl, HCI_ERR_PEER_USER); log_history_->AddLogHistory( Loading Loading @@ -647,17 +647,24 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { void ProcessHciNotifAclDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) { FreeLinkQualityReports(leAudioDevice); /* mark ASEs as not used. */ leAudioDevice->DeactivateAllAses(); if (!group) { LOG(ERROR) << __func__ << " group is null for device: " << ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_) << " group_id: " << leAudioDevice->group_id_; /* mark ASEs as not used. */ leAudioDevice->DeactivateAllAses(); return; } /* It is possible that ACL disconnection came before CIS disconnect event */ for (auto& ase : leAudioDevice->ases_) { group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase.cis_conn_hdl); } /* mark ASEs as not used. */ leAudioDevice->DeactivateAllAses(); /* If group is in Idle and not transitioning, update the current group * audio context availability which could change due to disconnected group * member. Loading Loading @@ -905,7 +912,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { AudioStreamDataPathState::CIS_ASSIGNED; } RemoveCisFromStreamConfiguration(group, leAudioDevice, event->cis_conn_hdl); group->RemoveCisFromStreamIfNeeded(leAudioDevice, event->cis_conn_hdl); auto target_state = group->GetTargetState(); switch (target_state) { Loading Loading @@ -1230,89 +1237,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { group->CreateStreamVectorForOffloader(ase->direction); } void RemoveCisFromStreamConfiguration(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) { auto* stream_conf = &group->stream_conf; LOG_INFO(" CIS Connection Handle: %d", cis_conn_hdl); auto sink_channels = stream_conf->sink_num_of_channels; auto source_channels = stream_conf->source_num_of_channels; if (!stream_conf->sink_streams.empty() || !stream_conf->source_streams.empty()) { stream_conf->sink_streams.erase( std::remove_if( stream_conf->sink_streams.begin(), stream_conf->sink_streams.end(), [leAudioDevice, &cis_conn_hdl, &stream_conf](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.sink && cis_conn_hdl == pair.first) { stream_conf->sink_num_of_devices--; stream_conf->sink_num_of_channels -= ases_pair.sink->codec_config.channel_count; stream_conf->sink_audio_channel_allocation &= ~pair.second; } return (ases_pair.sink && cis_conn_hdl == pair.first); }), stream_conf->sink_streams.end()); stream_conf->source_streams.erase( std::remove_if( stream_conf->source_streams.begin(), stream_conf->source_streams.end(), [leAudioDevice, &cis_conn_hdl, &stream_conf](auto& pair) { if (!cis_conn_hdl) { cis_conn_hdl = pair.first; } auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl); if (ases_pair.source && cis_conn_hdl == pair.first) { stream_conf->source_num_of_devices--; stream_conf->source_num_of_channels -= ases_pair.source->codec_config.channel_count; stream_conf->source_audio_channel_allocation &= ~pair.second; } return (ases_pair.source && cis_conn_hdl == pair.first); }), stream_conf->source_streams.end()); LOG_INFO( " Sink Number Of Devices: %d" ", Sink Number Of Channels: %d" ", Source Number Of Devices: %d" ", Source Number Of Channels: %d", stream_conf->sink_num_of_devices, stream_conf->sink_num_of_channels, stream_conf->source_num_of_devices, stream_conf->source_num_of_channels); } if (stream_conf->sink_num_of_channels == 0) { group->ClearSinksFromConfiguration(); } if (stream_conf->source_num_of_channels == 0) { group->ClearSourcesFromConfiguration(); } /* Update offloader streams if needed */ if (sink_channels > stream_conf->sink_num_of_channels) { group->CreateStreamVectorForOffloader( le_audio::types::kLeAudioDirectionSink); } if (source_channels > stream_conf->source_num_of_channels) { group->CreateStreamVectorForOffloader( le_audio::types::kLeAudioDirectionSource); } group->CigUnassignCis(leAudioDevice); } bool CigCreate(LeAudioDeviceGroup* group) { uint32_t sdu_interval_mtos, sdu_interval_stom; uint16_t max_trans_lat_mtos, max_trans_lat_stom; Loading Loading @@ -2762,7 +2686,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } RemoveCisFromStreamConfiguration(group, leAudioDevice, ase->cis_conn_hdl); group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase->cis_conn_hdl); IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER); log_history_->AddLogHistory( Loading
system/bta/le_audio/state_machine_test.cc +71 −0 Original line number Diff line number Diff line Loading @@ -4633,5 +4633,76 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) { ASSERT_NE(ase->retrans_nb, 0); } TEST_F(StateMachineTest, testAclDropWithoutApriorCisDisconnection) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; const auto num_devices = 2; ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); // 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); PrepareDisableHandler(group); PrepareReleaseHandler(group); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* firstDevice = leAudioDevice; LeAudioDevice* lastDevice = leAudioDevice; auto expected_devices_written = 0; while (leAudioDevice) { /* Three Writes: * 1: Codec Config * 2: Codec QoS * 3: Enabling */ lastDevice = leAudioDevice; EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(AtLeast(3)); expected_devices_written++; 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); InjectInitialIdleNotification(group); // 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); testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); /* Separate CIS for dual CIS device is treated as sink device */ ASSERT_EQ(group->stream_conf.sink_num_of_devices, 2); ASSERT_EQ(group->stream_conf.sink_num_of_channels, 2); // Inject CIS and ACL disconnection of first device InjectAclDisconnected(group, firstDevice); InjectCisDisconnected(group, lastDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST); InjectAclDisconnected(group, lastDevice); ASSERT_EQ(group->stream_conf.sink_num_of_devices, 0); ASSERT_EQ(group->stream_conf.sink_num_of_channels, 0); } } // namespace internal } // namespace le_audio