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

Commit d26099b8 authored by Pavlin Radoslavov's avatar Pavlin Radoslavov
Browse files

Update the A2DP Codec Config API

Previously, the JNI upcall would contain only the current codec config.
In the new API, the upcall contains:
 1. The current codec config
 2. The list of codecs containing the local codecs capabilities
 3. The list of codecs containing the selectable codecs capabilities.
    This list is the intersection of the local codecs capabilities
    and the capabilities of the paired device.

Also, updated the codec backend to accomodate the above changes:
 * Update all selectable codecs inside bta_av_co_audio_set_codec()
 * Changed getCodecConfigAndCapabilities() to return current codec
   config, local codecs capabilities, and selectable codecs capabilities.
 * Updated each codec to compute and store a copy of the selectable
   capabilities, and the local capabilities.
 * Updated tA2DP_SBC_CIE to include new field bits_per_sample
   (for consistency with the rest of the codecs).
 * Replaced usage of codec_priority of 0 with BTAV_A2DP_CODEC_PRIORITY_DEFAULT
 * If there is user codec (re)config call, we always send an upcall
   to inform the Java layer about the most recent codec info.
   Thus, the caller would always know whether the request succeeded or failed.

Test: A2DP streaming with headsets and switching the codecs
Change-Id: Ie7a5cd5c2ab01bb8676032be05bc2ad03baa1e3f
parent e740bde6
Loading
Loading
Loading
Loading
+90 −18
Original line number Diff line number Diff line
@@ -132,6 +132,8 @@ static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer);
static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(
    A2dpCodecConfig& codec_config, tBTA_AV_CO_PEER* p_peer);
static bool bta_av_co_audio_update_selectable_codec(
    A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer);
static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
                                            const uint8_t* new_codec_config,
                                            uint8_t num_protect,
@@ -848,21 +850,39 @@ static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(

//
// Select the current codec configuration based on peer codec support.
// Return true on success, otherwise false.
// Furthermore, the local state for the remaining non-selected codecs is
// updated to reflect whether the codec is selectable.
// Return a pointer to the corresponding |tBTA_AV_CO_SINK| sink entry
// on success, otherwise NULL.
//
static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer) {
  tBTA_AV_CO_SINK* p_sink = NULL;

  // Update all selectable codecs.
  // This is needed to update the selectable parameters for each codec.
  // NOTE: The selectable codec info is used only for informational purpose.
  for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {
    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
                     iter->name().c_str());
    bta_av_co_audio_update_selectable_codec(*iter, p_peer);
  }

  // Select the codec
  for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {
    APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
    // Try to select an open device for the codec
    tBTA_AV_CO_SINK* p_sink = bta_av_co_audio_codec_selected(*iter, p_peer);
    p_sink = bta_av_co_audio_codec_selected(*iter, p_peer);
    if (p_sink != NULL) {
      APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
      return p_sink;
      break;
    }
    APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
  }

  return NULL;
  // NOTE: Unconditionally dispatch the event to make sure a callback with
  // the most recent codec info is generated.
  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);

  return p_sink;
}

// Select an open device for the preferred codec specified by |codec_config|.
@@ -896,8 +916,9 @@ static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(
                     codec_config.name().c_str());
    return NULL;
  }
  if (!bta_av_co_cb.codecs->setCodecConfig(p_sink->codec_caps, true,
                                           new_codec_config)) {
  if (!bta_av_co_cb.codecs->setCodecConfig(
          p_sink->codec_caps, true /* is_capability */, new_codec_config,
          true /* select_current_codec */)) {
    APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__,
                     codec_config.name().c_str());
    return NULL;
@@ -906,11 +927,52 @@ static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(

  bta_av_co_save_new_codec_config(p_peer, new_codec_config, p_sink->num_protect,
                                  p_sink->protect_info);
  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
  // NOTE: Event BTIF_AV_SOURCE_CONFIG_UPDATED_EVT is dispatched by the caller

  return p_sink;
}

// Update a selectable codec |codec_config| with the corresponding codec
// information from a peer device |p_peer|.
// Returns true if the codec is updated, otherwise false.
static bool bta_av_co_audio_update_selectable_codec(
    A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer) {
  uint8_t new_codec_config[AVDT_CODEC_SIZE];

  APPL_TRACE_DEBUG("%s", __func__);

  // Find the peer sink for the codec
  const tBTA_AV_CO_SINK* p_sink = NULL;
  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
    btav_a2dp_codec_index_t peer_codec_index =
        A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
    if (peer_codec_index != codec_config.codecIndex()) {
      continue;
    }
    if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) {
      APPL_TRACE_DEBUG(
          "%s: peer sink for codec %s does not support "
          "Copy Protection",
          __func__, codec_config.name().c_str());
      continue;
    }
    p_sink = &p_peer->sinks[index];
    break;
  }
  if (p_sink == NULL) {
    // The peer sink device does not support this codec
    return false;
  }
  if (!bta_av_co_cb.codecs->setCodecConfig(
          p_sink->codec_caps, true /* is_capability */, new_codec_config,
          false /* select_current_codec */)) {
    APPL_TRACE_DEBUG("%s: cannot update source codec %s", __func__,
                     codec_config.name().c_str());
    return false;
  }
  return true;
}

