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

Commit b528bcae authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "AAC support for A2DP sink"

parents 75358bb3 4f27b125
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -1051,6 +1051,19 @@ const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
  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(
    const btav_a2dp_codec_config_t& codec_user_config) {
  uint8_t result_codec_config[AVDT_CODEC_SIZE];
+6 −0
Original line number 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.
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.
// |codec_user_config| contains the preferred codec configuration.
// Returns true on success, otherwise false.
+38 −113
Original line number Diff line number Diff line
@@ -35,9 +35,6 @@
#include "osi/include/osi.h"
#include "osi/include/thread.h"

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

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

/**
@@ -75,13 +72,6 @@ typedef struct {
  btif_a2dp_sink_focus_state_t focus_state;
} 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 */
typedef struct {
  thread_t* worker_thread;
@@ -89,11 +79,11 @@ typedef struct {
  fixed_queue_t* rx_audio_queue;
  bool rx_flush; /* discards any incoming data when true */
  alarm_t* decode_alarm;
  uint8_t frames_to_process;
  tA2DP_SAMPLE_RATE sample_rate;
  tA2DP_CHANNEL_COUNT channel_count;
  btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
  void* audio_track;
  const tA2DP_DECODER_INTERFACE* decoder_interface;
} tBTIF_A2DP_SINK_CB;

// 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 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_shutdown_delayed(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_audio_rx_flush_req(void);
/* 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(
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
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);
}

// Must be called while locked.
static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
  uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
  int count;
  uint32_t pcmBytes, availPcmBytes;
  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);
static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) {
#ifndef OS_GENERIC
  BtifAvrcpAudioTrackWriteData(btif_a2dp_sink_cb.audio_track,
                               reinterpret_cast<void*>(data), len);
#endif
}

// 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) ||
      (btif_a2dp_sink_cb.rx_flush)) {
    APPL_TRACE_DEBUG("State Changed happened in this tick");
    return;
  }

  APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
                   num_sbc_frames, sbc_frame_len);

  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;
  CHECK(btif_a2dp_sink_cb.decoder_interface);
  if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
    APPL_TRACE_ERROR("%s Decoding failed!", __func__);
  }
    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) {
  LockGuard lock(g_mutex);

  tBT_SBC_HDR* p_msg;
  int num_sbc_frames;
  int num_frames_to_process;

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

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

  do {
    p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
        btif_a2dp_sink_cb.rx_audio_queue);
    if (p_msg == NULL) return;
    /* 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);
  while (true) {
    p_msg = (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
    if (p_msg == NULL) {
      break;
    }
    APPL_TRACE_DEBUG("Number of packets in queue %d",
                     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 */
    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);
  } while (num_frames_to_process > 0);
  }

  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) {
  LockGuard lock(g_mutex);
  /* Flush all received SBC buffers (encoded) */
  /* Flush all received encoded audio buffers */
  APPL_TRACE_DEBUG("%s", __func__);

  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(
    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
  LockGuard lock(g_mutex);
  OI_STATUS status;

  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[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;
  APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
  status = OI_CODEC_SBC_DecoderReset(
      &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
      sizeof(btif_a2dp_sink_context_data), 2, 2, false);
  if (!OI_SUCCESS(status)) {
    APPL_TRACE_ERROR("%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
                     __func__, status);

  btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
  if (btif_a2dp_sink_cb.decoder_interface == NULL) {
    APPL_TRACE_ERROR("%s: Cannot stream audio: no source decoder interface",
                     __func__);
    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 =
#ifndef OS_GENERIC
      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__);
    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) {
@@ -563,17 +494,11 @@ uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {

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

  // 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_AAC,

  BTAV_A2DP_CODEC_INDEX_SINK_MAX,

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