Loading system/bta/le_audio/client.cc +51 −6 Original line number Diff line number Diff line Loading @@ -332,8 +332,9 @@ class LeAudioClientImpl : public LeAudioClient { } /* Choose the right configuration context */ auto new_configuration_context = ChooseConfigurationContextType(local_metadata_context_types_.source); auto new_configuration_context = AdjustForVoiceAssistant( group, ChooseConfigurationContextType(local_metadata_context_types_.source)); log::debug("new_configuration_context= {}", ToString(new_configuration_context)); Loading Loading @@ -4953,6 +4954,50 @@ class LeAudioClientImpl : public LeAudioClient { return remote_metadata; } LeAudioContextType AdjustForVoiceAssistant( LeAudioDeviceGroup* group, LeAudioContextType new_configuration_context) { if (!IS_FLAG_ENABLED(le_audio_support_unidirectional_voice_assistant)) { log::debug( "Flag le_audio_support_unidirectional_voice_assistant NOT enabled"); return new_configuration_context; } /* Some remote devices expect VOICE ASSISTANT to be unidirectional Phone is * Source and Earbuds are Sink */ if (new_configuration_context != LeAudioContextType::VOICEASSISTANTS) { return new_configuration_context; } auto sink_supported_contexts = group->GetSupportedContexts( bluetooth::le_audio::types::kLeAudioDirectionSink); auto source_supported_contexts = group->GetSupportedContexts( bluetooth::le_audio::types::kLeAudioDirectionSource); log::debug(" group_id: {}, sink_supported: {}, source_supported {}", group->group_id_, ToString(sink_supported_contexts), ToString(source_supported_contexts)); if (sink_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS) && source_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { return new_configuration_context; } if (sink_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { log::info( "group_id {} supports only Sink direction for Voice Assistant. " "Selecting configurarion context type {}", group->group_id_, ToString(LeAudioContextType::INSTRUCTIONAL)); return LeAudioContextType::INSTRUCTIONAL; } log::warn( " group_id: {}, unexpected configuration, sink_supported: {}, " "source_supported {}", group->group_id_, ToString(sink_supported_contexts), ToString(source_supported_contexts)); return new_configuration_context; } /* Return true if stream is started */ bool ReconfigureOrUpdateRemote(LeAudioDeviceGroup* group, int remote_direction) { Loading @@ -4972,8 +5017,8 @@ class LeAudioClientImpl : public LeAudioClient { override_contexts.to_string()); /* Choose the right configuration context */ auto new_configuration_context = ChooseConfigurationContextType(override_contexts); auto new_configuration_context = AdjustForVoiceAssistant( group, ChooseConfigurationContextType(override_contexts)); log::debug("new_configuration_context= {}.", ToString(new_configuration_context)); Loading @@ -4993,8 +5038,8 @@ class LeAudioClientImpl : public LeAudioClient { /* Choose the right configuration context */ auto config_context_candids = get_bidirectional(remote_metadata); auto new_config_context = ChooseConfigurationContextType(config_context_candids); auto new_config_context = AdjustForVoiceAssistant( group, ChooseConfigurationContextType(config_context_candids)); log::debug("config_context_candids= {}, new_config_context= {}", ToString(config_context_candids), ToString(new_config_context)); Loading system/bta/le_audio/le_audio_client_test.cc +141 −0 Original line number Diff line number Diff line Loading @@ -5923,6 +5923,147 @@ TEST_F(UnicastTest, SpeakerStreamingNonDefault) { LocalAudioSourceResume(); } TEST_F_WITH_FLAGS(UnicastTest, TestUnidirectionalVoiceAssistant_Sink, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( TEST_BT, le_audio_support_unidirectional_voice_assistant))) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; /** * Scenario test steps * 1. Configure group to support VOICEASSISTANT only on SINK * 2. Start stream * 5. Verify that Unidirectional VOICEASSISTANT has been created */ available_snk_context_types_ = (types::LeAudioContextType::VOICEASSISTANTS | types::LeAudioContextType::MEDIA | types::LeAudioContextType::UNSPECIFIED) .value(); supported_snk_context_types_ = available_snk_context_types_; available_src_context_types_ = (types::LeAudioContextType::LIVE | types::LeAudioContextType::UNSPECIFIED) .value(); supported_src_context_types_ = available_src_context_types_; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, 0 /*rank*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) .WillOnce(DoAll(SaveArg<1>(&group_id))); types::BidirectionalPair<types::AudioContexts> metadata_contexts = { .sink = types::AudioContexts(types::LeAudioContextType::VOICEASSISTANTS), .source = types::AudioContexts()}; EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::INSTRUCTIONAL, metadata_contexts, _)) .Times(1); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); // Start streaming uint8_t cis_count_out = 1; uint8_t cis_count_in = 0; // Audio sessions are started only when device gets active EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); // Verify Data transfer on one local audio source cis TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); SyncOnMainLoop(); } TEST_F_WITH_FLAGS(UnicastTest, TestUnidirectionalVoiceAssistant_Source, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( TEST_BT, le_audio_support_unidirectional_voice_assistant))) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; /** * Scenario test steps * 1. Configure group to support VOICEASSISTANT only on SOURCE * 2. Start stream * 5. Verify that bi-direction VOICEASSISTANT has been created */ available_snk_context_types_ = (types::LeAudioContextType::MEDIA | types::LeAudioContextType::UNSPECIFIED) .value(); supported_snk_context_types_ = available_snk_context_types_; available_src_context_types_ = (types::LeAudioContextType::VOICEASSISTANTS | types::LeAudioContextType::LIVE | types::LeAudioContextType::UNSPECIFIED) .value(); supported_src_context_types_ = available_src_context_types_; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeftOfCenter, codec_spec_conf::kLeAudioLocationFrontLeftOfCenter, default_channel_cnt, default_channel_cnt, 0x0004, /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 2 /*set_size*/, 1 /*rank*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) .WillOnce(DoAll(SaveArg<1>(&group_id))); types::BidirectionalPair<types::AudioContexts> metadata_contexts = { .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), .source = types::AudioContexts(types::LeAudioContextType::VOICEASSISTANTS)}; EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::VOICEASSISTANTS, metadata_contexts, _)) .Times(1); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); // Start streaming uint8_t cis_count_out = 1; uint8_t cis_count_in = 1; // Audio sessions are started only when device gets active EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, AUDIO_SOURCE_VOICE_RECOGNITION); // Verify Data transfer on one local audio source cis TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); } TEST_F(UnicastTest, SpeakerStreamingAutonomousRelease) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; Loading Loading
system/bta/le_audio/client.cc +51 −6 Original line number Diff line number Diff line Loading @@ -332,8 +332,9 @@ class LeAudioClientImpl : public LeAudioClient { } /* Choose the right configuration context */ auto new_configuration_context = ChooseConfigurationContextType(local_metadata_context_types_.source); auto new_configuration_context = AdjustForVoiceAssistant( group, ChooseConfigurationContextType(local_metadata_context_types_.source)); log::debug("new_configuration_context= {}", ToString(new_configuration_context)); Loading Loading @@ -4953,6 +4954,50 @@ class LeAudioClientImpl : public LeAudioClient { return remote_metadata; } LeAudioContextType AdjustForVoiceAssistant( LeAudioDeviceGroup* group, LeAudioContextType new_configuration_context) { if (!IS_FLAG_ENABLED(le_audio_support_unidirectional_voice_assistant)) { log::debug( "Flag le_audio_support_unidirectional_voice_assistant NOT enabled"); return new_configuration_context; } /* Some remote devices expect VOICE ASSISTANT to be unidirectional Phone is * Source and Earbuds are Sink */ if (new_configuration_context != LeAudioContextType::VOICEASSISTANTS) { return new_configuration_context; } auto sink_supported_contexts = group->GetSupportedContexts( bluetooth::le_audio::types::kLeAudioDirectionSink); auto source_supported_contexts = group->GetSupportedContexts( bluetooth::le_audio::types::kLeAudioDirectionSource); log::debug(" group_id: {}, sink_supported: {}, source_supported {}", group->group_id_, ToString(sink_supported_contexts), ToString(source_supported_contexts)); if (sink_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS) && source_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { return new_configuration_context; } if (sink_supported_contexts.test(LeAudioContextType::VOICEASSISTANTS)) { log::info( "group_id {} supports only Sink direction for Voice Assistant. " "Selecting configurarion context type {}", group->group_id_, ToString(LeAudioContextType::INSTRUCTIONAL)); return LeAudioContextType::INSTRUCTIONAL; } log::warn( " group_id: {}, unexpected configuration, sink_supported: {}, " "source_supported {}", group->group_id_, ToString(sink_supported_contexts), ToString(source_supported_contexts)); return new_configuration_context; } /* Return true if stream is started */ bool ReconfigureOrUpdateRemote(LeAudioDeviceGroup* group, int remote_direction) { Loading @@ -4972,8 +5017,8 @@ class LeAudioClientImpl : public LeAudioClient { override_contexts.to_string()); /* Choose the right configuration context */ auto new_configuration_context = ChooseConfigurationContextType(override_contexts); auto new_configuration_context = AdjustForVoiceAssistant( group, ChooseConfigurationContextType(override_contexts)); log::debug("new_configuration_context= {}.", ToString(new_configuration_context)); Loading @@ -4993,8 +5038,8 @@ class LeAudioClientImpl : public LeAudioClient { /* Choose the right configuration context */ auto config_context_candids = get_bidirectional(remote_metadata); auto new_config_context = ChooseConfigurationContextType(config_context_candids); auto new_config_context = AdjustForVoiceAssistant( group, ChooseConfigurationContextType(config_context_candids)); log::debug("config_context_candids= {}, new_config_context= {}", ToString(config_context_candids), ToString(new_config_context)); Loading
system/bta/le_audio/le_audio_client_test.cc +141 −0 Original line number Diff line number Diff line Loading @@ -5923,6 +5923,147 @@ TEST_F(UnicastTest, SpeakerStreamingNonDefault) { LocalAudioSourceResume(); } TEST_F_WITH_FLAGS(UnicastTest, TestUnidirectionalVoiceAssistant_Sink, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( TEST_BT, le_audio_support_unidirectional_voice_assistant))) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; /** * Scenario test steps * 1. Configure group to support VOICEASSISTANT only on SINK * 2. Start stream * 5. Verify that Unidirectional VOICEASSISTANT has been created */ available_snk_context_types_ = (types::LeAudioContextType::VOICEASSISTANTS | types::LeAudioContextType::MEDIA | types::LeAudioContextType::UNSPECIFIED) .value(); supported_snk_context_types_ = available_snk_context_types_; available_src_context_types_ = (types::LeAudioContextType::LIVE | types::LeAudioContextType::UNSPECIFIED) .value(); supported_src_context_types_ = available_src_context_types_; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, 0 /*rank*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) .WillOnce(DoAll(SaveArg<1>(&group_id))); types::BidirectionalPair<types::AudioContexts> metadata_contexts = { .sink = types::AudioContexts(types::LeAudioContextType::VOICEASSISTANTS), .source = types::AudioContexts()}; EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::INSTRUCTIONAL, metadata_contexts, _)) .Times(1); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); // Start streaming uint8_t cis_count_out = 1; uint8_t cis_count_in = 0; // Audio sessions are started only when device gets active EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); // Verify Data transfer on one local audio source cis TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); SyncOnMainLoop(); } TEST_F_WITH_FLAGS(UnicastTest, TestUnidirectionalVoiceAssistant_Source, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG( TEST_BT, le_audio_support_unidirectional_voice_assistant))) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; /** * Scenario test steps * 1. Configure group to support VOICEASSISTANT only on SOURCE * 2. Start stream * 5. Verify that bi-direction VOICEASSISTANT has been created */ available_snk_context_types_ = (types::LeAudioContextType::MEDIA | types::LeAudioContextType::UNSPECIFIED) .value(); supported_snk_context_types_ = available_snk_context_types_; available_src_context_types_ = (types::LeAudioContextType::VOICEASSISTANTS | types::LeAudioContextType::LIVE | types::LeAudioContextType::UNSPECIFIED) .value(); supported_src_context_types_ = available_src_context_types_; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeftOfCenter, codec_spec_conf::kLeAudioLocationFrontLeftOfCenter, default_channel_cnt, default_channel_cnt, 0x0004, /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 2 /*set_size*/, 1 /*rank*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) .WillOnce(DoAll(SaveArg<1>(&group_id))); types::BidirectionalPair<types::AudioContexts> metadata_contexts = { .sink = types::AudioContexts(types::LeAudioContextType::UNSPECIFIED), .source = types::AudioContexts(types::LeAudioContextType::VOICEASSISTANTS)}; EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::VOICEASSISTANTS, metadata_contexts, _)) .Times(1); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); // Start streaming uint8_t cis_count_out = 1; uint8_t cis_count_in = 1; // Audio sessions are started only when device gets active EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); StartStreaming(AUDIO_USAGE_ASSISTANT, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, AUDIO_SOURCE_VOICE_RECOGNITION); // Verify Data transfer on one local audio source cis TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); SyncOnMainLoop(); } TEST_F(UnicastTest, SpeakerStreamingAutonomousRelease) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; Loading