Loading system/gd/hci/controller.cc +167 −50 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "hci_controller_generated.h" #include "os/log.h" #include "os/metrics.h" #include "os/system_properties.h" #include "sysprops/sysprops_module.h" Loading Loading @@ -196,9 +197,16 @@ struct Controller::impl { // Skip vendor capabilities check if configured. if (os::GetSystemPropertyBool( kPropertyVendorCapabilitiesEnabled, kDefaultVendorCapabilitiesEnabled)) { // More commands can be enqueued from le_get_vendor_capabilities_handler std::promise<void> vendor_promise; auto vendor_future = vendor_promise.get_future(); hci_->EnqueueCommand( LeGetVendorCapabilitiesBuilder::Create(), handler->BindOnceOn(this, &Controller::impl::le_get_vendor_capabilities_handler)); handler->BindOnceOn( this, &Controller::impl::le_get_vendor_capabilities_handler, std::move(vendor_promise))); vendor_future.wait(); } else { vendor_capabilities_.is_supported_ = 0x00; } Loading Loading @@ -531,7 +539,8 @@ struct Controller::impl { le_periodic_advertiser_list_size_ = complete_view.GetPeriodicAdvertiserListSize(); } void le_get_vendor_capabilities_handler(CommandCompleteView view) { void le_get_vendor_capabilities_handler( std::promise<void> vendor_promise, CommandCompleteView view) { auto complete_view = LeGetVendorCapabilitiesCompleteView::Create(view); vendor_capabilities_.is_supported_ = 0x00; Loading @@ -551,7 +560,10 @@ struct Controller::impl { vendor_capabilities_.a2dp_source_offload_capability_mask_ = 0x00; vendor_capabilities_.bluetooth_quality_report_support_ = 0x00; if (complete_view.IsValid()) { if (!complete_view.IsValid()) { vendor_promise.set_value(); return; } vendor_capabilities_.is_supported_ = 0x01; // v0.55 Loading @@ -559,20 +571,25 @@ struct Controller::impl { vendor_capabilities_.max_advt_instances_ = base_vendor_capabilities.max_advt_instances_; vendor_capabilities_.offloaded_resolution_of_private_address_ = base_vendor_capabilities.offloaded_resolution_of_private_address_; vendor_capabilities_.total_scan_results_storage_ = base_vendor_capabilities.total_scan_results_storage_; vendor_capabilities_.total_scan_results_storage_ = base_vendor_capabilities.total_scan_results_storage_; vendor_capabilities_.max_irk_list_sz_ = base_vendor_capabilities.max_irk_list_sz_; vendor_capabilities_.filtering_support_ = base_vendor_capabilities.filtering_support_; vendor_capabilities_.max_filter_ = base_vendor_capabilities.max_filter_; vendor_capabilities_.activity_energy_info_support_ = base_vendor_capabilities.activity_energy_info_support_; vendor_capabilities_.activity_energy_info_support_ = base_vendor_capabilities.activity_energy_info_support_; if (complete_view.GetPayload().size() == 0) { vendor_capabilities_.version_supported_ = 55; vendor_promise.set_value(); return; } // v0.95 auto v95 = LeGetVendorCapabilitiesComplete095View::Create(complete_view); if (!v95.IsValid()) { LOG_ERROR("invalid data for hci requirements v0.95"); LOG_INFO("invalid data for hci requirements v0.95"); vendor_promise.set_value(); return; } vendor_capabilities_.version_supported_ = v95.GetVersionSupported(); Loading @@ -580,29 +597,108 @@ struct Controller::impl { vendor_capabilities_.extended_scan_support_ = v95.GetExtendedScanSupport(); vendor_capabilities_.debug_logging_supported_ = v95.GetDebugLoggingSupported(); if (vendor_capabilities_.version_supported_ <= 95 || complete_view.GetPayload().size() == 0) { vendor_promise.set_value(); return; } // v0.96 auto v96 = LeGetVendorCapabilitiesComplete096View::Create(v95); if (!v96.IsValid()) { LOG_ERROR("invalid data for hci requirements v0.96"); LOG_INFO("invalid data for hci requirements v0.96"); vendor_promise.set_value(); return; } vendor_capabilities_.le_address_generation_offloading_support_ = v96.GetLeAddressGenerationOffloadingSupport(); vendor_capabilities_.le_address_generation_offloading_support_ = v96.GetLeAddressGenerationOffloadingSupport(); if (vendor_capabilities_.version_supported_ <= 96 || complete_view.GetPayload().size() == 0) { vendor_promise.set_value(); return; } // v0.98 auto v98 = LeGetVendorCapabilitiesComplete098View::Create(v96); if (!v98.IsValid()) { LOG_ERROR("invalid data for hci requirements v0.98"); LOG_INFO("invalid data for hci requirements v0.98"); vendor_promise.set_value(); return; } vendor_capabilities_.a2dp_source_offload_capability_mask_ = v98.GetA2dpSourceOffloadCapabilityMask(); vendor_capabilities_.a2dp_source_offload_capability_mask_ = v98.GetA2dpSourceOffloadCapabilityMask(); vendor_capabilities_.bluetooth_quality_report_support_ = v98.GetBluetoothQualityReportSupport(); // v1.03 auto v103 = LeGetVendorCapabilitiesComplete103View::Create(v98); if (!v103.IsValid()) { LOG_INFO("invalid data for hci requirements v1.03"); vendor_promise.set_value(); return; } vendor_capabilities_.dynamic_audio_buffer_support_ = v103.GetDynamicAudioBufferSupport(); if (vendor_capabilities_.dynamic_audio_buffer_support_ == 0) { vendor_promise.set_value(); return; } hci_->EnqueueCommand( DabGetAudioBufferTimeCapabilityBuilder::Create(), module_.GetHandler()->BindOnceOn( this, &Controller::impl::le_get_dynamic_audio_buffer_support_handler, std::move(vendor_promise))); } void le_get_dynamic_audio_buffer_support_handler( std::promise<void> vendor_promise, CommandCompleteView view) { vendor_promise.set_value(); auto dab_complete_view = DynamicAudioBufferCompleteView::Create(view); if (!dab_complete_view.IsValid()) { LOG_WARN("Invalid command complete"); return; } if (dab_complete_view.GetStatus() != ErrorCode::SUCCESS) { LOG_WARN("Unexpected error code %s", ErrorCodeText(dab_complete_view.GetStatus()).c_str()); return; } auto complete_view = DabGetAudioBufferTimeCapabilityCompleteView::Create(dab_complete_view); if (!complete_view.IsValid()) { LOG_WARN("Invalid get complete"); return; } dab_supported_codecs_ = complete_view.GetAudioCodecTypeSupported(); dab_codec_capabilities_ = complete_view.GetAudioCodecCapabilities(); } void set_controller_dab_audio_buffer_time_complete(CommandCompleteView complete) { auto dab_complete = DynamicAudioBufferCompleteView::Create(complete); if (!dab_complete.IsValid()) { LOG_WARN("Invalid command complete"); return; } if (dab_complete.GetStatus() != ErrorCode::SUCCESS) { LOG_WARN("Unexpected return code %s", ErrorCodeText(dab_complete.GetStatus()).c_str()); return; } auto dab_set_complete = DabSetAudioBufferTimeCompleteView::Create(dab_complete); if (!dab_set_complete.IsValid()) { LOG_WARN("Invalid set complete"); return; } LOG_INFO( "Configured Media Tx Buffer, time returned = %d", dab_set_complete.GetCurrentBufferTimeMs()); } void set_controller_dab_audio_buffer_time(uint16_t buffer_time_ms) { hci_->EnqueueCommand( DabSetAudioBufferTimeBuilder::Create(buffer_time_ms), module_.GetHandler()->BindOnceOn( this, &Controller::impl::set_controller_dab_audio_buffer_time_complete)); } void set_event_mask(uint64_t event_mask) { Loading Loading @@ -1033,6 +1129,8 @@ struct Controller::impl { return vendor_capabilities_.a2dp_source_offload_capability_mask_ != 0x00; case OpCode::CONTROLLER_BQR: return vendor_capabilities_.bluetooth_quality_report_support_ == 0x01; case OpCode::DYNAMIC_AUDIO_BUFFER: return vendor_capabilities_.dynamic_audio_buffer_support_ > 0x00; // Before MSFT extension is fully supported, return false for the following MSFT_OPCODE_XXXX for now. case OpCode::MSFT_OPCODE_INTEL: return false; Loading Loading @@ -1095,6 +1193,8 @@ struct Controller::impl { uint8_t le_number_supported_advertising_sets_{}; uint8_t le_periodic_advertiser_list_size_{}; VendorCapabilities vendor_capabilities_{}; uint32_t dab_supported_codecs_{}; std::array<DynamicAudioBufferCodecCapability, 32> dab_codec_capabilities_{}; }; // namespace hci Controller::Controller() : impl_(std::make_unique<impl>(*this)) {} Loading Loading @@ -1365,6 +1465,23 @@ Controller::VendorCapabilities Controller::GetVendorCapabilities() const { return impl_->vendor_capabilities_; } uint32_t Controller::GetDabSupportedCodecs() const { return impl_->dab_supported_codecs_; } const std::array<DynamicAudioBufferCodecCapability, 32>& Controller::GetDabCodecCapabilities() const { return impl_->dab_codec_capabilities_; } void Controller::SetDabAudioBufferTime(uint16_t buffer_time_ms) { if (impl_->vendor_capabilities_.dynamic_audio_buffer_support_ == 0) { LOG_WARN("Dynamic Audio Buffer not supported"); return; } impl_->set_controller_dab_audio_buffer_time(buffer_time_ms); } uint8_t Controller::GetLePeriodicAdvertiserListSize() const { return impl_->le_periodic_advertiser_list_size_; } Loading system/gd/hci/controller.h +6 −0 Original line number Diff line number Diff line Loading @@ -203,10 +203,16 @@ class Controller : public Module { uint8_t le_address_generation_offloading_support_; uint32_t a2dp_source_offload_capability_mask_; uint8_t bluetooth_quality_report_support_; uint32_t dynamic_audio_buffer_support_; }; virtual VendorCapabilities GetVendorCapabilities() const; virtual uint32_t GetDabSupportedCodecs() const; virtual const std::array<DynamicAudioBufferCodecCapability, 32>& GetDabCodecCapabilities() const; virtual void SetDabAudioBufferTime(uint16_t buffer_time_ms); virtual bool IsSupported(OpCode op_code) const; static const ModuleFactory Factory; Loading system/gd/hci/controller_test.cc +113 −17 Original line number Diff line number Diff line Loading @@ -49,6 +49,8 @@ constexpr uint16_t kCredits1 = 0x78; constexpr uint16_t kHandle2 = 0x456; constexpr uint16_t kCredits2 = 0x9a; constexpr uint64_t kRandomNumber = 0x123456789abcdef0; /*sbc_supported= 1, aac_supported= 1, aptx_supported= 0, aptx_hd_supported= 0, ldac_supported= 1 */ constexpr uint32_t kDynamicAudioBufferSupport = 0x13; uint16_t feature_spec_version = 55; constexpr char title[] = "hci_controller_test"; Loading Loading @@ -171,7 +173,8 @@ class HciLayerFakeForController : public HciLayerFake { event_builder = LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0xF0); } break; case (OpCode::LE_GET_VENDOR_CAPABILITIES): { case (OpCode::LE_GET_VENDOR_CAPABILITIES): if (vendor_capabilities_ == nullptr) { BaseVendorCapabilities base_vendor_capabilities; base_vendor_capabilities.max_advt_instances_ = 0x10; base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01; Loading @@ -183,12 +186,37 @@ class HciLayerFakeForController : public HciLayerFake { auto payload = std::make_unique<RawBuilder>(); if (feature_spec_version > 55) { std::vector<uint8_t> payload_bytes = {0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00}; std::vector<uint8_t> payload_bytes = { 0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00}; payload->AddOctets2(feature_spec_version); payload->AddOctets(payload_bytes); } event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create( num_packets, ErrorCode::SUCCESS, base_vendor_capabilities, std::move(payload)); } else { event_builder = std::move(vendor_capabilities_); vendor_capabilities_.reset(); } break; case (OpCode::DYNAMIC_AUDIO_BUFFER): { auto dab_command = DynamicAudioBufferView::CreateOptional(VendorCommandView::Create(command)); if (dab_command->GetDabCommand() == DabCommand::GET_AUDIO_BUFFER_TIME_CAPABILITY) { std::array<DynamicAudioBufferCodecCapability, 32> capabilities{}; capabilities[0] = DynamicAudioBufferCodecCapability(0x123, 0x103, 0x1234); // sbc_capabilities capabilities[1] = DynamicAudioBufferCodecCapability(0x223, 0x123, 0x2340); // aac_capabilities capabilities[4] = DynamicAudioBufferCodecCapability(0x323, 0x223, 0x3456); // ldac_capabilities event_builder = DabGetAudioBufferTimeCapabilityCompleteBuilder::Create( 1, ErrorCode::SUCCESS, kDynamicAudioBufferSupport, capabilities); } else { auto set_command = DabSetAudioBufferTimeView::CreateOptional(*dab_command); dynamic_audio_buffer_time = set_command->GetBufferTimeMs(); event_builder = DabSetAudioBufferTimeCompleteBuilder::Create( 1, ErrorCode::SUCCESS, dynamic_audio_buffer_time); } } break; case (OpCode::SET_EVENT_MASK): { auto view = SetEventMaskView::Create(command); Loading Loading @@ -240,12 +268,14 @@ class HciLayerFakeForController : public HciLayerFake { IncomingEvent(NumberOfCompletedPacketsBuilder::Create(completed_packets)); } std::unique_ptr<EventBuilder> vendor_capabilities_ = nullptr; constexpr static uint16_t acl_data_packet_length = 1024; constexpr static uint8_t synchronous_data_packet_length = 60; constexpr static uint16_t total_num_acl_data_packets = 10; constexpr static uint16_t total_num_synchronous_data_packets = 12; uint64_t event_mask = 0; uint64_t le_event_mask = 0; uint16_t dynamic_audio_buffer_time = 0; }; class ControllerTest : public ::testing::Test { Loading @@ -254,6 +284,8 @@ class ControllerTest : public ::testing::Test { feature_spec_version = feature_spec_version_; bluetooth::common::InitFlags::SetAllForTesting(); test_hci_layer_ = new HciLayerFakeForController; test_hci_layer_->vendor_capabilities_ = std::move(vendor_capabilities_); vendor_capabilities_.reset(); fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); fake_registry_.Start<Controller>(&thread_); Loading @@ -270,6 +302,7 @@ class ControllerTest : public ::testing::Test { Controller* controller_ = nullptr; os::Handler* client_handler_ = nullptr; uint16_t feature_spec_version_ = 98; std::unique_ptr<EventBuilder> vendor_capabilities_ = nullptr; }; } // namespace Loading Loading @@ -297,6 +330,35 @@ class Controller096Test : public ControllerTest { } }; class Controller103Test : public ControllerTest { protected: void SetUp() override { feature_spec_version_ = 0x100 + 0x03; BaseVendorCapabilities base_vendor_capabilities; base_vendor_capabilities.max_advt_instances_ = 0x10; base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01; base_vendor_capabilities.total_scan_results_storage_ = 0x2800; base_vendor_capabilities.max_irk_list_sz_ = 0x20; base_vendor_capabilities.filtering_support_ = 0x01; base_vendor_capabilities.max_filter_ = 0x10; base_vendor_capabilities.activity_energy_info_support_ = 0x01; vendor_capabilities_ = LeGetVendorCapabilitiesComplete103Builder::Create( 1, ErrorCode::SUCCESS, base_vendor_capabilities, feature_spec_version_, 0x102, /*extended_scan_support=*/1, /*debug_logging_supported=*/1, /*le_address_generation_offloading_support=*/0, /*a2dp_source_offload_capability_mask=*/0x4, /*bluetooth_quality_report_support=*/1, kDynamicAudioBufferSupport, std::make_unique<RawBuilder>()); ControllerTest::SetUp(); } }; TEST_F(ControllerTest, startup_teardown) {} TEST_F(ControllerTest, read_controller_info) { Loading Loading @@ -430,6 +492,40 @@ TEST_F(ControllerTest, feature_spec_version_098_test) { ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); } TEST_F(ControllerTest, feature_spec_version_098_no_dab_test) { ASSERT_FALSE(controller_->IsSupported(OpCode::DYNAMIC_AUDIO_BUFFER)); } TEST_F(ControllerTest, set_dynamic_audio_buffer_time) { controller_->SetDabAudioBufferTime(123); thread_.GetReactor()->WaitForIdle(std::chrono::seconds(1)); ASSERT_EQ(0, test_hci_layer_->dynamic_audio_buffer_time); } TEST_F(Controller103Test, feature_spec_version_103_dab_test) { ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 0x100 + 3); ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT)); ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO)); ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); ASSERT_TRUE(controller_->IsSupported(OpCode::DYNAMIC_AUDIO_BUFFER)); ASSERT_EQ(controller_->GetDabSupportedCodecs(), kDynamicAudioBufferSupport); for (size_t bit = 0; bit < 32; bit++) { if (kDynamicAudioBufferSupport & (1u << bit)) { ASSERT_GT(controller_->GetDabCodecCapabilities()[bit].maximum_time_ms_, 0) << " bit " << bit; } else { ASSERT_EQ(controller_->GetDabCodecCapabilities()[bit].maximum_time_ms_, 0); ASSERT_EQ(controller_->GetDabCodecCapabilities()[bit].minimum_time_ms_, 0); ASSERT_EQ(controller_->GetDabCodecCapabilities()[bit].default_time_ms_, 0); } } } TEST_F(Controller103Test, set_dynamic_audio_buffer_time) { controller_->SetDabAudioBufferTime(123); thread_.GetReactor()->WaitForIdle(std::chrono::seconds(1)); ASSERT_EQ(123, test_hci_layer_->dynamic_audio_buffer_time); } std::promise<void> credits1_set; std::promise<void> credits2_set; Loading system/pdl/hci/hci_packets.pdl +67 −2 Original line number Diff line number Diff line Loading @@ -456,6 +456,7 @@ enum OpCode : 16 { CONTROLLER_DEBUG_INFO = 0xFD5B, CONTROLLER_A2DP_OPCODE = 0xFD5D, CONTROLLER_BQR = 0xFD5E, DYNAMIC_AUDIO_BUFFER = 0xFD5F, // MSFT_OPCODE_xxxx below are needed for the tests. MSFT_OPCODE_MEDIATEK = 0xFD30, MSFT_OPCODE_QUALCOMM = 0xFD70, Loading Loading @@ -5311,7 +5312,17 @@ packet LeGetVendorCapabilitiesComplete096 : LeGetVendorCapabilitiesComplete095 { packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 { a2dp_source_offload_capability_mask: 32, bluetooth_quality_report_support: 8 bluetooth_quality_report_support: 8, _payload_, } packet LeGetVendorCapabilitiesComplete103 : LeGetVendorCapabilitiesComplete098 { dynamic_audio_buffer_support : 32, _payload_, } test LeGetVendorCapabilitiesComplete103 { "\x0e\x1c\x01\x53\xfd\x00\x10\x01\x00\x28\x00\x01\x3e\x01\x03\x01\x14\x00\x01\x01\x00\x23\x00\x00\x00\x01\x23\x00\x00\x00", } enum SubOcf : 8 { Loading Loading @@ -5780,6 +5791,60 @@ test ControllerBqrComplete { "\x0e\x08\x01\x5e\xfd\x00\x1f\x00\x07\x00", } enum DabCommand : 8 { GET_AUDIO_BUFFER_TIME_CAPABILITY = 0x01, SET_AUDIO_BUFFER_TIME = 0x02, } packet DynamicAudioBuffer : VendorCommand (op_code = DYNAMIC_AUDIO_BUFFER) { dab_command : DabCommand, _body_, } packet DynamicAudioBufferComplete : CommandComplete (command_op_code = DYNAMIC_AUDIO_BUFFER) { status : ErrorCode, dab_command : DabCommand, _body_, } packet DabGetAudioBufferTimeCapability : DynamicAudioBuffer (dab_command = GET_AUDIO_BUFFER_TIME_CAPABILITY) { } test DabGetAudioBufferTimeCapability { "\x5f\xfd\x01\x01", } struct DynamicAudioBufferCodecCapability { default_time_ms : 16, maximum_time_ms : 16, minimum_time_ms : 16, } packet DabGetAudioBufferTimeCapabilityComplete : DynamicAudioBufferComplete (dab_command = GET_AUDIO_BUFFER_TIME_CAPABILITY) { audio_codec_type_supported : 32, audio_codec_capabilities : DynamicAudioBufferCodecCapability[32], } test DabGetAudioBufferTimeCapabilityComplete { "\x0e\xc9\x01\x5f\xfd\x00\x01\x03\x00\x00\x00\xf4\x01\xf4\x01\x64\x00\xf4\x01\xf4\x01\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", } packet DabSetAudioBufferTime : DynamicAudioBuffer(dab_command = SET_AUDIO_BUFFER_TIME) { buffer_time_ms : 16, // Requested audio buffer time for the currently used codec. } test DabSetAudioBufferTime { "\x5f\xfd\x03\x02\x23\x01", } packet DabSetAudioBufferTimeComplete : DynamicAudioBufferComplete (dab_command = SET_AUDIO_BUFFER_TIME) { current_buffer_time_ms : 16, } test DabSetAudioBufferTimeComplete { "\x0e\x07\x01\x5f\xfd\x00\x02\x23\x01", } // HCI Event Packets packet InquiryComplete : Event (event_code = INQUIRY_COMPLETE) { Loading Loading
system/gd/hci/controller.cc +167 −50 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "hci_controller_generated.h" #include "os/log.h" #include "os/metrics.h" #include "os/system_properties.h" #include "sysprops/sysprops_module.h" Loading Loading @@ -196,9 +197,16 @@ struct Controller::impl { // Skip vendor capabilities check if configured. if (os::GetSystemPropertyBool( kPropertyVendorCapabilitiesEnabled, kDefaultVendorCapabilitiesEnabled)) { // More commands can be enqueued from le_get_vendor_capabilities_handler std::promise<void> vendor_promise; auto vendor_future = vendor_promise.get_future(); hci_->EnqueueCommand( LeGetVendorCapabilitiesBuilder::Create(), handler->BindOnceOn(this, &Controller::impl::le_get_vendor_capabilities_handler)); handler->BindOnceOn( this, &Controller::impl::le_get_vendor_capabilities_handler, std::move(vendor_promise))); vendor_future.wait(); } else { vendor_capabilities_.is_supported_ = 0x00; } Loading Loading @@ -531,7 +539,8 @@ struct Controller::impl { le_periodic_advertiser_list_size_ = complete_view.GetPeriodicAdvertiserListSize(); } void le_get_vendor_capabilities_handler(CommandCompleteView view) { void le_get_vendor_capabilities_handler( std::promise<void> vendor_promise, CommandCompleteView view) { auto complete_view = LeGetVendorCapabilitiesCompleteView::Create(view); vendor_capabilities_.is_supported_ = 0x00; Loading @@ -551,7 +560,10 @@ struct Controller::impl { vendor_capabilities_.a2dp_source_offload_capability_mask_ = 0x00; vendor_capabilities_.bluetooth_quality_report_support_ = 0x00; if (complete_view.IsValid()) { if (!complete_view.IsValid()) { vendor_promise.set_value(); return; } vendor_capabilities_.is_supported_ = 0x01; // v0.55 Loading @@ -559,20 +571,25 @@ struct Controller::impl { vendor_capabilities_.max_advt_instances_ = base_vendor_capabilities.max_advt_instances_; vendor_capabilities_.offloaded_resolution_of_private_address_ = base_vendor_capabilities.offloaded_resolution_of_private_address_; vendor_capabilities_.total_scan_results_storage_ = base_vendor_capabilities.total_scan_results_storage_; vendor_capabilities_.total_scan_results_storage_ = base_vendor_capabilities.total_scan_results_storage_; vendor_capabilities_.max_irk_list_sz_ = base_vendor_capabilities.max_irk_list_sz_; vendor_capabilities_.filtering_support_ = base_vendor_capabilities.filtering_support_; vendor_capabilities_.max_filter_ = base_vendor_capabilities.max_filter_; vendor_capabilities_.activity_energy_info_support_ = base_vendor_capabilities.activity_energy_info_support_; vendor_capabilities_.activity_energy_info_support_ = base_vendor_capabilities.activity_energy_info_support_; if (complete_view.GetPayload().size() == 0) { vendor_capabilities_.version_supported_ = 55; vendor_promise.set_value(); return; } // v0.95 auto v95 = LeGetVendorCapabilitiesComplete095View::Create(complete_view); if (!v95.IsValid()) { LOG_ERROR("invalid data for hci requirements v0.95"); LOG_INFO("invalid data for hci requirements v0.95"); vendor_promise.set_value(); return; } vendor_capabilities_.version_supported_ = v95.GetVersionSupported(); Loading @@ -580,29 +597,108 @@ struct Controller::impl { vendor_capabilities_.extended_scan_support_ = v95.GetExtendedScanSupport(); vendor_capabilities_.debug_logging_supported_ = v95.GetDebugLoggingSupported(); if (vendor_capabilities_.version_supported_ <= 95 || complete_view.GetPayload().size() == 0) { vendor_promise.set_value(); return; } // v0.96 auto v96 = LeGetVendorCapabilitiesComplete096View::Create(v95); if (!v96.IsValid()) { LOG_ERROR("invalid data for hci requirements v0.96"); LOG_INFO("invalid data for hci requirements v0.96"); vendor_promise.set_value(); return; } vendor_capabilities_.le_address_generation_offloading_support_ = v96.GetLeAddressGenerationOffloadingSupport(); vendor_capabilities_.le_address_generation_offloading_support_ = v96.GetLeAddressGenerationOffloadingSupport(); if (vendor_capabilities_.version_supported_ <= 96 || complete_view.GetPayload().size() == 0) { vendor_promise.set_value(); return; } // v0.98 auto v98 = LeGetVendorCapabilitiesComplete098View::Create(v96); if (!v98.IsValid()) { LOG_ERROR("invalid data for hci requirements v0.98"); LOG_INFO("invalid data for hci requirements v0.98"); vendor_promise.set_value(); return; } vendor_capabilities_.a2dp_source_offload_capability_mask_ = v98.GetA2dpSourceOffloadCapabilityMask(); vendor_capabilities_.a2dp_source_offload_capability_mask_ = v98.GetA2dpSourceOffloadCapabilityMask(); vendor_capabilities_.bluetooth_quality_report_support_ = v98.GetBluetoothQualityReportSupport(); // v1.03 auto v103 = LeGetVendorCapabilitiesComplete103View::Create(v98); if (!v103.IsValid()) { LOG_INFO("invalid data for hci requirements v1.03"); vendor_promise.set_value(); return; } vendor_capabilities_.dynamic_audio_buffer_support_ = v103.GetDynamicAudioBufferSupport(); if (vendor_capabilities_.dynamic_audio_buffer_support_ == 0) { vendor_promise.set_value(); return; } hci_->EnqueueCommand( DabGetAudioBufferTimeCapabilityBuilder::Create(), module_.GetHandler()->BindOnceOn( this, &Controller::impl::le_get_dynamic_audio_buffer_support_handler, std::move(vendor_promise))); } void le_get_dynamic_audio_buffer_support_handler( std::promise<void> vendor_promise, CommandCompleteView view) { vendor_promise.set_value(); auto dab_complete_view = DynamicAudioBufferCompleteView::Create(view); if (!dab_complete_view.IsValid()) { LOG_WARN("Invalid command complete"); return; } if (dab_complete_view.GetStatus() != ErrorCode::SUCCESS) { LOG_WARN("Unexpected error code %s", ErrorCodeText(dab_complete_view.GetStatus()).c_str()); return; } auto complete_view = DabGetAudioBufferTimeCapabilityCompleteView::Create(dab_complete_view); if (!complete_view.IsValid()) { LOG_WARN("Invalid get complete"); return; } dab_supported_codecs_ = complete_view.GetAudioCodecTypeSupported(); dab_codec_capabilities_ = complete_view.GetAudioCodecCapabilities(); } void set_controller_dab_audio_buffer_time_complete(CommandCompleteView complete) { auto dab_complete = DynamicAudioBufferCompleteView::Create(complete); if (!dab_complete.IsValid()) { LOG_WARN("Invalid command complete"); return; } if (dab_complete.GetStatus() != ErrorCode::SUCCESS) { LOG_WARN("Unexpected return code %s", ErrorCodeText(dab_complete.GetStatus()).c_str()); return; } auto dab_set_complete = DabSetAudioBufferTimeCompleteView::Create(dab_complete); if (!dab_set_complete.IsValid()) { LOG_WARN("Invalid set complete"); return; } LOG_INFO( "Configured Media Tx Buffer, time returned = %d", dab_set_complete.GetCurrentBufferTimeMs()); } void set_controller_dab_audio_buffer_time(uint16_t buffer_time_ms) { hci_->EnqueueCommand( DabSetAudioBufferTimeBuilder::Create(buffer_time_ms), module_.GetHandler()->BindOnceOn( this, &Controller::impl::set_controller_dab_audio_buffer_time_complete)); } void set_event_mask(uint64_t event_mask) { Loading Loading @@ -1033,6 +1129,8 @@ struct Controller::impl { return vendor_capabilities_.a2dp_source_offload_capability_mask_ != 0x00; case OpCode::CONTROLLER_BQR: return vendor_capabilities_.bluetooth_quality_report_support_ == 0x01; case OpCode::DYNAMIC_AUDIO_BUFFER: return vendor_capabilities_.dynamic_audio_buffer_support_ > 0x00; // Before MSFT extension is fully supported, return false for the following MSFT_OPCODE_XXXX for now. case OpCode::MSFT_OPCODE_INTEL: return false; Loading Loading @@ -1095,6 +1193,8 @@ struct Controller::impl { uint8_t le_number_supported_advertising_sets_{}; uint8_t le_periodic_advertiser_list_size_{}; VendorCapabilities vendor_capabilities_{}; uint32_t dab_supported_codecs_{}; std::array<DynamicAudioBufferCodecCapability, 32> dab_codec_capabilities_{}; }; // namespace hci Controller::Controller() : impl_(std::make_unique<impl>(*this)) {} Loading Loading @@ -1365,6 +1465,23 @@ Controller::VendorCapabilities Controller::GetVendorCapabilities() const { return impl_->vendor_capabilities_; } uint32_t Controller::GetDabSupportedCodecs() const { return impl_->dab_supported_codecs_; } const std::array<DynamicAudioBufferCodecCapability, 32>& Controller::GetDabCodecCapabilities() const { return impl_->dab_codec_capabilities_; } void Controller::SetDabAudioBufferTime(uint16_t buffer_time_ms) { if (impl_->vendor_capabilities_.dynamic_audio_buffer_support_ == 0) { LOG_WARN("Dynamic Audio Buffer not supported"); return; } impl_->set_controller_dab_audio_buffer_time(buffer_time_ms); } uint8_t Controller::GetLePeriodicAdvertiserListSize() const { return impl_->le_periodic_advertiser_list_size_; } Loading
system/gd/hci/controller.h +6 −0 Original line number Diff line number Diff line Loading @@ -203,10 +203,16 @@ class Controller : public Module { uint8_t le_address_generation_offloading_support_; uint32_t a2dp_source_offload_capability_mask_; uint8_t bluetooth_quality_report_support_; uint32_t dynamic_audio_buffer_support_; }; virtual VendorCapabilities GetVendorCapabilities() const; virtual uint32_t GetDabSupportedCodecs() const; virtual const std::array<DynamicAudioBufferCodecCapability, 32>& GetDabCodecCapabilities() const; virtual void SetDabAudioBufferTime(uint16_t buffer_time_ms); virtual bool IsSupported(OpCode op_code) const; static const ModuleFactory Factory; Loading
system/gd/hci/controller_test.cc +113 −17 Original line number Diff line number Diff line Loading @@ -49,6 +49,8 @@ constexpr uint16_t kCredits1 = 0x78; constexpr uint16_t kHandle2 = 0x456; constexpr uint16_t kCredits2 = 0x9a; constexpr uint64_t kRandomNumber = 0x123456789abcdef0; /*sbc_supported= 1, aac_supported= 1, aptx_supported= 0, aptx_hd_supported= 0, ldac_supported= 1 */ constexpr uint32_t kDynamicAudioBufferSupport = 0x13; uint16_t feature_spec_version = 55; constexpr char title[] = "hci_controller_test"; Loading Loading @@ -171,7 +173,8 @@ class HciLayerFakeForController : public HciLayerFake { event_builder = LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0xF0); } break; case (OpCode::LE_GET_VENDOR_CAPABILITIES): { case (OpCode::LE_GET_VENDOR_CAPABILITIES): if (vendor_capabilities_ == nullptr) { BaseVendorCapabilities base_vendor_capabilities; base_vendor_capabilities.max_advt_instances_ = 0x10; base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01; Loading @@ -183,12 +186,37 @@ class HciLayerFakeForController : public HciLayerFake { auto payload = std::make_unique<RawBuilder>(); if (feature_spec_version > 55) { std::vector<uint8_t> payload_bytes = {0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00}; std::vector<uint8_t> payload_bytes = { 0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00}; payload->AddOctets2(feature_spec_version); payload->AddOctets(payload_bytes); } event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create( num_packets, ErrorCode::SUCCESS, base_vendor_capabilities, std::move(payload)); } else { event_builder = std::move(vendor_capabilities_); vendor_capabilities_.reset(); } break; case (OpCode::DYNAMIC_AUDIO_BUFFER): { auto dab_command = DynamicAudioBufferView::CreateOptional(VendorCommandView::Create(command)); if (dab_command->GetDabCommand() == DabCommand::GET_AUDIO_BUFFER_TIME_CAPABILITY) { std::array<DynamicAudioBufferCodecCapability, 32> capabilities{}; capabilities[0] = DynamicAudioBufferCodecCapability(0x123, 0x103, 0x1234); // sbc_capabilities capabilities[1] = DynamicAudioBufferCodecCapability(0x223, 0x123, 0x2340); // aac_capabilities capabilities[4] = DynamicAudioBufferCodecCapability(0x323, 0x223, 0x3456); // ldac_capabilities event_builder = DabGetAudioBufferTimeCapabilityCompleteBuilder::Create( 1, ErrorCode::SUCCESS, kDynamicAudioBufferSupport, capabilities); } else { auto set_command = DabSetAudioBufferTimeView::CreateOptional(*dab_command); dynamic_audio_buffer_time = set_command->GetBufferTimeMs(); event_builder = DabSetAudioBufferTimeCompleteBuilder::Create( 1, ErrorCode::SUCCESS, dynamic_audio_buffer_time); } } break; case (OpCode::SET_EVENT_MASK): { auto view = SetEventMaskView::Create(command); Loading Loading @@ -240,12 +268,14 @@ class HciLayerFakeForController : public HciLayerFake { IncomingEvent(NumberOfCompletedPacketsBuilder::Create(completed_packets)); } std::unique_ptr<EventBuilder> vendor_capabilities_ = nullptr; constexpr static uint16_t acl_data_packet_length = 1024; constexpr static uint8_t synchronous_data_packet_length = 60; constexpr static uint16_t total_num_acl_data_packets = 10; constexpr static uint16_t total_num_synchronous_data_packets = 12; uint64_t event_mask = 0; uint64_t le_event_mask = 0; uint16_t dynamic_audio_buffer_time = 0; }; class ControllerTest : public ::testing::Test { Loading @@ -254,6 +284,8 @@ class ControllerTest : public ::testing::Test { feature_spec_version = feature_spec_version_; bluetooth::common::InitFlags::SetAllForTesting(); test_hci_layer_ = new HciLayerFakeForController; test_hci_layer_->vendor_capabilities_ = std::move(vendor_capabilities_); vendor_capabilities_.reset(); fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); fake_registry_.Start<Controller>(&thread_); Loading @@ -270,6 +302,7 @@ class ControllerTest : public ::testing::Test { Controller* controller_ = nullptr; os::Handler* client_handler_ = nullptr; uint16_t feature_spec_version_ = 98; std::unique_ptr<EventBuilder> vendor_capabilities_ = nullptr; }; } // namespace Loading Loading @@ -297,6 +330,35 @@ class Controller096Test : public ControllerTest { } }; class Controller103Test : public ControllerTest { protected: void SetUp() override { feature_spec_version_ = 0x100 + 0x03; BaseVendorCapabilities base_vendor_capabilities; base_vendor_capabilities.max_advt_instances_ = 0x10; base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01; base_vendor_capabilities.total_scan_results_storage_ = 0x2800; base_vendor_capabilities.max_irk_list_sz_ = 0x20; base_vendor_capabilities.filtering_support_ = 0x01; base_vendor_capabilities.max_filter_ = 0x10; base_vendor_capabilities.activity_energy_info_support_ = 0x01; vendor_capabilities_ = LeGetVendorCapabilitiesComplete103Builder::Create( 1, ErrorCode::SUCCESS, base_vendor_capabilities, feature_spec_version_, 0x102, /*extended_scan_support=*/1, /*debug_logging_supported=*/1, /*le_address_generation_offloading_support=*/0, /*a2dp_source_offload_capability_mask=*/0x4, /*bluetooth_quality_report_support=*/1, kDynamicAudioBufferSupport, std::make_unique<RawBuilder>()); ControllerTest::SetUp(); } }; TEST_F(ControllerTest, startup_teardown) {} TEST_F(ControllerTest, read_controller_info) { Loading Loading @@ -430,6 +492,40 @@ TEST_F(ControllerTest, feature_spec_version_098_test) { ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); } TEST_F(ControllerTest, feature_spec_version_098_no_dab_test) { ASSERT_FALSE(controller_->IsSupported(OpCode::DYNAMIC_AUDIO_BUFFER)); } TEST_F(ControllerTest, set_dynamic_audio_buffer_time) { controller_->SetDabAudioBufferTime(123); thread_.GetReactor()->WaitForIdle(std::chrono::seconds(1)); ASSERT_EQ(0, test_hci_layer_->dynamic_audio_buffer_time); } TEST_F(Controller103Test, feature_spec_version_103_dab_test) { ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 0x100 + 3); ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT)); ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO)); ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); ASSERT_TRUE(controller_->IsSupported(OpCode::DYNAMIC_AUDIO_BUFFER)); ASSERT_EQ(controller_->GetDabSupportedCodecs(), kDynamicAudioBufferSupport); for (size_t bit = 0; bit < 32; bit++) { if (kDynamicAudioBufferSupport & (1u << bit)) { ASSERT_GT(controller_->GetDabCodecCapabilities()[bit].maximum_time_ms_, 0) << " bit " << bit; } else { ASSERT_EQ(controller_->GetDabCodecCapabilities()[bit].maximum_time_ms_, 0); ASSERT_EQ(controller_->GetDabCodecCapabilities()[bit].minimum_time_ms_, 0); ASSERT_EQ(controller_->GetDabCodecCapabilities()[bit].default_time_ms_, 0); } } } TEST_F(Controller103Test, set_dynamic_audio_buffer_time) { controller_->SetDabAudioBufferTime(123); thread_.GetReactor()->WaitForIdle(std::chrono::seconds(1)); ASSERT_EQ(123, test_hci_layer_->dynamic_audio_buffer_time); } std::promise<void> credits1_set; std::promise<void> credits2_set; Loading
system/pdl/hci/hci_packets.pdl +67 −2 Original line number Diff line number Diff line Loading @@ -456,6 +456,7 @@ enum OpCode : 16 { CONTROLLER_DEBUG_INFO = 0xFD5B, CONTROLLER_A2DP_OPCODE = 0xFD5D, CONTROLLER_BQR = 0xFD5E, DYNAMIC_AUDIO_BUFFER = 0xFD5F, // MSFT_OPCODE_xxxx below are needed for the tests. MSFT_OPCODE_MEDIATEK = 0xFD30, MSFT_OPCODE_QUALCOMM = 0xFD70, Loading Loading @@ -5311,7 +5312,17 @@ packet LeGetVendorCapabilitiesComplete096 : LeGetVendorCapabilitiesComplete095 { packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 { a2dp_source_offload_capability_mask: 32, bluetooth_quality_report_support: 8 bluetooth_quality_report_support: 8, _payload_, } packet LeGetVendorCapabilitiesComplete103 : LeGetVendorCapabilitiesComplete098 { dynamic_audio_buffer_support : 32, _payload_, } test LeGetVendorCapabilitiesComplete103 { "\x0e\x1c\x01\x53\xfd\x00\x10\x01\x00\x28\x00\x01\x3e\x01\x03\x01\x14\x00\x01\x01\x00\x23\x00\x00\x00\x01\x23\x00\x00\x00", } enum SubOcf : 8 { Loading Loading @@ -5780,6 +5791,60 @@ test ControllerBqrComplete { "\x0e\x08\x01\x5e\xfd\x00\x1f\x00\x07\x00", } enum DabCommand : 8 { GET_AUDIO_BUFFER_TIME_CAPABILITY = 0x01, SET_AUDIO_BUFFER_TIME = 0x02, } packet DynamicAudioBuffer : VendorCommand (op_code = DYNAMIC_AUDIO_BUFFER) { dab_command : DabCommand, _body_, } packet DynamicAudioBufferComplete : CommandComplete (command_op_code = DYNAMIC_AUDIO_BUFFER) { status : ErrorCode, dab_command : DabCommand, _body_, } packet DabGetAudioBufferTimeCapability : DynamicAudioBuffer (dab_command = GET_AUDIO_BUFFER_TIME_CAPABILITY) { } test DabGetAudioBufferTimeCapability { "\x5f\xfd\x01\x01", } struct DynamicAudioBufferCodecCapability { default_time_ms : 16, maximum_time_ms : 16, minimum_time_ms : 16, } packet DabGetAudioBufferTimeCapabilityComplete : DynamicAudioBufferComplete (dab_command = GET_AUDIO_BUFFER_TIME_CAPABILITY) { audio_codec_type_supported : 32, audio_codec_capabilities : DynamicAudioBufferCodecCapability[32], } test DabGetAudioBufferTimeCapabilityComplete { "\x0e\xc9\x01\x5f\xfd\x00\x01\x03\x00\x00\x00\xf4\x01\xf4\x01\x64\x00\xf4\x01\xf4\x01\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", } packet DabSetAudioBufferTime : DynamicAudioBuffer(dab_command = SET_AUDIO_BUFFER_TIME) { buffer_time_ms : 16, // Requested audio buffer time for the currently used codec. } test DabSetAudioBufferTime { "\x5f\xfd\x03\x02\x23\x01", } packet DabSetAudioBufferTimeComplete : DynamicAudioBufferComplete (dab_command = SET_AUDIO_BUFFER_TIME) { current_buffer_time_ms : 16, } test DabSetAudioBufferTimeComplete { "\x0e\x07\x01\x5f\xfd\x00\x02\x23\x01", } // HCI Event Packets packet InquiryComplete : Event (event_code = INQUIRY_COMPLETE) { Loading