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

Commit 4f27b125 authored by Bailey Forrest's avatar Bailey Forrest Committed by Pavlin Radoslavov
Browse files

AAC support for A2DP sink

Bug: 37562860
Test: Test on device.
Change-Id: Ic8699e5ffa5f97e102ec4b9fc63ce5afd3382c5d
parent 5a87b740
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -1051,6 +1051,19 @@ const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
  return encoder_interface;
  return encoder_interface;
}
}


const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) {
  /* Protect access to bta_av_co_cb.codec_config */
  mutex_global_lock();

  const tA2DP_DECODER_INTERFACE* decoder_interface =
      A2DP_GetDecoderInterface(bta_av_co_cb.codec_config);

  /* Protect access to bta_av_co_cb.codec_config */
  mutex_global_unlock();

  return decoder_interface;
}

bool bta_av_co_set_codec_user_config(
bool bta_av_co_set_codec_user_config(
    const btav_a2dp_codec_config_t& codec_user_config) {
    const btav_a2dp_codec_config_t& codec_user_config) {
  uint8_t result_codec_config[AVDT_CODEC_SIZE];
  uint8_t result_codec_config[AVDT_CODEC_SIZE];
+6 −0
Original line number Original line Diff line number Diff line
@@ -37,6 +37,12 @@ void bta_av_co_get_peer_params(tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params);
// otherwise NULL.
// otherwise NULL.
const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);
const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);


// Gets the current A2DP decoder interface that can be used to decode received
// A2DP packets - see |tA2DP_DECODER_INTERFACE|.
// Returns the A2DP decoder interface if the current codec is setup, otherwise
// NULL.
const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void);

// Sets the user preferred codec configuration.
// Sets the user preferred codec configuration.
// |codec_user_config| contains the preferred codec configuration.
// |codec_user_config| contains the preferred codec configuration.
// Returns true on success, otherwise false.
// Returns true on success, otherwise false.
+38 −113
Original line number Original line Diff line number Diff line
@@ -35,9 +35,6 @@
#include "osi/include/osi.h"
#include "osi/include/osi.h"
#include "osi/include/thread.h"
#include "osi/include/thread.h"


#include "oi_codec_sbc.h"
#include "oi_status.h"

using LockGuard = std::lock_guard<std::mutex>;
using LockGuard = std::lock_guard<std::mutex>;


/**
/**
@@ -75,13 +72,6 @@ typedef struct {
  btif_a2dp_sink_focus_state_t focus_state;
  btif_a2dp_sink_focus_state_t focus_state;
} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
} tBTIF_MEDIA_SINK_FOCUS_UPDATE;


typedef struct {
  uint16_t num_frames_to_be_processed;
  uint16_t len;
  uint16_t offset;
  uint16_t layer_specific;
} tBT_SBC_HDR;

/* BTIF A2DP Sink control block */
/* BTIF A2DP Sink control block */
typedef struct {
typedef struct {
  thread_t* worker_thread;
  thread_t* worker_thread;
@@ -89,11 +79,11 @@ typedef struct {
  fixed_queue_t* rx_audio_queue;
  fixed_queue_t* rx_audio_queue;
  bool rx_flush; /* discards any incoming data when true */
  bool rx_flush; /* discards any incoming data when true */
  alarm_t* decode_alarm;
  alarm_t* decode_alarm;
  uint8_t frames_to_process;
  tA2DP_SAMPLE_RATE sample_rate;
  tA2DP_SAMPLE_RATE sample_rate;
  tA2DP_CHANNEL_COUNT channel_count;
  tA2DP_CHANNEL_COUNT channel_count;
  btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
  btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
  void* audio_track;
  void* audio_track;
  const tA2DP_DECODER_INTERFACE* decoder_interface;
} tBTIF_A2DP_SINK_CB;
} tBTIF_A2DP_SINK_CB;


// Mutex for below data structures.
// Mutex for below data structures.
@@ -103,12 +93,6 @@ static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;


static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};
static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};


static OI_CODEC_SBC_DECODER_CONTEXT btif_a2dp_sink_context;
static uint32_t btif_a2dp_sink_context_data[CODEC_DATA_WORDS(
    2, SBC_CODEC_FAST_FILTER_BUFFERS)];
