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

Commit 63183603 authored by Sunny Kapdi's avatar Sunny Kapdi Committed by Petri Gynther
Browse files

A2DP Offload support

The encoding of the A2DP data packets if offloaded
to platform specific HAL. The communication with the
HAL is enabled by IBluetoothAudioOffload and
IBluetoothAudioHost interfaces. Bluetooth stack is
still responsible for A2DP control path.

Bug: 63932139
Bug: 72242910
Test: Manual; TestTracker/148125
Change-Id: Ie6e9c233ca431d0ab8cf15d10c30836e41bbdcb7
(cherry picked from commit c013d10798f674fd4a73f03b9178952928294b1e)
parent ff4d366a
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -92,7 +92,9 @@ typedef enum {
  A2DP_CTRL_ACK_SUCCESS,
  A2DP_CTRL_ACK_FAILURE,
  A2DP_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
  A2DP_CTRL_ACK_UNSUPPORTED
  A2DP_CTRL_ACK_UNSUPPORTED,
  A2DP_CTRL_ACK_PENDING,
  A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS,
} tA2DP_CTRL_ACK;

typedef uint32_t tA2DP_SAMPLE_RATE;
+207 −65
Original line number Diff line number Diff line
@@ -32,11 +32,14 @@
#include <string.h>
#include <vector>

#include "a2dp_sbc.h"
#include "avdt_api.h"
#include "bt_utils.h"
#include "bta_av_int.h"
#include "btif/include/btif_av_co.h"
#include "btif/include/btif_storage.h"
#include "btm_int.h"
#include "device/include/controller.h"
#include "device/include/interop.h"
#include "l2c_api.h"
#include "l2cdefs.h"
@@ -44,10 +47,11 @@
#include "osi/include/osi.h"
#include "osi/include/properties.h"
#include "utl.h"

#if (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
#include "btif/include/btif_av.h"
#include "btif/include/btif_hf.h"

