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

Commit e3a7961f authored by Jeremy Wu's avatar Jeremy Wu
Browse files

HfpClientInterface: allow uni-directional audio stream on SCO

In some cases (e.g., on start-suspend transient states), there could be
only one direction of active audio stream, and either of the r/w is not
allowed.

In this CL, we capture the precise state of the active directions, and
make the streams appear to be active to the lower layers that assume
both are always active.

Test: verify BT audio works
Test: m Bluetooth
Bug: 349290628
Bug: 315234036
Flag: com::android::bluetooth::flags::is_sco_managed_by_audio and HFP
and bluetooth.hfp.software_datapath.enabled

Change-Id: Ide1006b016c94960d5e869b5b48c85d3e3a7754f
parent da9cdc0b
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "hfp_client_interface_aidl.h"

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>

#include <map>

@@ -70,11 +71,19 @@ std::unordered_map<tBTA_AG_UUID_CODEC, ::hfp::sco_config> HfpTransport::GetHfpSc
  return providerInfo->GetHfpScoConfig();
}

HfpTransport::HfpTransport() { hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; }
bool HfpTransport::IsStreamActive() { return is_stream_active; }

void HfpTransport::SetStreamActive(bool active) { is_stream_active = active; }

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

BluetoothAudioCtrlAck HfpTransport::StartRequest() {
  if (hfp_pending_cmd_ == HFP_CTRL_CMD_START) {
    log::info("HFP_CTRL_CMD_START in progress");
    is_stream_active = true;
    return BluetoothAudioCtrlAck::PENDING;
  } else if (hfp_pending_cmd_ != HFP_CTRL_CMD_NONE) {
    log::warn("busy in pending_cmd={}", hfp_pending_cmd_);
@@ -88,6 +97,7 @@ BluetoothAudioCtrlAck HfpTransport::StartRequest() {

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

@@ -105,11 +115,15 @@ BluetoothAudioCtrlAck HfpTransport::StartRequest() {
  if (ctrl_ack->second != BluetoothAudioCtrlAck::SUCCESS_FINISHED) {
    return ctrl_ack->second;
  }
  is_stream_active = true;
  return BluetoothAudioCtrlAck::PENDING;
}

void HfpTransport::StopRequest() {
  log::info("handling");

  is_stream_active = false;

  RawAddress addr = bta_ag_get_active_device();
  if (addr.IsEmpty()) {
    log::error("No active device found");
@@ -180,6 +194,13 @@ BluetoothAudioCtrlAck HfpDecodingTransport::StartRequest(bool is_low_latency) {
}

BluetoothAudioCtrlAck HfpDecodingTransport::SuspendRequest() {
  transport_->SetStreamActive(false);

  if (HfpEncodingTransport::instance_ && HfpEncodingTransport::instance_->IsStreamActive()) {
    log::info("SCO will suspend when encoding transport suspends.");
    return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
  }

  return transport_->SuspendRequest();
}

@@ -212,6 +233,8 @@ uint8_t HfpDecodingTransport::GetPendingCmd() const { return transport_->GetPend

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

bool HfpDecodingTransport::IsStreamActive() { return transport_->IsStreamActive(); }

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

HfpEncodingTransport::HfpEncodingTransport(SessionType session_type)
@@ -226,6 +249,13 @@ BluetoothAudioCtrlAck HfpEncodingTransport::StartRequest(bool is_low_latency) {
}

BluetoothAudioCtrlAck HfpEncodingTransport::SuspendRequest() {
  transport_->SetStreamActive(false);

  if (HfpDecodingTransport::instance_ && HfpDecodingTransport::instance_->IsStreamActive()) {
    log::info("SCO will suspend when decoding transport suspends.");
    return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
  }

  return transport_->SuspendRequest();
}

@@ -260,6 +290,8 @@ uint8_t HfpEncodingTransport::GetPendingCmd() const { return transport_->GetPend

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

bool HfpEncodingTransport::IsStreamActive() { return transport_->IsStreamActive(); }

}  // namespace hfp
}  // namespace aidl
}  // namespace audio
+10 −0
Original line number Diff line number Diff line
@@ -74,8 +74,14 @@ public:
  static std::unordered_map<tBTA_AG_UUID_CODEC, ::hfp::sco_config> GetHfpScoConfig(
          SessionType sessionType);

  bool IsStreamActive();

  void SetStreamActive(bool active);

private:
  tHFP_CTRL_CMD hfp_pending_cmd_;

  bool is_stream_active;
};

// Source transport implementation
@@ -108,6 +114,8 @@ public:

  void ResetPendingCmd();

  bool IsStreamActive();

  static inline HfpDecodingTransport* instance_ = nullptr;
  static inline BluetoothAudioSourceClientInterface* software_hal_interface = nullptr;
  static inline BluetoothAudioSourceClientInterface* offloading_hal_interface = nullptr;
@@ -146,6 +154,8 @@ public:

  void ResetPendingCmd();

  bool IsStreamActive();

  static inline HfpEncodingTransport* instance_ = nullptr;
  static inline BluetoothAudioSinkClientInterface* software_hal_interface = nullptr;
  static inline BluetoothAudioSinkClientInterface* offloading_hal_interface = nullptr;
+16 −2
Original line number Diff line number Diff line
@@ -188,9 +188,15 @@ size_t HfpClientInterface::Decode::Write(const uint8_t* p_buf, uint32_t len) {
    return 0;
  }
  log::verbose("decode");

  auto instance = aidl::hfp::HfpDecodingTransport::instance_;
  if (instance->IsStreamActive()) {
    return get_decode_client_interface()->WriteAudioData(p_buf, len);
  }

  return len;
}

void HfpClientInterface::Decode::ConfirmStreamingRequest() {
  auto instance = aidl::hfp::HfpDecodingTransport::instance_;
  auto pending_cmd = instance->GetPendingCmd();
@@ -349,9 +355,17 @@ size_t HfpClientInterface::Encode::Read(uint8_t* p_buf, uint32_t len) {
    return 0;
  }
  log::verbose("encode");

  auto instance = aidl::hfp::HfpEncodingTransport::instance_;
  if (instance->IsStreamActive()) {
    return get_encode_client_interface()->ReadAudioData(p_buf, len);
  }

  memset(p_buf, 0x00, len);

  return len;
}

void HfpClientInterface::Encode::ConfirmStreamingRequest() {
  auto instance = aidl::hfp::HfpEncodingTransport::instance_;
  auto pending_cmd = instance->GetPendingCmd();
+40 −0
Original line number Diff line number Diff line
@@ -131,6 +131,9 @@ std::ostream& operator<<(std::ostream& os, const BluetoothAudioCtrlAck& ack) { r

namespace hfp {

static bool encoding_transport_is_stream_active_ret;
static bool decoding_transport_is_stream_active_ret;

HfpTransport::HfpTransport() {}
BluetoothAudioCtrlAck HfpTransport::StartRequest() {
  return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
@@ -180,6 +183,7 @@ void HfpDecodingTransport::LogBytesWritten(size_t bytes_written) {}
uint8_t HfpDecodingTransport::GetPendingCmd() const { return HFP_CTRL_CMD_NONE; }
void HfpDecodingTransport::ResetPendingCmd() {}
void HfpDecodingTransport::StopRequest() {}
bool HfpDecodingTransport::IsStreamActive() { return decoding_transport_is_stream_active_ret; }

HfpEncodingTransport::HfpEncodingTransport(SessionType session_type)
    : IBluetoothSinkTransportInstance(session_type, (AudioConfiguration){}) {}
@@ -204,6 +208,7 @@ void HfpEncodingTransport::ResetPresentationPosition() {}
void HfpEncodingTransport::LogBytesRead(size_t bytes_written) {}
uint8_t HfpEncodingTransport::GetPendingCmd() const { return HFP_CTRL_CMD_NONE; }
void HfpEncodingTransport::ResetPendingCmd() {}
bool HfpEncodingTransport::IsStreamActive() { return encoding_transport_is_stream_active_ret; }

}  // namespace hfp
}  // namespace aidl
@@ -241,6 +246,8 @@ protected:
    init_message_loop_thread();
    sink_client_read_called = false;
    source_client_write_called = false;
    bluetooth::audio::aidl::hfp::encoding_transport_is_stream_active_ret = true;
    bluetooth::audio::aidl::hfp::decoding_transport_is_stream_active_ret = true;
  }

  virtual void TearDown() override { cleanup_message_loop_thread(); }
@@ -259,6 +266,24 @@ TEST_F(HfpClientInterfaceTest, InitEncodeInterfaceAndRead) {
  HfpClientInterface::Get()->ReleaseEncode(encode_);
}

TEST_F(HfpClientInterfaceTest, InitEncodeInterfaceAndReadWhenStreamInactive) {
  uint8_t data[48];
  data[0] = 0xab;

  HfpClientInterface::Encode* encode_ = nullptr;

  bluetooth::audio::aidl::hfp::encoding_transport_is_stream_active_ret = false;

  encode_ = HfpClientInterface::Get()->GetEncode(&message_loop_thread);
  ASSERT_NE(nullptr, encode_);

  encode_->Read(data, 48);
  ASSERT_EQ(0, sink_client_read_called);
  ASSERT_EQ(0x00, data[0]);

  HfpClientInterface::Get()->ReleaseEncode(encode_);
}

TEST_F(HfpClientInterfaceTest, InitDecodeInterfaceAndWrite) {
  uint8_t data[48];
  HfpClientInterface::Decode* decode_ = nullptr;
@@ -272,4 +297,19 @@ TEST_F(HfpClientInterfaceTest, InitDecodeInterfaceAndWrite) {
  HfpClientInterface::Get()->ReleaseDecode(decode_);
}

TEST_F(HfpClientInterfaceTest, InitDecodeInterfaceAndWriteWhenStreamInactive) {
  uint8_t data[48];

  HfpClientInterface::Decode* decode_ = nullptr;

  bluetooth::audio::aidl::hfp::decoding_transport_is_stream_active_ret = false;

  decode_ = HfpClientInterface::Get()->GetDecode(&message_loop_thread);
  ASSERT_NE(nullptr, decode_);

  decode_->Write(data, 48);
  ASSERT_EQ(0, source_client_write_called);

  HfpClientInterface::Get()->ReleaseDecode(decode_);
}
}  // namespace