static int16_t
    btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];

static void btif_a2dp_sink_startup_delayed(void* context);
static void btif_a2dp_sink_startup_delayed(void* context);
static void btif_a2dp_sink_shutdown_delayed(void* context);
static void btif_a2dp_sink_shutdown_delayed(void* context);
static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
@@ -118,7 +102,7 @@ static void btif_a2dp_sink_audio_handle_start_decoding(void);
static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
static void btif_a2dp_sink_audio_rx_flush_req(void);
static void btif_a2dp_sink_audio_rx_flush_req(void);
/* Handle incoming media packets A2DP SINK streaming */
/* Handle incoming media packets A2DP SINK streaming */
static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg);
static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg);
static void btif_a2dp_sink_decoder_update_event(
static void btif_a2dp_sink_decoder_update_event(
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
static void btif_a2dp_sink_clear_track_event(void);
static void btif_a2dp_sink_clear_track_event(void);
@@ -365,57 +349,31 @@ static void btif_a2dp_sink_audio_handle_start_decoding(void) {
            btif_decode_alarm_cb, NULL);
            btif_decode_alarm_cb, NULL);
}
}


// Must be called while locked.
static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) {
static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
#ifndef OS_GENERIC
  uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
  BtifAvrcpAudioTrackWriteData(btif_a2dp_sink_cb.audio_track,
  int count;
                               reinterpret_cast<void*>(data), len);
  uint32_t pcmBytes, availPcmBytes;
#endif
  int16_t* pcmDataPointer =
}
      btif_a2dp_sink_pcm_data; /* Will be overwritten on next packet receipt */
  OI_STATUS status;
  int num_sbc_frames = p_msg->num_frames_to_be_processed;
  uint32_t sbc_frame_len = p_msg->len - 1;
  availPcmBytes = sizeof(btif_a2dp_sink_pcm_data);


// Must be called while locked.
static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg) {
  if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
  if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
      (btif_a2dp_sink_cb.rx_flush)) {
      (btif_a2dp_sink_cb.rx_flush)) {
    APPL_TRACE_DEBUG("State Changed happened in this tick");
    APPL_TRACE_DEBUG("State Changed happened in this tick");
    return;
    return;
  }
  }


  APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
  CHECK(btif_a2dp_sink_cb.decoder_interface);
                   num_sbc_frames, sbc_frame_len);
  if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {

    APPL_TRACE_ERROR("%s Decoding failed!", __func__);
  for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count++) {
    pcmBytes = availPcmBytes;
    status = OI_CODEC_SBC_DecodeFrame(
        &btif_a2dp_sink_context, (const OI_BYTE**)&sbc_start_frame,
        (uint32_t*)&sbc_frame_len, (int16_t*)pcmDataPointer,
        (uint32_t*)&pcmBytes);
    if (!OI_SUCCESS(status)) {
      APPL_TRACE_ERROR("%s: Decoding failure: %d", __func__, status);
      break;
  }
  }
    availPcmBytes -= pcmBytes;
    pcmDataPointer += pcmBytes / 2;
    p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
    p_msg->len = sbc_frame_len + 1;
  }

#ifndef OS_GENERIC
  BtifAvrcpAudioTrackWriteData(
      btif_a2dp_sink_cb.audio_track, (void*)btif_a2dp_sink_pcm_data,
      (sizeof(btif_a2dp_sink_pcm_data) - availPcmBytes));
#endif
}
}


static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
  LockGuard lock(g_mutex);
  LockGuard lock(g_mutex);


  tBT_SBC_HDR* p_msg;
  BT_HDR* p_msg;
  int num_sbc_frames;
  int num_frames_to_process;

  if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
  if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
    APPL_TRACE_DEBUG("%s: empty queue", __func__);
    APPL_TRACE_DEBUG("%s: empty queue", __func__);
    return;
    return;