/*****************************************************************************
 *  Constants
@@ -73,6 +77,11 @@
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4

#define MAX_2MBPS_AVDTP_MTU 663
#define BTIF_A2DP_MAX_BITPOOL_MQ 35

static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb,
                                         tBT_A2DP_OFFLOAD* p_a2dp_offload);
static void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb,
                               UNUSED_ATTR tBTA_AV_DATA* p_data);

@@ -97,7 +106,8 @@ const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos = {bta_av_co_audio_init,
                                           bta_av_co_audio_stop,
                                           bta_av_co_audio_source_data_path,
                                           bta_av_co_audio_delay,
                                           bta_av_co_audio_update_mtu};
                                           bta_av_co_audio_update_mtu,
                                           bta_av_co_content_protect_is_active};

/* ssm action functions for audio stream */
const tBTA_AV_SACT bta_av_a2dp_action[] = {
@@ -1844,9 +1854,10 @@ void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
  BT_HDR* p_buf;
  uint8_t policy = HCI_ENABLE_SNIFF_MODE;

  APPL_TRACE_ERROR("%s: peer %s handle:%d audio_open_cnt:%d, p_data %p",
                   __func__, p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
                   bta_av_cb.audio_open_cnt, p_data);
  APPL_TRACE_ERROR(
      "%s: peer %s handle:%d audio_open_cnt:%d, p_data %p start:%d", __func__,
      p_scb->peer_addr.ToString().c_str(), p_scb->hndl,
      bta_av_cb.audio_open_cnt, p_data, start);

  bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
  if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
@@ -1855,17 +1866,10 @@ void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
  bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);

  if (p_scb->co_started) {
    /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
    vendor_get_interface()->send_command(
        (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
    if (p_scb->offload_start_pending) {
      tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
      tBTA_AV bta_av_data;
      bta_av_data.status = status;
      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
    if (p_scb->offload_started) {
      bta_av_vendor_offload_stop();
      p_scb->offload_started = false;
    }
    p_scb->offload_start_pending = false;
    */

    bta_av_stream_chg(p_scb, false);
    p_scb->co_started = false;
@@ -2489,18 +2493,10 @@ void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {

  /* in case that we received suspend_ind, we may need to call co_stop here */
  if (p_scb->co_started) {
    /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
    vendor_get_interface()->send_command(
        (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
    if (p_scb->offload_start_pending) {
      tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
      tBTA_AV bta_av_data;
      bta_av_data.status = status;
      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
    if (p_scb->offload_started) {
      bta_av_vendor_offload_stop();
      p_scb->offload_started = false;
    }
    p_scb->offload_start_pending = false;
    */

    bta_av_stream_chg(p_scb, false);

    {
@@ -2958,6 +2954,67 @@ void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
  }
}

void offload_vendor_callback(tBTM_VSC_CMPL* param) {
  uint8_t status = 0;
  uint8_t sub_opcode = 0;
  if (param->param_len) {
    APPL_TRACE_DEBUG("%s: param_len = %d status = %d", __func__,
                     param->param_len, param->p_param_buf[0]);
    status = param->p_param_buf[0];
  }
  if (status == 0) {
    sub_opcode = param->p_param_buf[1];
    APPL_TRACE_DEBUG("%s: subopcode = %d", __func__, sub_opcode);
    switch (sub_opcode) {
      case VS_HCI_A2DP_OFFLOAD_STOP:
        APPL_TRACE_DEBUG("%s: VS_HCI_STOP_A2DP_MEDIA successful", __func__);
        break;
      case VS_HCI_A2DP_OFFLOAD_START:
        (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
        break;
      default:
        break;
    }
  } else {
    APPL_TRACE_DEBUG("%s: Offload failed for subopcode= %d", __func__,
                     sub_opcode);
    if (param->opcode != VS_HCI_A2DP_OFFLOAD_STOP)
      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
  }
}

void bta_av_vendor_offload_start(tBTA_AV_SCB* p_scb,
                                 tBT_A2DP_OFFLOAD* offload_start) {
  uint8_t param[sizeof(tBT_A2DP_OFFLOAD)];
  APPL_TRACE_DEBUG("%s", __func__);

  uint8_t* p_param = param;
  *p_param++ = VS_HCI_A2DP_OFFLOAD_START;

  UINT32_TO_STREAM(p_param, offload_start->codec_type);
  UINT16_TO_STREAM(p_param, offload_start->max_latency);
  UINT16_TO_STREAM(p_param, offload_start->scms_t_enable);
  UINT32_TO_STREAM(p_param, offload_start->sample_rate);
  UINT8_TO_STREAM(p_param, offload_start->bits_per_sample);
  UINT8_TO_STREAM(p_param, offload_start->ch_mode);
  UINT32_TO_STREAM(p_param, offload_start->encoded_audio_bitrate);
  UINT16_TO_STREAM(p_param, offload_start->acl_hdl);
  UINT16_TO_STREAM(p_param, offload_start->l2c_rcid);
  UINT16_TO_STREAM(p_param, offload_start->mtu);
  ARRAY_TO_STREAM(p_param, offload_start->codec_info,
                  (int8_t)sizeof(offload_start->codec_info));
  p_scb->offload_started = true;
  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, p_param - param,
                            param, offload_vendor_callback);
}

void bta_av_vendor_offload_stop() {
  uint8_t param[sizeof(tBT_A2DP_OFFLOAD)];
  APPL_TRACE_DEBUG("%s", __func__);
  param[0] = VS_HCI_A2DP_OFFLOAD_STOP;
  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, 1, param,
                            offload_vendor_callback);
}
/*******************************************************************************
 *
 * Function         bta_av_offload_req
@@ -2971,16 +3028,24 @@ void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
  tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES;

  tBT_A2DP_OFFLOAD offload_start;
  APPL_TRACE_DEBUG("%s: stream %s, audio channels open %d", __func__,
                   p_scb->started ? "STARTED" : "STOPPED",
                   bta_av_cb.audio_open_cnt);

  /* Check if stream has already been started. */
  /* Support offload if only one audio source stream is open. */
  if (p_scb->started != true) {
    status = BTA_AV_FAIL_STREAM;
  } else {
    bta_av_offload_codec_builder(p_scb, &offload_start);
    bta_av_vendor_offload_start(p_scb, &offload_start);
    return;
  }
  if (status != BTA_AV_SUCCESS) {
    tBTA_AV bta_av_data;
    bta_av_data.status = status;
    (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
  }

  /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
  uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
  else if (bta_av_cb.audio_open_cnt == 1 &&
@@ -3018,11 +3083,6 @@ void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
    }
  }
 */
  if (status != BTA_AV_SUCCESS) {
    tBTA_AV bta_av_data;
    bta_av_data.status = status;
    (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
  }
}

/*******************************************************************************
@@ -3052,3 +3112,85 @@ void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
  bta_av_data.status = status;
  (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
}

static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb,
                                         tBT_A2DP_OFFLOAD* p_a2dp_offload) {
  A2dpCodecConfig* CodecConfig = bta_av_get_a2dp_current_codec();
  btav_a2dp_codec_index_t codec_index =
      A2DP_SourceCodecIndex(p_scb->cfg.codec_info);
  uint32_t codec_type = 0;
  uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
  if (mtu == 0 || mtu > p_scb->stream_mtu) mtu = p_scb->stream_mtu;
  APPL_TRACE_DEBUG("%s:codec_index = %d", __func__, codec_index);
  switch (codec_index) {
    case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
      codec_type = BTA_AV_CODEC_TYPE_SBC;
      if (A2DP_GetMaxBitpoolSbc(p_scb->cfg.codec_info) <=
          BTIF_A2DP_MAX_BITPOOL_MQ) {
        APPL_TRACE_WARNING("%s: Restricting streaming MTU size for MQ Bitpool",
                           __func__);
        mtu = MAX_2MBPS_AVDTP_MTU;
      }
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
      codec_type = BTA_AV_CODEC_TYPE_AAC;
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
      codec_type = BTA_AV_CODEC_TYPE_APTX;
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
      codec_type = BTA_AV_CODEC_TYPE_APTXHD;
      break;
    case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
      codec_type = BTA_AV_CODEC_TYPE_LDAC;
      break;
    default:
      APPL_TRACE_ERROR("%s: Unknown Codec type ", __func__);
      return;
  }
  if (mtu > BTA_AV_MAX_A2DP_MTU) mtu = BTA_AV_MAX_A2DP_MTU;
  p_a2dp_offload->codec_type = codec_type;
  p_a2dp_offload->max_latency = 0;
  p_a2dp_offload->mtu = mtu;
  p_a2dp_offload->acl_hdl =
      BTM_GetHCIConnHandle(p_scb->peer_addr, BT_TRANSPORT_BR_EDR);
  p_a2dp_offload->scms_t_enable = p_scb->p_cos->cp_is_active(p_scb->peer_addr);
  APPL_TRACE_DEBUG("%s: scms_t_enable =%d", __func__,
                   p_a2dp_offload->scms_t_enable);

  switch (A2DP_GetTrackSampleRate(p_scb->cfg.codec_info)) {
    case 44100:
      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
      break;
    case 48000:
      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
      break;
    case 88200:
      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
      break;
    case 96000:
      p_a2dp_offload->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
      break;
  }
  if (L2CA_GetIdentifiers(p_scb->l2c_cid, &p_a2dp_offload->l2c_rcid, NULL) ==
      false) {
    APPL_TRACE_ERROR("%s: Failed to fetch l2c rcid", __func__);
    return;
  }
  switch (CodecConfig->getAudioBitsPerSample()) {
    case 16:
      p_a2dp_offload->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
      break;
    case 24:
      p_a2dp_offload->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
      break;
    case 32:
      p_a2dp_offload->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
      break;
  }
  p_a2dp_offload->ch_mode = A2DP_GetTrackChannelCount(p_scb->cfg.codec_info);
  p_a2dp_offload->encoded_audio_bitrate = CodecConfig->getTrackBitRate();
  if (!CodecConfig->getCodecSpecificConfig(p_a2dp_offload)) {
    APPL_TRACE_ERROR("%s: not a valid codec info", __func__);
  }
}
+27 −0
Original line number Diff line number Diff line
@@ -191,6 +191,9 @@ typedef void (*tBTA_AV_CO_UPDATE_MTU)(tBTA_AV_HNDL bta_av_handle,
                                      const RawAddress& peer_addr,
                                      uint16_t mtu);

typedef bool (*tBTA_AV_CO_CONTENT_PROTECT_IS_ACTIVE)(
    const RawAddress& peer_addr);

/* the call-out functions for one stream */
typedef struct {
  tBTA_AV_CO_INIT init;
@@ -204,6 +207,7 @@ typedef struct {
  tBTA_AV_CO_DATAPATH data;
  tBTA_AV_CO_DELAY delay;
  tBTA_AV_CO_UPDATE_MTU update_mtu;
  tBTA_AV_CO_CONTENT_PROTECT_IS_ACTIVE cp_is_active;
} tBTA_AV_CO_FUNCTS;

/* data type for BTA_AV_API_ENABLE_EVT */
@@ -511,6 +515,7 @@ struct tBTA_AV_SCB {
  uint16_t uuid_int; /*intended UUID of Initiator to connect to */
  bool offload_start_pending;
  bool skip_sdp; /* Decides if sdp to be done prior to profile connection */
  bool offload_started;
};

#define BTA_AV_RC_ROLE_MASK 0x10
@@ -572,6 +577,27 @@ typedef struct {
  uint8_t audio_streams; /* handle mask of streaming audio channels */
} tBTA_AV_CB;

// A2DP offload VSC parameters
class tBT_A2DP_OFFLOAD {
 public:
  uint32_t codec_type;            /* codec types ex: SBC/AAC/LDAC/APTx */
  uint16_t max_latency;           /* maximum latency */
  uint16_t scms_t_enable;         /* content protection enable */
  uint32_t sample_rate;           /* Sample rates ex: 44.1/48/88.2/96 Khz */
  uint8_t bits_per_sample;        /* bits per sample ex: 16/24/32 */
  uint8_t ch_mode;                /* None:0 Left:1 Right:2 */
  uint32_t encoded_audio_bitrate; /* encoder audio bitrates */
  uint16_t acl_hdl;               /* connection handle */
  uint16_t l2c_rcid;              /* l2cap channel id */
  uint16_t mtu;                   /* MTU size */
  uint8_t codec_info[32];         /* Codec specific information */
};

/* Vendor OFFLOAD VSC */
#define HCI_VSQC_CONTROLLER_A2DP_OPCODE 0x000A

#define VS_HCI_A2DP_OFFLOAD_START 0x01
#define VS_HCI_A2DP_OFFLOAD_STOP 0x02
/*****************************************************************************
 *  Global data
 ****************************************************************************/
@@ -711,5 +737,6 @@ extern void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
extern void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
extern void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
extern void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
extern void bta_av_vendor_offload_stop(void);

#endif /* BTA_AV_INT_H */
+9 −0
Original line number Diff line number Diff line
@@ -154,6 +154,15 @@ typedef uint8_t tBTA_AV_ERR;

typedef uint8_t tBTA_AV_EVT;

typedef enum {
  BTA_AV_CODEC_TYPE_UNKNOWN = 0x00,
  BTA_AV_CODEC_TYPE_SBC = 0x01,
  BTA_AV_CODEC_TYPE_AAC = 0x02,
  BTA_AV_CODEC_TYPE_APTX = 0x04,
  BTA_AV_CODEC_TYPE_APTXHD = 0x08,
  BTA_AV_CODEC_TYPE_LDAC = 0x10
} tBTA_AV_CODEC_TYPE;

/* Event associated with BTA_AV_ENABLE_EVT */
typedef struct { tBTA_AV_FEAT features; } tBTA_AV_ENABLE;

+11 −0
Original line number Diff line number Diff line
@@ -224,4 +224,15 @@ void bta_av_co_audio_delay(tBTA_AV_HNDL bta_av_handle,
void bta_av_co_audio_update_mtu(tBTA_AV_HNDL bta_av_handle,
                                const RawAddress& peer_address, uint16_t mtu);

/*******************************************************************************
 **
 ** Function         bta_av_co_content_protect_is_active
 **
 ** Description     Get the current configuration of content protection
 **
 ** Returns          TRUE if the current streaming has CP, FALSE otherwise
 **
 ******************************************************************************/
bool bta_av_co_content_protect_is_active(const RawAddress& peer_address);

#endif /* BTA_AV_CO_H */
Loading