static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
                                            const uint8_t* new_codec_config,
                                            uint8_t num_protect,
@@ -973,9 +1035,11 @@ const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
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];
  const tBTA_AV_CO_SINK* p_sink = nullptr;
  bool restart_input = false;
  bool restart_output = false;
  bool config_updated = false;
  bool success = true;

  // Find the peer that is currently open
  tBTA_AV_CO_PEER* p_peer = nullptr;
@@ -988,11 +1052,11 @@ bool bta_av_co_set_codec_user_config(
  }
  if (p_peer == nullptr) {
    APPL_TRACE_ERROR("%s: no open peer to configure", __func__);
    return false;
    success = false;
    goto done;
  }

  // Find the peer SEP codec to use
  const tBTA_AV_CO_SINK* p_sink = nullptr;
  if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) {
    for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
      btav_a2dp_codec_index_t peer_codec_index =
@@ -1008,7 +1072,8 @@ bool bta_av_co_set_codec_user_config(
  }
  if (p_sink == nullptr) {
    APPL_TRACE_ERROR("%s: cannot find peer SEP to configure", __func__);
    return false;
    success = false;
    goto done;
  }

  tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
@@ -1017,7 +1082,8 @@ bool bta_av_co_set_codec_user_config(
          codec_user_config, &peer_params, p_sink->codec_caps,
          result_codec_config, &restart_input, &restart_output,
          &config_updated)) {
    return false;
    success = false;
    goto done;
  }

  if (restart_output) {
@@ -1034,13 +1100,15 @@ bool bta_av_co_set_codec_user_config(
                   p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
  }

  if (restart_input || config_updated) {
done:
  // NOTE: We uncoditionally send the upcall even if there is no change
  // or the user config failed. Thus, the caller would always know whether the
  // request succeeded or failed.
  // NOTE: Currently, the input is restarted by sending an upcall
  // and informing the Media Framework about the change.
  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
  }

  return true;
  return success;
}

// Sets the Over-The-Air preferred codec configuration.
@@ -1211,4 +1279,8 @@ void bta_av_co_init(void) {
  bta_av_co_cb.codecs->init();
  A2DP_InitDefaultCodec(bta_av_co_cb.codec_config);
  mutex_global_unlock();

  // NOTE: Unconditionally dispatch the event to make sure a callback with
  // the most recent codec info is generated.
  btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
}
+6 −4
Original line number Diff line number Diff line
@@ -296,12 +296,14 @@ static void btif_update_source_codec(void* p_data) {

static void btif_report_source_codec_state(UNUSED_ATTR void* p_data) {
  btav_a2dp_codec_config_t codec_config;
  std::vector<btav_a2dp_codec_config_t> codec_capabilities;
  std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
  std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;

  A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs();
  if (a2dp_codecs == nullptr) return;
  if (!a2dp_codecs->getCodecConfigAndCapabilities(&codec_config,
                                                  &codec_capabilities)) {
  if (!a2dp_codecs->getCodecConfigAndCapabilities(
          &codec_config, &codecs_local_capabilities,
          &codecs_selectable_capabilities)) {
    BTIF_TRACE_WARNING(
        "BTIF_AV_SOURCE_CONFIG_UPDATED_EVT failed: "
        "cannot get codec config and capabilities");
@@ -309,7 +311,7 @@ static void btif_report_source_codec_state(UNUSED_ATTR void* p_data) {
  }
  if (bt_av_src_callbacks != NULL) {
    HAL_CBACK(bt_av_src_callbacks, audio_config_cb, codec_config,
              codec_capabilities);
              codecs_local_capabilities, codecs_selectable_capabilities);
  }
}

+57 −1
Original line number Diff line number Diff line
@@ -650,7 +650,28 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_AAC_CIE& config_cie,
}

A2dpCodecConfigAac::A2dpCodecConfigAac()
    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC") {}
    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC") {
  // Compute the local capability
  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
  }
  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
  }
  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
  }
  if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
  }
  codec_local_capability_.bits_per_sample = a2dp_aac_caps.bits_per_sample;
  if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
  }
  if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
  }
}