@@ -433,42 +391,20 @@ static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
    return;
    return;
  }
  }


  num_frames_to_process = btif_a2dp_sink_cb.frames_to_process;
  APPL_TRACE_DEBUG(" Process Frames + ");
  APPL_TRACE_DEBUG(" Process Frames + ");


  do {
  while (true) {
    p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
    p_msg = (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
        btif_a2dp_sink_cb.rx_audio_queue);
    if (p_msg == NULL) {
    if (p_msg == NULL) return;
      break;
    /* Number of frames in queue packets */
    }
    num_sbc_frames = p_msg->num_frames_to_be_processed;
    APPL_TRACE_DEBUG("Frames left in topmost packet %d", num_sbc_frames);
    APPL_TRACE_DEBUG("Remaining frames to process in tick %d",
                     num_frames_to_process);
    APPL_TRACE_DEBUG("Number of packets in queue %d",
    APPL_TRACE_DEBUG("Number of packets in queue %d",
                     fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));
                     fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));


    if (num_sbc_frames > num_frames_to_process) {
      /* Queue packet has more frames */
      p_msg->num_frames_to_be_processed = num_frames_to_process;
      btif_a2dp_sink_handle_inc_media(p_msg);
      p_msg->num_frames_to_be_processed =
          num_sbc_frames - num_frames_to_process;
      num_frames_to_process = 0;
      break;
    }
    /* Queue packet has less frames */
    /* Queue packet has less frames */
    btif_a2dp_sink_handle_inc_media(p_msg);
    btif_a2dp_sink_handle_inc_media(p_msg);
    p_msg =
        (tBT_SBC_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
    if (p_msg == NULL) {
      APPL_TRACE_ERROR("Insufficient data in queue");
      break;
    }
    num_frames_to_process =
        num_frames_to_process - p_msg->num_frames_to_be_processed;
    osi_free(p_msg);
    osi_free(p_msg);
  } while (num_frames_to_process > 0);
  }


  APPL_TRACE_DEBUG("Process Frames - ");
  APPL_TRACE_DEBUG("Process Frames - ");
}
}
@@ -483,7 +419,7 @@ void btif_a2dp_sink_set_rx_flush(bool enable) {


static void btif_a2dp_sink_audio_rx_flush_event(void) {
static void btif_a2dp_sink_audio_rx_flush_event(void) {
  LockGuard lock(g_mutex);
  LockGuard lock(g_mutex);
  /* Flush all received SBC buffers (encoded) */
  /* Flush all received encoded audio buffers */
  APPL_TRACE_DEBUG("%s", __func__);
  APPL_TRACE_DEBUG("%s", __func__);


  fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
  fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
@@ -492,8 +428,6 @@ static void btif_a2dp_sink_audio_rx_flush_event(void) {
static void btif_a2dp_sink_decoder_update_event(
static void btif_a2dp_sink_decoder_update_event(
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
  LockGuard lock(g_mutex);
  LockGuard lock(g_mutex);
  OI_STATUS status;

  APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
  APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
                   p_buf->codec_info[1], p_buf->codec_info[2],
                   p_buf->codec_info[1], p_buf->codec_info[2],
                   p_buf->codec_info[3], p_buf->codec_info[4],
                   p_buf->codec_info[3], p_buf->codec_info[4],
@@ -519,15 +453,21 @@ static void btif_a2dp_sink_decoder_update_event(


  btif_a2dp_sink_cb.rx_flush = false;
  btif_a2dp_sink_cb.rx_flush = false;
  APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
  APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
  status = OI_CODEC_SBC_DecoderReset(

      &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
  btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
      sizeof(btif_a2dp_sink_context_data), 2, 2, false);
  if (btif_a2dp_sink_cb.decoder_interface == NULL) {
  if (!OI_SUCCESS(status)) {
    APPL_TRACE_ERROR("%s: Cannot stream audio: no source decoder interface",
    APPL_TRACE_ERROR("%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
                     __func__);
                     __func__, status);
    return;
  }
  }


  APPL_TRACE_DEBUG("%s: A2dpSink: SBC create track", __func__);
  if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
          btif_a2dp_sink_on_decode_complete)) {
    APPL_TRACE_ERROR("%s: A2dpSink: Failed to initialize decoder", __func__);
    return;
  }

  APPL_TRACE_DEBUG("%s: A2dpSink: create audio track", __func__);
  btif_a2dp_sink_cb.audio_track =
  btif_a2dp_sink_cb.audio_track =
#ifndef OS_GENERIC
#ifndef OS_GENERIC
      BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
      BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
@@ -538,15 +478,6 @@ static void btif_a2dp_sink_decoder_update_event(
    APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
    APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
    return;
    return;
  }
  }

  btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
      BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
  APPL_TRACE_DEBUG("%s: Frames to be processed in 20 ms %d", __func__,
                   btif_a2dp_sink_cb.frames_to_process);
  if (btif_a2dp_sink_cb.frames_to_process == 0) {
    APPL_TRACE_ERROR("%s: Cannot compute the number of frames to process",
                     __func__);
  }
}
}


uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
@@ -563,17 +494,11 @@ uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {


  BTIF_TRACE_VERBOSE("%s +", __func__);
  BTIF_TRACE_VERBOSE("%s +", __func__);
  /* Allocate and queue this buffer */
  /* Allocate and queue this buffer */
  tBT_SBC_HDR* p_msg = reinterpret_cast<tBT_SBC_HDR*>(
  BT_HDR* p_msg =
      osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len));
      reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(*p_msg) + p_pkt->len));
  memcpy((uint8_t*)(p_msg + 1), (uint8_t*)(p_pkt + 1) + p_pkt->offset,
  memcpy(p_msg, p_pkt, sizeof(*p_msg));
         p_pkt->len);
  p_msg->num_frames_to_be_processed =
      (*((uint8_t*)(p_pkt + 1) + p_pkt->offset)) & 0x0f;
  p_msg->len = p_pkt->len;
  p_msg->offset = 0;
  p_msg->offset = 0;
  p_msg->layer_specific = p_pkt->layer_specific;
  memcpy(p_msg->data, p_pkt->data + p_pkt->offset, p_pkt->len);
  BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__,
                     p_msg->num_frames_to_be_processed, p_msg->len);
  fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
  fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
  if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
  if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
      MAX_A2DP_DELAYED_START_FRAME_COUNT) {
      MAX_A2DP_DELAYED_START_FRAME_COUNT) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ typedef enum {


  // Add an entry for each sink codec here
  // Add an entry for each sink codec here
  BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
  BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
  BTAV_A2DP_CODEC_INDEX_SINK_AAC,


  BTAV_A2DP_CODEC_INDEX_SINK_MAX,
  BTAV_A2DP_CODEC_INDEX_SINK_MAX,


+4 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ cc_library_static {
    ],
    ],
    include_dirs: [
    include_dirs: [
        "external/aac/libAACenc/include",
        "external/aac/libAACenc/include",
        "external/aac/libAACdec/include",
        "external/aac/libSYS/include",
        "external/aac/libSYS/include",
        "external/libldac/inc",
        "external/libldac/inc",
        "external/libldac/abr/inc",
        "external/libldac/abr/inc",
@@ -41,10 +42,12 @@ cc_library_static {
    ],
    ],
    srcs: [
    srcs: [
        "a2dp/a2dp_aac.cc",
        "a2dp/a2dp_aac.cc",
        "a2dp/a2dp_aac_decoder.cc",
        "a2dp/a2dp_aac_encoder.cc",
        "a2dp/a2dp_aac_encoder.cc",
        "a2dp/a2dp_api.cc",
        "a2dp/a2dp_api.cc",
        "a2dp/a2dp_codec_config.cc",
        "a2dp/a2dp_codec_config.cc",
        "a2dp/a2dp_sbc.cc",
        "a2dp/a2dp_sbc.cc",
        "a2dp/a2dp_sbc_decoder.cc",
        "a2dp/a2dp_sbc_encoder.cc",
        "a2dp/a2dp_sbc_encoder.cc",
        "a2dp/a2dp_sbc_up_sample.cc",
        "a2dp/a2dp_sbc_up_sample.cc",
        "a2dp/a2dp_vendor.cc",
        "a2dp/a2dp_vendor.cc",
@@ -201,6 +204,7 @@ cc_test {
    ],
    ],
    static_libs: [
    static_libs: [
        "libbt-stack",
        "libbt-stack",
        "libbt-sbc-decoder",
        "libbt-sbc-encoder",
        "libbt-sbc-encoder",
        "libFraunhoferAAC",
        "libFraunhoferAAC",
        "libosi",
        "libosi",
Loading