Loading system/bta/le_audio/devices.cc +6 −4 Original line number Diff line number Diff line Loading @@ -152,11 +152,11 @@ void LeAudioDeviceGroup::Deactivate(void) { } } void LeAudioDeviceGroup::Activate(void) { void LeAudioDeviceGroup::Activate(LeAudioContextType context_type) { for (auto leAudioDevice : leAudioDevices_) { if (leAudioDevice.expired()) continue; leAudioDevice.lock()->ActivateConfiguredAses(); leAudioDevice.lock()->ActivateConfiguredAses(context_type); } } Loading Loading @@ -1023,6 +1023,7 @@ bool LeAudioDevice::ConfigureAses( for (; needed_ase && ase; needed_ase--) { ase->active = true; ase->configured_for_context_type = context_type; active_ases++; if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) Loading Loading @@ -1779,7 +1780,7 @@ AudioContexts LeAudioDevice::SetAvailableContexts(AudioContexts snk_contexts, return updated_contexts; } void LeAudioDevice::ActivateConfiguredAses(void) { void LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) { if (conn_id_ == GATT_INVALID_CONN_ID) { LOG_DEBUG(" Device %s is not connected ", address_.ToString().c_str()); return; Loading @@ -1788,7 +1789,8 @@ void LeAudioDevice::ActivateConfiguredAses(void) { LOG_DEBUG(" Configuring device %s", address_.ToString().c_str()); for (auto& ase : ases_) { if (!ase.active && ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) { ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED && ase.configured_for_context_type == context_type) { LOG_DEBUG(" Ase id %d, cis id %d activated.", ase.id, ase.cis_id); ase.active = true; } Loading system/bta/le_audio/devices.h +2 −2 Original line number Diff line number Diff line Loading @@ -143,7 +143,7 @@ class LeAudioDevice { types::AudioContexts SetAvailableContexts(types::AudioContexts snk_cont_val, types::AudioContexts src_cont_val); void DeactivateAllAses(void); void ActivateConfiguredAses(void); void ActivateConfiguredAses(types::LeAudioContextType context_type); void Dump(int fd); void DisconnectAcl(void); std::vector<uint8_t> GetMetadata(types::LeAudioContextType context_type, Loading Loading @@ -217,7 +217,7 @@ class LeAudioDeviceGroup { int Size(void); int NumOfConnected( types::LeAudioContextType context_type = types::LeAudioContextType::RFU); void Activate(void); void Activate(types::LeAudioContextType context_type); void Deactivate(void); void Cleanup(void); LeAudioDevice* GetFirstDevice(void); Loading system/bta/le_audio/le_audio_types.h +2 −0 Original line number Diff line number Diff line Loading @@ -529,6 +529,7 @@ struct ase { active(false), reconfigure(false), data_path_state(AudioStreamDataPathState::IDLE), configured_for_context_type(LeAudioContextType::UNINITIALIZED), preferred_phy(0), state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} Loading @@ -542,6 +543,7 @@ struct ase { bool active; bool reconfigure; AudioStreamDataPathState data_path_state; LeAudioContextType configured_for_context_type; /* Codec configuration */ LeAudioCodecId codec_id; Loading system/bta/le_audio/state_machine.cc +3 −1 Original line number Diff line number Diff line Loading @@ -153,7 +153,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { switch (group->GetState()) { case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED: if (group->GetCurrentContextType() == context_type) { group->Activate(); group->Activate(context_type); SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); CigCreate(group); return true; Loading Loading @@ -1129,6 +1129,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* leAudioDeviceNext; ase->state = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; ase->active = false; ase->configured_for_context_type = le_audio::types::LeAudioContextType::UNINITIALIZED; if (!leAudioDevice->HaveAllActiveAsesSameState( AseState::BTA_LE_AUDIO_ASE_STATE_IDLE)) { Loading system/bta/le_audio/state_machine_test.cc +99 −7 Original line number Diff line number Diff line Loading @@ -644,6 +644,7 @@ class StateMachineTest : public Test { void MultipleTestDevicePrepare(int leaudio_group_id, uint16_t context_type, uint16_t device_cnt, uint16_t update_context_type, bool insert_default_pac_records = true) { // Prepare fake connected device group bool first_connections = true; Loading Loading @@ -680,8 +681,10 @@ class StateMachineTest : public Test { uint16_t attr_handle = ATTR_HANDLE_PACS_POOL_START; /* As per spec, unspecified shall be supported */ types::AudioContexts snk_context_type = kContextTypeUnspecified; types::AudioContexts src_context_type = kContextTypeUnspecified; types::AudioContexts snk_context_type = kContextTypeUnspecified | update_context_type; types::AudioContexts src_context_type = kContextTypeUnspecified | update_context_type; // Prepare Sink Published Audio Capability records if ((context_type & kContextTypeRingtone) || Loading Loading @@ -743,17 +746,20 @@ class StateMachineTest : public Test { } /* Stimulate update of active context map */ types::AudioContexts type_set = static_cast<uint16_t>(context_type); types::AudioContexts type_set = static_cast<uint16_t>( update_context_type == 0 ? context_type : context_type | update_context_type); group->UpdateActiveContextsMap(type_set); ASSERT_NE(group, nullptr); ASSERT_EQ(group->Size(), total_devices); } LeAudioDeviceGroup* PrepareSingleTestDeviceGroup(int leaudio_group_id, uint16_t context_type, uint16_t device_cnt = 1) { MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt); LeAudioDeviceGroup* PrepareSingleTestDeviceGroup( int leaudio_group_id, uint16_t context_type, uint16_t device_cnt = 1, uint16_t update_context_type = 0) { MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt, update_context_type); return le_audio_device_groups_.count(leaudio_group_id) ? le_audio_device_groups_[leaudio_group_id].get() : nullptr; Loading Loading @@ -1896,6 +1902,92 @@ TEST_F(StateMachineTest, testStreamCachingSingle) { types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); } TEST_F(StateMachineTest, testActivateStreamCachingSingle) { auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; additional_ases = 2; /* Prepare fake connected device group with update of Media and Conversational * contexts */ auto* group = PrepareSingleTestDeviceGroup( leaudio_group_id, context_type, 1, kContextTypeConversational | kContextTypeMedia); /* Since we prepared device with Conversational context in mind, only one ASE * should have been configured. */ PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group, 0, true); PrepareEnableHandler(group); PrepareReceiverStartReady(group); PrepareReleaseHandler(group); /* Ctp messages we expect: * 1. Codec Config * 2. QoS Config * 3. Enable * 4. Release * 5. QoS Config (because device stays in Configured state) * 6. Enable */ auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(8); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(5); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_)).Times(1); InjectInitialIdleNotification(group); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)); EXPECT_CALL( mock_callbacks_, StatusReportCb( leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)) .Times(2); // Start the configuration and stream Conversational content LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<types::LeAudioContextType>(context_type)); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); // Stop the stream LeAudioGroupStateMachine::Get()->StopStream(group); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); // Start the configuration and stream Media content context_type = kContextTypeMedia; LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<types::LeAudioContextType>(context_type)); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); } TEST_F(StateMachineTest, testReleaseMultiple) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; Loading Loading
system/bta/le_audio/devices.cc +6 −4 Original line number Diff line number Diff line Loading @@ -152,11 +152,11 @@ void LeAudioDeviceGroup::Deactivate(void) { } } void LeAudioDeviceGroup::Activate(void) { void LeAudioDeviceGroup::Activate(LeAudioContextType context_type) { for (auto leAudioDevice : leAudioDevices_) { if (leAudioDevice.expired()) continue; leAudioDevice.lock()->ActivateConfiguredAses(); leAudioDevice.lock()->ActivateConfiguredAses(context_type); } } Loading Loading @@ -1023,6 +1023,7 @@ bool LeAudioDevice::ConfigureAses( for (; needed_ase && ase; needed_ase--) { ase->active = true; ase->configured_for_context_type = context_type; active_ases++; if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) Loading Loading @@ -1779,7 +1780,7 @@ AudioContexts LeAudioDevice::SetAvailableContexts(AudioContexts snk_contexts, return updated_contexts; } void LeAudioDevice::ActivateConfiguredAses(void) { void LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) { if (conn_id_ == GATT_INVALID_CONN_ID) { LOG_DEBUG(" Device %s is not connected ", address_.ToString().c_str()); return; Loading @@ -1788,7 +1789,8 @@ void LeAudioDevice::ActivateConfiguredAses(void) { LOG_DEBUG(" Configuring device %s", address_.ToString().c_str()); for (auto& ase : ases_) { if (!ase.active && ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) { ase.state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED && ase.configured_for_context_type == context_type) { LOG_DEBUG(" Ase id %d, cis id %d activated.", ase.id, ase.cis_id); ase.active = true; } Loading
system/bta/le_audio/devices.h +2 −2 Original line number Diff line number Diff line Loading @@ -143,7 +143,7 @@ class LeAudioDevice { types::AudioContexts SetAvailableContexts(types::AudioContexts snk_cont_val, types::AudioContexts src_cont_val); void DeactivateAllAses(void); void ActivateConfiguredAses(void); void ActivateConfiguredAses(types::LeAudioContextType context_type); void Dump(int fd); void DisconnectAcl(void); std::vector<uint8_t> GetMetadata(types::LeAudioContextType context_type, Loading Loading @@ -217,7 +217,7 @@ class LeAudioDeviceGroup { int Size(void); int NumOfConnected( types::LeAudioContextType context_type = types::LeAudioContextType::RFU); void Activate(void); void Activate(types::LeAudioContextType context_type); void Deactivate(void); void Cleanup(void); LeAudioDevice* GetFirstDevice(void); Loading
system/bta/le_audio/le_audio_types.h +2 −0 Original line number Diff line number Diff line Loading @@ -529,6 +529,7 @@ struct ase { active(false), reconfigure(false), data_path_state(AudioStreamDataPathState::IDLE), configured_for_context_type(LeAudioContextType::UNINITIALIZED), preferred_phy(0), state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} Loading @@ -542,6 +543,7 @@ struct ase { bool active; bool reconfigure; AudioStreamDataPathState data_path_state; LeAudioContextType configured_for_context_type; /* Codec configuration */ LeAudioCodecId codec_id; Loading
system/bta/le_audio/state_machine.cc +3 −1 Original line number Diff line number Diff line Loading @@ -153,7 +153,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { switch (group->GetState()) { case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED: if (group->GetCurrentContextType() == context_type) { group->Activate(); group->Activate(context_type); SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); CigCreate(group); return true; Loading Loading @@ -1129,6 +1129,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* leAudioDeviceNext; ase->state = AseState::BTA_LE_AUDIO_ASE_STATE_IDLE; ase->active = false; ase->configured_for_context_type = le_audio::types::LeAudioContextType::UNINITIALIZED; if (!leAudioDevice->HaveAllActiveAsesSameState( AseState::BTA_LE_AUDIO_ASE_STATE_IDLE)) { Loading
system/bta/le_audio/state_machine_test.cc +99 −7 Original line number Diff line number Diff line Loading @@ -644,6 +644,7 @@ class StateMachineTest : public Test { void MultipleTestDevicePrepare(int leaudio_group_id, uint16_t context_type, uint16_t device_cnt, uint16_t update_context_type, bool insert_default_pac_records = true) { // Prepare fake connected device group bool first_connections = true; Loading Loading @@ -680,8 +681,10 @@ class StateMachineTest : public Test { uint16_t attr_handle = ATTR_HANDLE_PACS_POOL_START; /* As per spec, unspecified shall be supported */ types::AudioContexts snk_context_type = kContextTypeUnspecified; types::AudioContexts src_context_type = kContextTypeUnspecified; types::AudioContexts snk_context_type = kContextTypeUnspecified | update_context_type; types::AudioContexts src_context_type = kContextTypeUnspecified | update_context_type; // Prepare Sink Published Audio Capability records if ((context_type & kContextTypeRingtone) || Loading Loading @@ -743,17 +746,20 @@ class StateMachineTest : public Test { } /* Stimulate update of active context map */ types::AudioContexts type_set = static_cast<uint16_t>(context_type); types::AudioContexts type_set = static_cast<uint16_t>( update_context_type == 0 ? context_type : context_type | update_context_type); group->UpdateActiveContextsMap(type_set); ASSERT_NE(group, nullptr); ASSERT_EQ(group->Size(), total_devices); } LeAudioDeviceGroup* PrepareSingleTestDeviceGroup(int leaudio_group_id, uint16_t context_type, uint16_t device_cnt = 1) { MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt); LeAudioDeviceGroup* PrepareSingleTestDeviceGroup( int leaudio_group_id, uint16_t context_type, uint16_t device_cnt = 1, uint16_t update_context_type = 0) { MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt, update_context_type); return le_audio_device_groups_.count(leaudio_group_id) ? le_audio_device_groups_[leaudio_group_id].get() : nullptr; Loading Loading @@ -1896,6 +1902,92 @@ TEST_F(StateMachineTest, testStreamCachingSingle) { types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); } TEST_F(StateMachineTest, testActivateStreamCachingSingle) { auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; additional_ases = 2; /* Prepare fake connected device group with update of Media and Conversational * contexts */ auto* group = PrepareSingleTestDeviceGroup( leaudio_group_id, context_type, 1, kContextTypeConversational | kContextTypeMedia); /* Since we prepared device with Conversational context in mind, only one ASE * should have been configured. */ PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group, 0, true); PrepareEnableHandler(group); PrepareReceiverStartReady(group); PrepareReleaseHandler(group); /* Ctp messages we expect: * 1. Codec Config * 2. QoS Config * 3. Enable * 4. Release * 5. QoS Config (because device stays in Configured state) * 6. Enable */ auto* leAudioDevice = group->GetFirstDevice(); EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(8); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(5); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_)).Times(1); InjectInitialIdleNotification(group); // Validate GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)); EXPECT_CALL( mock_callbacks_, StatusReportCb( leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS)); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)) .Times(2); // Start the configuration and stream Conversational content LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<types::LeAudioContextType>(context_type)); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); // Stop the stream LeAudioGroupStateMachine::Get()->StopStream(group); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); // Start the configuration and stream Media content context_type = kContextTypeMedia; LeAudioGroupStateMachine::Get()->StartStream( group, static_cast<types::LeAudioContextType>(context_type)); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); } TEST_F(StateMachineTest, testReleaseMultiple) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6; Loading