A2dpCodecConfigAac::~A2dpCodecConfigAac() {}

@@ -873,6 +894,8 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info,
  // Save the internal state
  btav_a2dp_codec_config_t saved_codec_config = codec_config_;
  btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
  btav_a2dp_codec_config_t saved_codec_selectable_capability =
      codec_selectable_capability_;
  btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
  btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
  uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
@@ -953,6 +976,24 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info,

  // Select the sample frequency if there is no user preference
  do {
    // Compute the selectable capability
    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
      codec_selectable_capability_.sample_rate |=
          BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
    }
    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
      codec_selectable_capability_.sample_rate |=
          BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
    }
    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
      codec_selectable_capability_.sample_rate |=
          BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
    }
    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
      codec_selectable_capability_.sample_rate |=
          BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
    }

    if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;

    // Compute the common capability
@@ -1030,6 +1071,10 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info,

  // Select the bits per sample if there is no user preference
  do {
    // Compute the selectable capability
    codec_selectable_capability_.bits_per_sample =
        a2dp_aac_caps.bits_per_sample;

    if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
      break;

@@ -1092,6 +1137,16 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info,

  // Select the channel mode if there is no user preference
  do {
    // Compute the selectable capability
    if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
      codec_selectable_capability_.channel_mode |=
          BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
    }
    if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
      codec_selectable_capability_.channel_mode |=
          BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
    }

    if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;

    // Compute the common capability
@@ -1164,6 +1219,7 @@ fail:
  // Restore the internal state
  codec_config_ = saved_codec_config;
  codec_capability_ = saved_codec_capability;
  codec_selectable_capability_ = saved_codec_selectable_capability;
  codec_user_config_ = saved_codec_user_config;
  codec_audio_config_ = saved_codec_audio_config;
  memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+66 −20
Original line number Diff line number Diff line
@@ -35,22 +35,34 @@
/* The Media Type offset within the codec info byte array */
#define A2DP_MEDIA_TYPE_OFFSET 1

// Initializes the codec config.
// |codec_config| is the codec config to initialize.
// |codec_index| and |codec_priority| are the codec type and priority to use
// for the initialization.
static void init_btav_a2dp_codec_config(
    btav_a2dp_codec_config_t* codec_config, btav_a2dp_codec_index_t codec_index,
    btav_a2dp_codec_priority_t codec_priority) {
  memset(codec_config, 0, sizeof(btav_a2dp_codec_config_t));
  codec_config->codec_type = codec_index;
  codec_config->codec_priority = codec_priority;
}

