Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fc5cb63 authored by Bao Do's avatar Bao Do
Browse files

HFP Audio client - AIDL client implementation

Bug: 294134504
Bug: 315234036
Test: mmm packages/modules/Bluetooth/system/audio_hal_interface
Change-Id: Ia4fc8cee0c13de3b27be0c413f74b1d4dc782d5b
parent f4672191
Loading
Loading
Loading
Loading
+241 −0
Original line number Diff line number Diff line
/*
 * 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.
 */
#define LOG_TAG "BTAudioHfpAIDL"

#include "hfp_client_interface_aidl.h"

#include <map>

#include "aidl/android/hardware/bluetooth/audio/AudioConfiguration.h"
#include "aidl/transport_instance.h"
#include "bta/ag/bta_ag_int.h"
#include "btif_hf.h"
#include "btm_api_types.h"
#include "hardware/bluetooth.h"
#include "hardware/bluetooth_headset_interface.h"
#include "types/raw_address.h"

namespace bluetooth {
namespace audio {
namespace aidl {
namespace hfp {

std::map<bt_status_t, BluetoothAudioCtrlAck> status_to_ack_map = {
    {BT_STATUS_SUCCESS, BluetoothAudioCtrlAck::SUCCESS_FINISHED},
    {BT_STATUS_DONE, BluetoothAudioCtrlAck::SUCCESS_FINISHED},
    {BT_STATUS_FAIL, BluetoothAudioCtrlAck::FAILURE},
    {BT_STATUS_NOT_READY, BluetoothAudioCtrlAck::FAILURE_BUSY},
    {BT_STATUS_BUSY, BluetoothAudioCtrlAck::FAILURE_BUSY},
    {BT_STATUS_UNSUPPORTED, BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED},
};

tBTA_AG_SCB* get_hfp_active_device_callback() {
  const RawAddress& addr = bta_ag_get_active_device();
  if (addr.IsEmpty()) {
    LOG(ERROR) << __func__ << ": No active device found";
    return nullptr;
  }
  auto idx = bta_ag_idx_by_bdaddr(&addr);
  if (idx == 0) {
    LOG(ERROR) << __func__ << ": No index found for active device";
    return nullptr;
  }
  auto cb = bta_ag_scb_by_idx(idx);
  if (cb == nullptr) {
    LOG(ERROR) << __func__ << ": No callback for the active device";
    return nullptr;
  }
  return cb;
}

HfpTransport::HfpTransport() { hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; }

BluetoothAudioCtrlAck HfpTransport::StartRequest() {
  if (hfp_pending_cmd_ == HFP_CTRL_CMD_START) {
    LOG(INFO) << __func__ << ": HFP_CTRL_CMD_START in progress";
    return BluetoothAudioCtrlAck::PENDING;
  } else if (hfp_pending_cmd_ != HFP_CTRL_CMD_NONE) {
    LOG(WARNING) << __func__ << ": busy in pending_cmd=" << hfp_pending_cmd_;
    return BluetoothAudioCtrlAck::FAILURE_BUSY;
  }

  auto cb = get_hfp_active_device_callback();
  if (cb == nullptr) return BluetoothAudioCtrlAck::FAILURE;

  if (bta_ag_sco_is_open(cb)) {
    // Already started, ACK back immediately.
    return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
  }

  /* Post start SCO event and wait for sco to open */
  hfp_pending_cmd_ = HFP_CTRL_CMD_START;
  auto status =
      bluetooth::headset::GetInterface()->ConnectAudio(&cb->peer_addr, 0);
  hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
  LOG(INFO) << __func__ << ": ConnectAudio status = " << status << " - "
            << bt_status_text(status).c_str();
  auto ctrl_ack = status_to_ack_map.find(status);
  if (ctrl_ack == status_to_ack_map.end())
    return BluetoothAudioCtrlAck::FAILURE;
  return ctrl_ack->second;
}

void HfpTransport::StopRequest() {
  LOG(INFO) << __func__ << ": handling";
  RawAddress addr = bta_ag_get_active_device();
  if (addr.IsEmpty()) {
    LOG(ERROR) << __func__ << ": No active device found";
    return;
  }
  hfp_pending_cmd_ = HFP_CTRL_CMD_STOP;
  auto status = bluetooth::headset::GetInterface()->DisconnectAudio(&addr);
  LOG(INFO) << __func__ << ": DisconnectAudio status = " << status << " - "
            << bt_status_text(status).c_str();
  hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
  return;
}

void HfpTransport::ResetPendingCmd() { hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; }

uint8_t HfpTransport::GetPendingCmd() const { return hfp_pending_cmd_; }

// Unimplemented functions
void HfpTransport::LogBytesProcessed(size_t bytes_read) {}

BluetoothAudioCtrlAck HfpTransport::SuspendRequest() {
  return BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED;
}

void HfpTransport::SetLatencyMode(LatencyMode latency_mode) {}

bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                             uint64_t* total_bytes_read,
                             timespec* data_position) {
  return false;
}

void HfpTransport::SourceMetadataChanged(
    const source_metadata_v7_t& source_metadata) {}

void HfpTransport::SinkMetadataChanged(const sink_metadata_v7_t&) {}

void HfpTransport::ResetPresentationPosition() {}

// Source / sink functions
HfpDecodingTransport::HfpDecodingTransport(SessionType session_type)
    : IBluetoothSinkTransportInstance(session_type, (AudioConfiguration){}) {
  transport_ = new HfpTransport();
};

HfpDecodingTransport::~HfpDecodingTransport() { delete transport_; }

BluetoothAudioCtrlAck HfpDecodingTransport::StartRequest(bool is_low_latency) {
  return transport_->StartRequest();
}

BluetoothAudioCtrlAck HfpDecodingTransport::SuspendRequest() {
  return transport_->SuspendRequest();
}

void HfpDecodingTransport::SetLatencyMode(LatencyMode latency_mode) {
  transport_->SetLatencyMode(latency_mode);
}

bool HfpDecodingTransport::GetPresentationPosition(
    uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written,
    timespec* data_position) {
  return transport_->GetPresentationPosition(
      remote_delay_report_ns, total_bytes_written, data_position);
}

void HfpDecodingTransport::SourceMetadataChanged(
    const source_metadata_v7_t& source_metadata) {
  transport_->SourceMetadataChanged(source_metadata);
}

void HfpDecodingTransport::SinkMetadataChanged(
    const sink_metadata_v7_t& sink_metadata) {
  transport_->SinkMetadataChanged(sink_metadata);
}

void HfpDecodingTransport::ResetPresentationPosition() {
  transport_->ResetPresentationPosition();
}

void HfpDecodingTransport::LogBytesRead(size_t bytes_written) {
  transport_->LogBytesProcessed(bytes_written);
}

uint8_t HfpDecodingTransport::GetPendingCmd() const {
  return transport_->GetPendingCmd();
}

void HfpDecodingTransport::ResetPendingCmd() { transport_->ResetPendingCmd(); }

HfpEncodingTransport::HfpEncodingTransport(SessionType session_type)
    : IBluetoothSourceTransportInstance(session_type, (AudioConfiguration){}) {
  transport_ = new HfpTransport();
};

HfpEncodingTransport::~HfpEncodingTransport() { delete transport_; }

BluetoothAudioCtrlAck HfpEncodingTransport::StartRequest(bool is_low_latency) {
  return transport_->StartRequest();
}

BluetoothAudioCtrlAck HfpEncodingTransport::SuspendRequest() {
  return transport_->SuspendRequest();
}

void HfpEncodingTransport::SetLatencyMode(LatencyMode latency_mode) {
  transport_->SetLatencyMode(latency_mode);
}

bool HfpEncodingTransport::GetPresentationPosition(
    uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written,
    timespec* data_position) {
  return transport_->GetPresentationPosition(
      remote_delay_report_ns, total_bytes_written, data_position);
}

void HfpEncodingTransport::SourceMetadataChanged(
    const source_metadata_v7_t& source_metadata) {
  transport_->SourceMetadataChanged(source_metadata);
}

void HfpEncodingTransport::SinkMetadataChanged(
    const sink_metadata_v7_t& sink_metadata) {
  transport_->SinkMetadataChanged(sink_metadata);
}

void HfpEncodingTransport::ResetPresentationPosition() {
  transport_->ResetPresentationPosition();
}

void HfpEncodingTransport::LogBytesWritten(size_t bytes_written) {
  transport_->LogBytesProcessed(bytes_written);
}

uint8_t HfpEncodingTransport::GetPendingCmd() const {
  return transport_->GetPendingCmd();
}

void HfpEncodingTransport::ResetPendingCmd() { transport_->ResetPendingCmd(); }

}  // namespace hfp
}  // namespace aidl
}  // namespace audio
}  // namespace bluetooth