Loading system/bta/le_audio/device_groups.cc +1 −3 Original line number Diff line number Diff line Loading @@ -832,9 +832,7 @@ bool LeAudioDeviceGroup::ReloadAudioDirections(void) { return true; } bool LeAudioDeviceGroup::IsInTransition(void) const { return target_state_ != current_state_; } bool LeAudioDeviceGroup::IsInTransition(void) const { return in_transition_; } bool LeAudioDeviceGroup::IsStreaming(void) const { return current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING; Loading system/bta/le_audio/device_groups.h +18 −5 Original line number Diff line number Diff line Loading @@ -110,7 +110,8 @@ class LeAudioDeviceGroup { pending_group_available_contexts_change_( types::LeAudioContextType::UNINITIALIZED), target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), in_transition_(false) { #ifdef __ANDROID__ // 22 maps to BluetoothProfile#LE_AUDIO is_output_preference_le_audio = android::sysprop::BluetoothProperties:: Loading Loading @@ -227,13 +228,19 @@ class LeAudioDeviceGroup { inline types::AseState GetState(void) const { return current_state_; } void SetState(types::AseState state) { LOG(INFO) << __func__ << " current state: " << current_state_ << " new state: " << state; LOG_INFO(" current state: %s, new state %s, in_transition_ %d", bluetooth::common::ToString(current_state_).c_str(), bluetooth::common::ToString(state).c_str(), in_transition_); LeAudioLogHistory::Get()->AddLogHistory( kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogStateChangedOp, bluetooth::common::ToString(current_state_) + "->" + bluetooth::common::ToString(state)); current_state_ = state; if (target_state_ == current_state_) { in_transition_ = false; LOG_INFO("In transition flag cleared"); } } inline types::AseState GetTargetState(void) const { return target_state_; } Loading @@ -244,14 +251,19 @@ class LeAudioDeviceGroup { return notify_streaming_when_cises_are_ready_; } void SetTargetState(types::AseState state) { LOG(INFO) << __func__ << " target state: " << target_state_ << " new target state: " << state; LOG_INFO("target state: %s, new target state: %s, in_transition_ %d", bluetooth::common::ToString(target_state_).c_str(), bluetooth::common::ToString(state).c_str(), in_transition_); LeAudioLogHistory::Get()->AddLogHistory( kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogTargetStateChangedOp, bluetooth::common::ToString(target_state_) + "->" + bluetooth::common::ToString(state)); target_state_ = state; in_transition_ = target_state_ != current_state_; LOG_INFO("In transition flag = %d", in_transition_); } /* Returns context types for which support was recently added or removed */ Loading Loading @@ -396,6 +408,7 @@ class LeAudioDeviceGroup { types::AseState target_state_; types::AseState current_state_; bool in_transition_; std::vector<std::weak_ptr<LeAudioDevice>> leAudioDevices_; }; Loading system/bta/le_audio/state_machine.cc +7 −3 Original line number Diff line number Diff line Loading @@ -1871,6 +1871,10 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { /* This is autonomus change of the remote device */ LOG_DEBUG("Autonomus change for device %s, ase id %d. Just store it.", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id); /* Since at least one ASE is in configured state, we should admit * group is configured state */ group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); return; } Loading Loading @@ -2044,7 +2048,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } LOG_ERROR(", Autonomouse change, from: %s to %s", LOG_INFO("Autonomous change, from: %s to %s", ToString(group->GetState()).c_str(), ToString(group->GetTargetState()).c_str()); Loading system/bta/le_audio/state_machine_test.cc +86 −0 Original line number Diff line number Diff line Loading @@ -808,6 +808,26 @@ class StateMachineTestBase : public Test { } } void InjectInitialIdleAndConfiguredNotification(LeAudioDeviceGroup* group) { for (auto* device = group->GetFirstDevice(); device != nullptr; device = group->GetNextDevice(device)) { int i = 0; for (auto& ase : device->ases_) { if (i % 2 == 1) { InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, nullptr); } else { client_parser::ascs::ase_codec_configured_state_params codec_configured_state_params; InjectAseStateNotification(&ase, device, group, ascs::kAseStateCodecConfigured, &codec_configured_state_params); } i++; } } } void MultipleTestDevicePrepare(int leaudio_group_id, LeAudioContextType context_type, uint16_t device_cnt, Loading Loading @@ -3843,6 +3863,72 @@ TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) { } } TEST_F(StateMachineTest, testHandlingAutonomousCodecConfigStateOnConnection) { /* Scenario * 1. After connection remote device has different ASE configurations * 2. Try to start stream and make sure it is configured well. */ const auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; const int num_of_devices = 2; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_of_devices); auto* firstDevice = group->GetFirstDevice(); auto* secondDevice = group->GetNextDevice(firstDevice); /* Since we prepared device with Conversional context in mind, Sink and Source * ASEs should have been configured. */ PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReceiverStartReadyHandler(group); PrepareReceiverStopReady(group); /* Number of control point calls * 1. Codec Config * 2. QoS Config * 3. Enable * 4. Receiver Start Ready */ EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, firstDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_, secondDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); InjectInitialIdleAndConfiguredNotification(group); // Call it second time to make sure we get into state that current_state_ is // different then target_state_ even group is not in transition. InjectInitialIdleAndConfiguredNotification(group); ASSERT_TRUE(group->GetTargetState() != group->GetState()); ASSERT_FALSE(group->IsInTransition()); // Validate initial GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // 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)})); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } TEST_F(StateMachineTest, testHandlingCachedCodecConfig2Devices) { const auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; Loading Loading
system/bta/le_audio/device_groups.cc +1 −3 Original line number Diff line number Diff line Loading @@ -832,9 +832,7 @@ bool LeAudioDeviceGroup::ReloadAudioDirections(void) { return true; } bool LeAudioDeviceGroup::IsInTransition(void) const { return target_state_ != current_state_; } bool LeAudioDeviceGroup::IsInTransition(void) const { return in_transition_; } bool LeAudioDeviceGroup::IsStreaming(void) const { return current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING; Loading
system/bta/le_audio/device_groups.h +18 −5 Original line number Diff line number Diff line Loading @@ -110,7 +110,8 @@ class LeAudioDeviceGroup { pending_group_available_contexts_change_( types::LeAudioContextType::UNINITIALIZED), target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE), in_transition_(false) { #ifdef __ANDROID__ // 22 maps to BluetoothProfile#LE_AUDIO is_output_preference_le_audio = android::sysprop::BluetoothProperties:: Loading Loading @@ -227,13 +228,19 @@ class LeAudioDeviceGroup { inline types::AseState GetState(void) const { return current_state_; } void SetState(types::AseState state) { LOG(INFO) << __func__ << " current state: " << current_state_ << " new state: " << state; LOG_INFO(" current state: %s, new state %s, in_transition_ %d", bluetooth::common::ToString(current_state_).c_str(), bluetooth::common::ToString(state).c_str(), in_transition_); LeAudioLogHistory::Get()->AddLogHistory( kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogStateChangedOp, bluetooth::common::ToString(current_state_) + "->" + bluetooth::common::ToString(state)); current_state_ = state; if (target_state_ == current_state_) { in_transition_ = false; LOG_INFO("In transition flag cleared"); } } inline types::AseState GetTargetState(void) const { return target_state_; } Loading @@ -244,14 +251,19 @@ class LeAudioDeviceGroup { return notify_streaming_when_cises_are_ready_; } void SetTargetState(types::AseState state) { LOG(INFO) << __func__ << " target state: " << target_state_ << " new target state: " << state; LOG_INFO("target state: %s, new target state: %s, in_transition_ %d", bluetooth::common::ToString(target_state_).c_str(), bluetooth::common::ToString(state).c_str(), in_transition_); LeAudioLogHistory::Get()->AddLogHistory( kLogStateMachineTag, group_id_, RawAddress::kEmpty, kLogTargetStateChangedOp, bluetooth::common::ToString(target_state_) + "->" + bluetooth::common::ToString(state)); target_state_ = state; in_transition_ = target_state_ != current_state_; LOG_INFO("In transition flag = %d", in_transition_); } /* Returns context types for which support was recently added or removed */ Loading Loading @@ -396,6 +408,7 @@ class LeAudioDeviceGroup { types::AseState target_state_; types::AseState current_state_; bool in_transition_; std::vector<std::weak_ptr<LeAudioDevice>> leAudioDevices_; }; Loading
system/bta/le_audio/state_machine.cc +7 −3 Original line number Diff line number Diff line Loading @@ -1871,6 +1871,10 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { /* This is autonomus change of the remote device */ LOG_DEBUG("Autonomus change for device %s, ase id %d. Just store it.", ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), ase->id); /* Since at least one ASE is in configured state, we should admit * group is configured state */ group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); return; } Loading Loading @@ -2044,7 +2048,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } LOG_ERROR(", Autonomouse change, from: %s to %s", LOG_INFO("Autonomous change, from: %s to %s", ToString(group->GetState()).c_str(), ToString(group->GetTargetState()).c_str()); Loading
system/bta/le_audio/state_machine_test.cc +86 −0 Original line number Diff line number Diff line Loading @@ -808,6 +808,26 @@ class StateMachineTestBase : public Test { } } void InjectInitialIdleAndConfiguredNotification(LeAudioDeviceGroup* group) { for (auto* device = group->GetFirstDevice(); device != nullptr; device = group->GetNextDevice(device)) { int i = 0; for (auto& ase : device->ases_) { if (i % 2 == 1) { InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle, nullptr); } else { client_parser::ascs::ase_codec_configured_state_params codec_configured_state_params; InjectAseStateNotification(&ase, device, group, ascs::kAseStateCodecConfigured, &codec_configured_state_params); } i++; } } } void MultipleTestDevicePrepare(int leaudio_group_id, LeAudioContextType context_type, uint16_t device_cnt, Loading Loading @@ -3843,6 +3863,72 @@ TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) { } } TEST_F(StateMachineTest, testHandlingAutonomousCodecConfigStateOnConnection) { /* Scenario * 1. After connection remote device has different ASE configurations * 2. Try to start stream and make sure it is configured well. */ const auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; const int num_of_devices = 2; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_of_devices); auto* firstDevice = group->GetFirstDevice(); auto* secondDevice = group->GetNextDevice(firstDevice); /* Since we prepared device with Conversional context in mind, Sink and Source * ASEs should have been configured. */ PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReceiverStartReadyHandler(group); PrepareReceiverStopReady(group); /* Number of control point calls * 1. Codec Config * 2. QoS Config * 3. Enable * 4. Receiver Start Ready */ EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, firstDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_, secondDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(4); InjectInitialIdleAndConfiguredNotification(group); // Call it second time to make sure we get into state that current_state_ is // different then target_state_ even group is not in transition. InjectInitialIdleAndConfiguredNotification(group); ASSERT_TRUE(group->GetTargetState() != group->GetState()); ASSERT_FALSE(group->IsInTransition()); // Validate initial GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // 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)})); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } TEST_F(StateMachineTest, testHandlingCachedCodecConfig2Devices) { const auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; Loading