A2dpCodecConfig::A2dpCodecConfig(btav_a2dp_codec_index_t codec_index,
                                 const std::string& name)
    : codec_index_(codec_index), name_(name) {
  setDefaultCodecPriority();

  memset(&codec_config_, 0, sizeof(codec_config_));
  codec_config_.codec_type = codec_index_;

  memset(&codec_capability_, 0, sizeof(codec_capability_));
  codec_capability_.codec_type = codec_index_;

  memset(&codec_user_config_, 0, sizeof(codec_user_config_));
  codec_user_config_.codec_type = codec_index_;

  memset(&codec_audio_config_, 0, sizeof(codec_audio_config_));
  codec_audio_config_.codec_type = codec_index_;
  init_btav_a2dp_codec_config(&codec_config_, codec_index_, codecPriority());
  init_btav_a2dp_codec_config(&codec_capability_, codec_index_,
                              codecPriority());
  init_btav_a2dp_codec_config(&codec_local_capability_, codec_index_,
                              codecPriority());
  init_btav_a2dp_codec_config(&codec_selectable_capability_, codec_index_,
                              codecPriority());
  init_btav_a2dp_codec_config(&codec_user_config_, codec_index_,
                              BTAV_A2DP_CODEC_PRIORITY_DEFAULT);
  init_btav_a2dp_codec_config(&codec_audio_config_, codec_index_,
                              BTAV_A2DP_CODEC_PRIORITY_DEFAULT);

  memset(ota_codec_config_, 0, sizeof(ota_codec_config_));
  memset(ota_codec_peer_capability_, 0, sizeof(ota_codec_peer_capability_));
@@ -61,7 +73,7 @@ A2dpCodecConfig::~A2dpCodecConfig() {}

void A2dpCodecConfig::setCodecPriority(
    btav_a2dp_codec_priority_t codec_priority) {
  if (codec_priority == 0) {
  if (codec_priority == BTAV_A2DP_CODEC_PRIORITY_DEFAULT) {
    // Compute the default codec priority
    setDefaultCodecPriority();
  } else {
@@ -71,7 +83,8 @@ void A2dpCodecConfig::setCodecPriority(

void A2dpCodecConfig::setDefaultCodecPriority() {
  // Compute the default codec priority
  codec_priority_ = 1000 * codec_index_ + 1;
  uint32_t priority = 1000 * codec_index_ + 1;
  codec_priority_ = static_cast<btav_a2dp_codec_priority_t>(priority);
}

A2dpCodecConfig* A2dpCodecConfig::createCodec(
@@ -141,6 +154,20 @@ btav_a2dp_codec_config_t A2dpCodecConfig::getCodecCapability() {
  return codec_capability_;
}

btav_a2dp_codec_config_t A2dpCodecConfig::getCodecLocalCapability() {
  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);

  // TODO: We should check whether the codec capability is valid
  return codec_local_capability_;
}

btav_a2dp_codec_config_t A2dpCodecConfig::getCodecSelectableCapability() {
  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);

  // TODO: We should check whether the codec capability is valid
  return codec_selectable_capability_;
}

btav_a2dp_codec_config_t A2dpCodecConfig::getCodecUserConfig() {
  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);

@@ -172,7 +199,7 @@ uint8_t A2dpCodecConfig::getAudioBitsPerSample() {
bool A2dpCodecConfig::isCodecConfigEmpty(
    const btav_a2dp_codec_config_t& codec_config) {
  return (
      (codec_config.codec_priority == 0) &&
      (codec_config.codec_priority == BTAV_A2DP_CODEC_PRIORITY_DEFAULT) &&
      (codec_config.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) &&
      (codec_config.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) &&
      (codec_config.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) &&
@@ -324,7 +351,8 @@ A2dpCodecConfig* A2dpCodecs::findSourceCodecConfig(

bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info,
                                bool is_capability,
                                uint8_t* p_result_codec_config) {
                                uint8_t* p_result_codec_config,
                                bool select_current_codec) {
  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
  A2dpCodecConfig* a2dp_codec_config = findSourceCodecConfig(p_peer_codec_info);
  if (a2dp_codec_config == nullptr) return false;
@@ -332,7 +360,9 @@ bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info,
                                         p_result_codec_config)) {
    return false;
  }
  if (select_current_codec) {
    current_codec_config_ = a2dp_codec_config;
  }
  return true;
}

@@ -522,7 +552,8 @@ fail:

bool A2dpCodecs::getCodecConfigAndCapabilities(
    btav_a2dp_codec_config_t* p_codec_config,
    std::vector<btav_a2dp_codec_config_t>* p_codec_capabilities) {
    std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,
    std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities) {
  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);

  if (current_codec_config_ != nullptr) {
@@ -533,11 +564,26 @@ bool A2dpCodecs::getCodecConfigAndCapabilities(
    *p_codec_config = codec_config;
  }

  std::vector<btav_a2dp_codec_config_t> codec_capabilities;
  std::vector<btav_a2dp_codec_config_t> codecs_capabilities;
  for (auto codec : orderedSourceCodecs()) {
    codec_capabilities.push_back(codec->getCodecCapability());
    codecs_capabilities.push_back(codec->getCodecLocalCapability());
  }
  *p_codec_capabilities = codec_capabilities;
  *p_codecs_local_capabilities = codecs_capabilities;

  codecs_capabilities.clear();
  for (auto codec : orderedSourceCodecs()) {
    btav_a2dp_codec_config_t codec_capability =
        codec->getCodecSelectableCapability();
    // Don't add entries that cannot be used
    if ((codec_capability.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) ||
        (codec_capability.bits_per_sample ==
         BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) ||
        (codec_capability.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) {
      continue;
    }
    codecs_capabilities.push_back(codec_capability);
  }
  *p_codecs_selectable_capabilities = codecs_capabilities;

  return true;
}
+77 −17
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ typedef struct {
  uint8_t alloc_method; /* Allocation method */
  uint8_t min_bitpool;  /* Minimum bitpool */
  uint8_t max_bitpool;  /* Maximum bitpool */
  btav_a2dp_codec_bits_per_sample_t bits_per_sample;
} tA2DP_SBC_CIE;

/* SBC SRC codec capabilities */
@@ -59,7 +60,8 @@ static const tA2DP_SBC_CIE a2dp_sbc_caps = {
    A2DP_SBC_IE_SUBBAND_8,             /* num_subbands */
    A2DP_SBC_IE_ALLOC_MD_L,            /* alloc_method */
    A2DP_SBC_IE_MIN_BITPOOL,           /* min_bitpool */
    A2DP_SBC_MAX_BITPOOL      /* max_bitpool */
    A2DP_SBC_MAX_BITPOOL,              /* max_bitpool */
    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
};

/* SBC SINK codec capabilities */
@@ -72,7 +74,8 @@ static const tA2DP_SBC_CIE a2dp_sbc_sink_caps = {
    (A2DP_SBC_IE_SUBBAND_4 | A2DP_SBC_IE_SUBBAND_8),   /* num_subbands */
    (A2DP_SBC_IE_ALLOC_MD_L | A2DP_SBC_IE_ALLOC_MD_S), /* alloc_method */
    A2DP_SBC_IE_MIN_BITPOOL,                           /* min_bitpool */
    A2DP_SBC_MAX_BITPOOL                               /* max_bitpool */
    A2DP_SBC_MAX_BITPOOL,                              /* max_bitpool */
    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16                 /* bits_per_sample */
};

/* Default SBC codec configuration */
@@ -83,7 +86,8 @@ const tA2DP_SBC_CIE a2dp_sbc_default_config = {
    A2DP_SBC_IE_SUBBAND_8,             /* num_subbands */
    A2DP_SBC_IE_ALLOC_MD_L,            /* alloc_method */
    A2DP_SBC_IE_MIN_BITPOOL,           /* min_bitpool */
    A2DP_SBC_MAX_BITPOOL      /* max_bitpool */
    A2DP_SBC_MAX_BITPOOL,              /* max_bitpool */
    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
};

static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_sbc = {
@@ -1014,7 +1018,7 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_SBC_CIE& config_cie,
  if (config_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48)
    result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;

  result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
  result->bits_per_sample = config_cie.bits_per_sample;

  if (config_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO)
    result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
@@ -1026,7 +1030,28 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_SBC_CIE& config_cie,
}

A2dpCodecConfigSbc::A2dpCodecConfigSbc()
    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC") {}
    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC") {
  // Compute the local capability
  if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
  }
  if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
  }
  codec_local_capability_.bits_per_sample = a2dp_sbc_caps.bits_per_sample;
  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
  }
  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
  }
  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
  }
  if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
  }
}

