From b6134e0496b6d5fbe8b95fcf779104f43e498376 Mon Sep 17 00:00:00 2001 From: Bao Do <quocbaodo@google.com> Date: Wed, 6 Dec 2023 03:30:46 +0000 Subject: [PATCH] HFP Audio client - Decode session implementation Bug: 294134504 Bug: 315234036 Test: mmm packages/modules/Bluetooth/system/audio_hal_interface Change-Id: I7a75782aadaa5135ed9ed83d77d077ff5eeead9f --- .../hfp_client_interface.cc | 213 ++++++++++++++++++ .../hfp_client_interface.h | 32 ++- system/bta/ag/bta_ag_int.h | 1 + system/bta/ag/bta_ag_sco.cc | 4 + 4 files changed, 242 insertions(+), 8 deletions(-) create mode 100644 system/audio_hal_interface/hfp_client_interface.cc diff --git a/system/audio_hal_interface/hfp_client_interface.cc b/system/audio_hal_interface/hfp_client_interface.cc new file mode 100644 index 00000000000..c7e4c5a1f16 --- /dev/null +++ b/system/audio_hal_interface/hfp_client_interface.cc @@ -0,0 +1,213 @@ +/* + * Copyright 2023 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 <cstdint> + +#define LOG_TAG "BTAudioClientHfpStub" + +#include "aidl/client_interface_aidl.h" +#include "aidl/hfp_client_interface_aidl.h" +#include "hal_version_manager.h" +#include "hfp_client_interface.h" +#include "osi/include/log.h" +#include "osi/include/properties.h" + +using ::bluetooth::audio::aidl::hfp::HfpDecodingTransport; +using AudioConfiguration = + ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; +using ::aidl::android::hardware::bluetooth::audio::ChannelMode; +using ::aidl::android::hardware::bluetooth::audio::CodecId; +using ::aidl::android::hardware::bluetooth::audio::HfpConfiguration; +using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; + +namespace bluetooth { +namespace audio { +namespace hfp { + +// Helper functions +aidl::BluetoothAudioSinkClientInterface* get_decode_client_interface() { + return HfpDecodingTransport::active_hal_interface; +} + +HfpDecodingTransport* get_decode_transport_instance() { + return HfpDecodingTransport::instance_; +} + +PcmConfiguration get_default_pcm_configuration() { + PcmConfiguration pcm_config{ + .sampleRateHz = 8000, + .channelMode = ChannelMode::MONO, + .bitsPerSample = 16, + }; + return pcm_config; +} + +HfpConfiguration get_default_hfp_configuration() { + HfpConfiguration hfp_config{ + .codecId = CodecId::Core::CVSD, + .connectionHandle = 6, + .nrec = false, + .controllerCodec = true, + }; + return hfp_config; +} + +CodecId get_codec_id_by_peer_codec(tBTA_AG_PEER_CODEC sco_codec) { + if (sco_codec & BTM_SCO_CODEC_LC3) return CodecId::Core::LC3; + if (sco_codec & BTM_SCO_CODEC_MSBC) return CodecId::Core::MSBC; + if (sco_codec & BTM_SCO_CODEC_CVSD) return CodecId::Core::CVSD; + // Unknown vendor codec otherwise + CodecId codec_id = CodecId::Vendor(); + return codec_id; +} + +AudioConfiguration offload_config_to_hal_audio_config( + const ::hfp::offload_config& offload_config) { + HfpConfiguration hfp_config{ + .codecId = get_codec_id_by_peer_codec(offload_config.sco_codec), + .connectionHandle = offload_config.connection_handle, + .nrec = offload_config.is_nrec, + .controllerCodec = offload_config.is_controller_codec, + }; + return AudioConfiguration(hfp_config); +} + +bool is_hal_enabled() { + return !osi_property_get_bool(BLUETOOTH_AUDIO_HAL_PROP_DISABLED, false); +} + +bool is_aidl_support_hfp() { + return HalVersionManager::GetHalTransport() == + BluetoothAudioHalTransport::AIDL && + HalVersionManager::GetHalVersion() >= + BluetoothAudioHalVersion::VERSION_AIDL_V4; +} + +// Decode client implementation +void HfpClientInterface::Decode::Cleanup() { + LOG(INFO) << __func__ << " decode"; + StopSession(); + if (HfpDecodingTransport::instance_) { + delete HfpDecodingTransport::software_hal_interface; + HfpDecodingTransport::software_hal_interface = nullptr; + delete HfpDecodingTransport::instance_; + HfpDecodingTransport::instance_ = nullptr; + } +} + +void HfpClientInterface::Decode::StartSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " decode"; + AudioConfiguration audio_config; + audio_config.set<AudioConfiguration::pcmConfig>( + get_default_pcm_configuration()); + if (!get_decode_client_interface()->UpdateAudioConfig(audio_config)) { + LOG(ERROR) << __func__ << ": cannot update audio config to HAL"; + return; + } + get_decode_client_interface()->StartSession(); +} + +void HfpClientInterface::Decode::StopSession() { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + LOG(INFO) << __func__ << " decode"; + get_decode_client_interface()->EndSession(); + if (get_decode_transport_instance()) { + get_decode_transport_instance()->ResetPendingCmd(); + get_decode_transport_instance()->ResetPresentationPosition(); + } +} + +void HfpClientInterface::Decode::UpdateAudioConfigToHal( + const ::hfp::offload_config& offload_config) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return; + } + + LOG(INFO) << __func__ << " decode"; + get_decode_client_interface()->UpdateAudioConfig( + offload_config_to_hal_audio_config(offload_config)); +} + +size_t HfpClientInterface::Decode::Read(uint8_t* p_buf, uint32_t len) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return 0; + } + LOG(INFO) << __func__ << " decode"; + return get_decode_client_interface()->ReadAudioData(p_buf, len); +} + +HfpClientInterface::Decode* HfpClientInterface::GetDecode( + bluetooth::common::MessageLoopThread* message_loop) { + if (!is_aidl_support_hfp()) { + LOG(WARNING) << __func__ << ": Unsupported HIDL or AIDL version"; + return nullptr; + } + + if (decode_ == nullptr) { + decode_ = new Decode(); + } else { + LOG(WARNING) << __func__ << ": Decode is already acquired"; + return nullptr; + } + + LOG(INFO) << __func__ << " decode"; + + HfpDecodingTransport::instance_ = new HfpDecodingTransport( + aidl::SessionType::HFP_SOFTWARE_DECODING_DATAPATH); + HfpDecodingTransport::software_hal_interface = + new aidl::BluetoothAudioSinkClientInterface( + HfpDecodingTransport::instance_, message_loop); + if (!HfpDecodingTransport::software_hal_interface->IsValid()) { + LOG(WARNING) << __func__ << ": BluetoothAudio HAL for HFP is invalid"; + delete HfpDecodingTransport::software_hal_interface; + HfpDecodingTransport::software_hal_interface = nullptr; + delete HfpDecodingTransport::instance_; + return nullptr; + } + + HfpDecodingTransport::active_hal_interface = + HfpDecodingTransport::software_hal_interface; + + return decode_; +} + +bool HfpClientInterface::ReleaseDecode(HfpClientInterface::Decode* decode) { + if (decode != decode_) { + LOG(WARNING) << __func__ << ", can't release not acquired decode"; + return false; + } + + LOG(INFO) << __func__ << " decode"; + if (get_decode_client_interface()) decode->Cleanup(); + + delete decode_; + decode_ = nullptr; + + return true; +} + +} // namespace hfp +} // namespace audio +} // namespace bluetooth diff --git a/system/audio_hal_interface/hfp_client_interface.h b/system/audio_hal_interface/hfp_client_interface.h index a8810bdc777..05cd5b21ae2 100644 --- a/system/audio_hal_interface/hfp_client_interface.h +++ b/system/audio_hal_interface/hfp_client_interface.h @@ -59,17 +59,32 @@ class HfpClientInterface { size_t Write(const uint8_t* p_buf, uint32_t len); }; - // Get HFP sink client interface if it's not previously acquired and not - // yet released. + class Offload : public IClientInterfaceEndpoint { + public: + virtual ~Offload() = default; + + void Cleanup() override; + void StartSession() override; + void StopSession() override; + void UpdateAudioConfigToHal(const ::hfp::offload_config& config) override; + }; + + // Get HFP software decoding client interface if it's not previously acquired + // and not yet released. Decode* GetDecode(bluetooth::common::MessageLoopThread* message_loop); - // Release sink interface if belongs to HFP client interface - bool ReleaseDecode(Decode* sink); + // Release interface if belongs to HFP client interface + bool ReleaseDecode(Decode* decode); - // Get HFP source client interface if it's not previously acquired and - // not yet released. + // Get HFP software encoding client interface if it's not previously acquired + // and not yet released. Encode* GetEncode(bluetooth::common::MessageLoopThread* message_loop); - // Release source interface if belongs to HFP client interface - bool ReleaseEncode(Encode* source); + // Release interface if belongs to HFP client interface + bool ReleaseEncode(Encode* encode); + + // Get HFP offload client interface + Offload GetOffload(bluetooth::common::MessageLoopThread* message_loop); + // Release offload interface if belongs to HFP client interface + bool ReleaseOffload(Encode* encode); // Get interface, if previously not initialized - it'll initialize singleton. static HfpClientInterface* Get(); @@ -78,6 +93,7 @@ class HfpClientInterface { static HfpClientInterface* interface; Decode* decode_ = nullptr; Encode* encode_ = nullptr; + Offload* offload_ = nullptr; }; } // namespace hfp } // namespace audio diff --git a/system/bta/ag/bta_ag_int.h b/system/bta/ag/bta_ag_int.h index 57f6704e16c..41b0ac90492 100644 --- a/system/bta/ag/bta_ag_int.h +++ b/system/bta/ag/bta_ag_int.h @@ -429,6 +429,7 @@ void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result); void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb); bool bta_ag_is_sco_open_allowed(tBTA_AG_SCB* p_scb, const std::string event); void bta_ag_send_bcs(tBTA_AG_SCB* p_scb); +bool bta_ag_get_sco_offload_enabled(); void bta_ag_set_sco_offload_enabled(bool value); void bta_ag_set_sco_allowed(bool value); const RawAddress& bta_ag_get_active_device(); diff --git a/system/bta/ag/bta_ag_sco.cc b/system/bta/ag/bta_ag_sco.cc index bda5d95be2a..a2e3e57b916 100644 --- a/system/bta/ag/bta_ag_sco.cc +++ b/system/bta/ag/bta_ag_sco.cc @@ -1522,6 +1522,10 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb, bta_ag_create_pending_sco(p_scb, bta_ag_cb.sco.is_local); } +bool bta_ag_get_sco_offload_enabled() { + return hfp_hal_interface::get_offload_enabled(); +} + void bta_ag_set_sco_offload_enabled(bool value) { hfp_hal_interface::enable_offload(value); } -- GitLab