/* * * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "iso_manager_impl.h" #include "common/bind.h" #include "hci/hci_packets.h" #include "iso/iso_manager.h" #include "os/handler.h" #include "os/log.h" #include "packet/raw_builder.h" namespace bluetooth { namespace iso { namespace internal { using bluetooth::hci::IsoBuilder; IsoManagerImpl::IsoManagerImpl(os::Handler* iso_handler, hci::HciLayer* hci_layer, hci::Controller* controller) : iso_handler_(iso_handler), hci_layer_(hci_layer), hci_le_iso_interface_(hci_layer->GetLeIsoInterface(iso_handler_->BindOn(this, &IsoManagerImpl::OnHciLeEvent))), controller_(controller) { hci_layer_->GetIsoQueueEnd()->RegisterDequeue( iso_handler_, common::Bind(&IsoManagerImpl::OnIncomingPacket, common::Unretained(this))); iso_enqueue_buffer_ = std::make_unique>(hci_layer_->GetIsoQueueEnd()); } IsoManagerImpl::~IsoManagerImpl() { hci_layer_->GetIsoQueueEnd()->UnregisterDequeue(); iso_enqueue_buffer_ = nullptr; } void IsoManagerImpl::OnHciLeEvent(hci::LeMetaEventView event) { hci::SubeventCode code = event.GetSubeventCode(); if (code == hci::SubeventCode::CIS_ESTABLISHED) { hci::LeCisEstablishedView le_cis_established_view = hci::LeCisEstablishedView::Create(event); if (!le_cis_established_view.IsValid()) { LOG_ERROR("Invalid LeCisEstablishedView packet received"); return; } cis_established_callback.Invoke(le_cis_established_view.GetConnectionHandle()); return; } else if (code == hci::SubeventCode::CIS_REQUEST) { hci::LeCisRequestView le_cis_request_view = hci::LeCisRequestView::Create(event); if (!le_cis_request_view.IsValid()) { LOG_ERROR("Invalid LeCisRequestView packet received"); return; } hci_le_iso_interface_->EnqueueCommand( hci::LeAcceptCisRequestBuilder::Create(le_cis_request_view.GetCisConnectionHandle()), iso_handler_->BindOnce([](hci::CommandStatusView command_status) { LOG_INFO("command_status=%hhu ", command_status.GetStatus()); })); return; } LOG_ERROR("Unhandled HCI LE ISO event, code %s", hci::SubeventCodeText(code).c_str()); ASSERT_LOG(false, "Unhandled HCI LE ISO event"); } void IsoManagerImpl::SetCigParameters( uint8_t cig_id, uint32_t sdu_interval_m_to_s, uint32_t sdu_interval_s_to_m, hci::ClockAccuracy peripherals_clock_accuracy, hci::Packing packing, hci::Enable framing, uint16_t max_transport_latency_m_to_s, uint16_t max_transport_latency_s_to_m, const std::vector& cis_configs, SetCigParametersCallback command_complete_callback) { hci_le_iso_interface_->EnqueueCommand( hci::LeSetCigParametersBuilder::Create( cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_configs), iso_handler_->BindOnce( &IsoManagerImpl::SetCigParametersComplete, common::Unretained(this), cig_id, cis_configs, std::move(command_complete_callback))); } void IsoManagerImpl::SetCigParametersComplete( uint8_t cig_id, const std::vector& cis_configs, SetCigParametersCallback command_complete_callback, hci::CommandCompleteView command_complete) { ASSERT(command_complete.IsValid()); hci::LeSetCigParametersCompleteView setCigParamsComplete = hci::LeSetCigParametersCompleteView::Create(command_complete); ASSERT(setCigParamsComplete.IsValid()); if (setCigParamsComplete.GetStatus() == hci::ErrorCode::SUCCESS) { uint8_t cig_id_back_from_ctrl = setCigParamsComplete.GetCigId(); auto conn_handles = setCigParamsComplete.GetConnectionHandle(); ASSERT(cig_id_back_from_ctrl == cig_id); ASSERT(conn_handles.size() == cis_configs.size()); auto cis_it = cis_configs.begin(); auto handle_it = conn_handles.begin(); std::vector handles; while (cis_it != cis_configs.end()) { iso_connections_.push_back({ .cig_id = cig_id, .cis_id = cis_it->cis_id_, .connection_handle = *handle_it, }); handles.push_back(*handle_it); cis_it++; handle_it++; } command_complete_callback.Invoke(handles); } } void IsoManagerImpl::SetCigParametersTest( uint8_t cig_id, uint32_t sdu_interval_m_to_s, uint32_t sdu_interval_s_to_m, uint8_t ft_m_to_s, uint8_t ft_s_to_m, uint16_t iso_interval, hci::ClockAccuracy peripherals_clock_accuracy, hci::Packing packing, hci::Enable framing, uint16_t max_transport_latency_m_to_s, uint16_t max_transport_latency_s_to_m, const std::vector& cis_test_configs, SetCigParametersCallback command_complete_callback) { hci_le_iso_interface_->EnqueueCommand( hci::LeSetCigParametersTestBuilder::Create( cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m, iso_interval, peripherals_clock_accuracy, packing, framing, cis_test_configs), iso_handler_->BindOnce( &IsoManagerImpl::SetCigParametersTestComplete, common::Unretained(this), cig_id, cis_test_configs, std::move(command_complete_callback))); } void IsoManagerImpl::SetCigParametersTestComplete( uint8_t cig_id, const std::vector& cis_configs, SetCigParametersCallback command_complete_callback, hci::CommandCompleteView command_complete) { ASSERT(command_complete.IsValid()); hci::LeSetCigParametersTestCompleteView setCigParamsComplete = hci::LeSetCigParametersTestCompleteView::Create(command_complete); ASSERT(setCigParamsComplete.IsValid()); if (setCigParamsComplete.GetStatus() == hci::ErrorCode::SUCCESS) { uint8_t cig_id_back_from_ctrl = setCigParamsComplete.GetCigId(); auto conn_handles = setCigParamsComplete.GetConnectionHandle(); ASSERT(cig_id_back_from_ctrl == cig_id); ASSERT(conn_handles.size() == cis_configs.size()); auto cis_it = cis_configs.begin(); auto handle_it = conn_handles.begin(); std::vector handles; while (cis_it != cis_configs.end()) { iso_connections_.push_back({ .cig_id = cig_id, .cis_id = cis_it->cis_id_, .connection_handle = *handle_it, }); handles.push_back(*handle_it); cis_it++; handle_it++; } command_complete_callback.Invoke(handles); } } void IsoManagerImpl::LeCreateCis(std::vector> cis_and_acl_handles) { std::vector cis_configs; for (const auto& handle_pair : cis_and_acl_handles) { hci::CreateCisConfig config; config.cis_connection_handle_ = handle_pair.first; config.acl_connection_handle_ = handle_pair.second; cis_configs.push_back(config); } hci_le_iso_interface_->EnqueueCommand( hci::LeCreateCisBuilder::Create(cis_configs), iso_handler_->BindOnce([](hci::CommandStatusView command_status) { LOG_INFO("command_status=%hhu ", command_status.GetStatus()); })); } void IsoManagerImpl::RemoveCig(uint8_t cig_id) { ASSERT(IsKnownCig(cig_id)); hci_le_iso_interface_->EnqueueCommand( hci::LeRemoveCigBuilder::Create(cig_id), iso_handler_->BindOnce(&IsoManagerImpl::RemoveCigComplete, common::Unretained(this))); } void IsoManagerImpl::RemoveCigComplete(hci::CommandCompleteView command_complete) { ASSERT(command_complete.IsValid()); hci::LeRemoveCigCompleteView removeCigComplete = hci::LeRemoveCigCompleteView::Create(command_complete); ASSERT(removeCigComplete.IsValid()); } void IsoManagerImpl::SendIsoPacket(uint16_t cis_handle, std::vector packet) { auto builder = hci::IsoWithoutTimestampBuilder::Create( cis_handle, hci::IsoPacketBoundaryFlag::COMPLETE_SDU, 0 /* sequence_number*/, hci::IsoPacketStatusFlag::VALID, std::make_unique(packet)); LOG_INFO("%c%c", packet[0], packet[1]); iso_enqueue_buffer_->Enqueue(std::move(builder), iso_handler_); } void IsoManagerImpl::OnIncomingPacket() { std::unique_ptr packet = hci_layer_->GetIsoQueueEnd()->TryDequeue(); iso_data_callback.Invoke(std::move(packet)); } } // namespace internal } // namespace iso } // namespace bluetooth