A2dpCodecConfigSbc::~A2dpCodecConfigSbc() {}

@@ -1214,6 +1239,8 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info,
  // Save the internal state
  btav_a2dp_codec_config_t saved_codec_config = codec_config_;
  btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
  btav_a2dp_codec_config_t saved_codec_selectable_capability =
      codec_selectable_capability_;
  btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
  btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
  uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
@@ -1270,6 +1297,16 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info,

  // Select the sample frequency if there is no user preference
  do {
    // Compute the selectable capability
    if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
      codec_selectable_capability_.sample_rate |=
          BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
    }
    if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
      codec_selectable_capability_.sample_rate |=
          BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
    }

    if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;

    // Compute the common capability
@@ -1326,6 +1363,10 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info,

  // Select the bits per sample if there is no user preference
  do {
    // Compute the selectable capability
    codec_selectable_capability_.bits_per_sample =
        a2dp_sbc_caps.bits_per_sample;

    if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
      break;

@@ -1396,6 +1437,24 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info,

  // Select the channel mode if there is no user preference
  do {
    // Compute the selectable capability
    if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
      codec_selectable_capability_.channel_mode |=
          BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
    }
    if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
      codec_selectable_capability_.channel_mode |=
          BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
    }
    if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
      codec_selectable_capability_.channel_mode |=
          BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
    }
    if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
      codec_selectable_capability_.channel_mode |=
          BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
    }

    if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;

    // Compute the common capability
@@ -1538,6 +1597,7 @@ fail:
  // Restore the internal state
  codec_config_ = saved_codec_config;
  codec_capability_ = saved_codec_capability;
  codec_selectable_capability_ = saved_codec_selectable_capability;
  codec_user_config_ = saved_codec_user_config;
  codec_audio_config_ = saved_codec_audio_config;
  memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
Loading