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