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

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

Handle properly AVDTP SetConfig from the A2DP Sink device

If the remote device is proactive and sends AVDTP SetConfig after
re-connection before the local device gets the chance to do it, the
internal codec setup state might be inconsistent.

* Fix the internal logic when the local device is Acceptor inside
  file bta_av_co.cc, and simplify some of the code.
* Fix the handling of p_scb->sep_info_idx inside bta_av_save_caps()
  when receiving capabilities from the remote device.
* Add new A2dpCodecConfig::setPeerCodecCapabilities() method that is
  implemented by each codec.

Bug: 77525584
Test: Manual - initiate connection by Momentum 2.0 Wireless Headset.
      Connect/disconnect/reconnect multiple headsets.

Change-Id: I456df7c8a2fa0758c0908a4628c4dfae3259dbdb
parent 82eb6b35
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -1523,24 +1523,30 @@ void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {

  cfg = p_scb->peer_cap;
  /* let application know the capability of the SNK */
  p_scb->p_cos->getcfg(p_scb->hndl, p_scb->peer_addr, cfg.codec_info,
  if (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->peer_addr, cfg.codec_info,
                           &p_scb->sep_info_idx, p_info->seid, &cfg.num_protect,
                       cfg.protect_info);

                           cfg.protect_info) != A2DP_SUCCESS) {
    p_scb->sep_info_idx++;
  APPL_TRACE_DEBUG("%s: result: sep_info_idx:%d", __func__,
    APPL_TRACE_DEBUG("%s: result: next sep_info_idx:%d", __func__,
                     p_scb->sep_info_idx);
  } else {
    // All capabilities found
    getcap_done = true;
    APPL_TRACE_DEBUG("%s: result: done sep_info_idx:%d", __func__,
                     p_scb->sep_info_idx);
  }
  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
                   A2DP_CodecInfoString(cfg.codec_info).c_str());

  if (p_scb->num_seps > p_scb->sep_info_idx) {
  if (p_scb->num_seps > p_scb->sep_info_idx && !getcap_done) {
    /* Some devices have seps at the end of the discover list, which is not */
    /* matching media type(video not audio).                                */
    /* In this case, we are done with getcap without sending another        */
    /* request to AVDT.                                                     */
    if (!bta_av_next_getcap(p_scb, p_data)) getcap_done = true;
  } else
  } else {
    getcap_done = true;
  }

  if (getcap_done) {
    APPL_TRACE_DEBUG("%s: getcap_done: num_seps:%d sep_info_idx:%d wait:0x%x",
+218 −150
Original line number Diff line number Diff line
@@ -219,7 +219,7 @@ class BtaAvCo {

  /**
   * Process retrieved codec configuration and content protection from
   * Peer Source SEP.
   * Peer Sink SEP.
   *
   * @param bta_av_handle the BTA AV handle to identify the peer
   * @param peer_address the peer address
@@ -478,6 +478,26 @@ class BtaAvCo {
   */
  BtaAvCoPeer* FindPeer(const RawAddress& peer_address);

  /**
   * Find the peer Sink SEP entry for a given codec index.
   *
   * @param p_peer the peer to use
   * @param codec_index the codec index to use
   * @return the peer Sink SEP for the codec index if found, otherwise nullptr
   */
  BtaAvCoSep* FindPeerSink(BtaAvCoPeer* p_peer,
                           btav_a2dp_codec_index_t codec_index);

  /**
   * Find the peer Source SEP entry for a given codec index.
   *
   * @param p_peer the peer to use
   * @param codec_config the codec index to use
   * @return the peer Source SEP for the codec index if found, otherwise nullptr
   */
  BtaAvCoSep* FindPeerSource(BtaAvCoPeer* p_peer,
                             btav_a2dp_codec_index_t codec_index);

 private:
  /**
   * Reset the state.
@@ -513,7 +533,7 @@ class BtaAvCo {
   * @return a pointer to the corresponding SEP Sink entry on success,
   * otherwise nullptr
   */
  BtaAvCoSep* SelectSourceCodec(BtaAvCoPeer* p_peer);
  const BtaAvCoSep* SelectSourceCodec(BtaAvCoPeer* p_peer);

  /**
   * Select the Sink codec configuration based on peer codec support.
@@ -525,7 +545,7 @@ class BtaAvCo {
   * @return a pointer to the corresponding SEP Source entry on success,
   * otherwise nullptr
   */
  BtaAvCoSep* SelectSinkCodec(BtaAvCoPeer* p_peer);
  const BtaAvCoSep* SelectSinkCodec(BtaAvCoPeer* p_peer);

  /**
   * Save new codec configuration.
@@ -561,6 +581,15 @@ class BtaAvCo {
                         uint8_t num_protect, const uint8_t* p_protect_info,
                         bool* p_restart_output);

  /**
   * Update all selectable Source codecs with the corresponding codec
   * information from a Sink peer.
   *
   * @param p_peer the peer Sink SEP to use
   * @return the number of codecs that have been updated
   */
  size_t UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer);

  /**
   * Update a selectable Source codec with the corresponding codec information
   * from a Sink peer.
@@ -572,6 +601,15 @@ class BtaAvCo {
  bool UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config,
                                   BtaAvCoPeer* p_peer);

  /**
   * Update all selectable Sink codecs with the corresponding codec
   * information from a Source peer.
   *
   * @param p_peer the peer Source SEP to use
   * @return the number of codecs that have been updated
   */
  size_t UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer);

  /**
   * Update a selectable Sink codec with the corresponding codec information
   * from a Source peer.
@@ -591,8 +629,8 @@ class BtaAvCo {
   * @return a pointer to the corresponding SEP Sink entry on success,
   * otnerwise nullptr
   */
  BtaAvCoSep* AttemptSourceCodecSelection(const A2dpCodecConfig& codec_config,
                                          BtaAvCoPeer* p_peer);
  const BtaAvCoSep* AttemptSourceCodecSelection(
      const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer);

  /**
   * Attempt to select Sink codec configuration for a Source peer.
@@ -602,8 +640,8 @@ class BtaAvCo {
   * @return a pointer to the corresponding SEP Source entry on success,
   * otnerwise nullptr
   */
  BtaAvCoSep* AttemptSinkCodecSelection(const A2dpCodecConfig& codec_config,
                                        BtaAvCoPeer* p_peer);
  const BtaAvCoSep* AttemptSinkCodecSelection(
      const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer);

  /**
   * Check if a peer SEP has content protection enabled.
@@ -838,6 +876,7 @@ void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle,
  p_peer->num_rx_sinks = 0;
  p_peer->num_rx_sources = 0;
  p_peer->num_sup_sinks = 0;
  p_peer->num_sup_sources = 0;
  if (uuid_local == UUID_SERVCLASS_AUDIO_SINK) {
    p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE;
  } else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE) {
@@ -898,14 +937,32 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig(
      (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
    return A2DP_FAIL;
  }
  APPL_TRACE_DEBUG("%s: last Sink reached", __func__);
  APPL_TRACE_DEBUG("%s: last Sink codec reached for peer %s", __func__,
                   p_peer->addr.ToString().c_str());

  // Select the Source codec
  const BtaAvCoSep* p_sink = SelectSourceCodec(p_peer);
  const BtaAvCoSep* p_sink = nullptr;
  if (p_peer->acceptor) {
    UpdateAllSelectableSourceCodecs(p_peer);
    if (p_peer->p_sink == nullptr) {
      // Update the selected codec
      p_peer->p_sink =
          FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_peer->codec_config));
    }
    p_sink = p_peer->p_sink;
    if (p_sink == nullptr) {
      APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s",
                       __func__, p_peer->addr.ToString().c_str());
      return A2DP_FAIL;
    }
  } else {
    p_sink = SelectSourceCodec(p_peer);
    if (p_sink == nullptr) {
    APPL_TRACE_ERROR("%s: cannot set up codec for the peer Sink", __func__);
      APPL_TRACE_ERROR("%s: cannot set up codec for peer %s", __func__,
                       p_peer->addr.ToString().c_str());
      return A2DP_FAIL;
    }
  }

  // By default, no content protection
  *p_num_protect = 0;
@@ -915,18 +972,19 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig(
  }

  // If acceptor -> reconfig otherwise reply for configuration
  *p_sep_info_idx = p_sink->sep_info_idx;
  APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__,
                   p_peer->addr.ToString().c_str(),
                   (p_peer->acceptor) ? "true" : "false",
                   (p_peer->reconfig_needed) ? "true" : "false");
  if (p_peer->acceptor) {
    // Stop fetching caps once we retrieved a supported codec
    APPL_TRACE_EVENT("%s: no need to fetch more SEPs", __func__);
    *p_sep_info_idx = p_peer->num_seps;
    if (p_peer->reconfig_needed) {
      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
                       bta_av_handle);
      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__,
                       bta_av_handle, p_peer->addr.ToString().c_str());
      BTA_AvReconfig(bta_av_handle, true, p_sink->sep_info_idx,
                     p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst);
    }
  } else {
    *p_sep_info_idx = p_sink->sep_info_idx;
    memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
  }

@@ -992,14 +1050,32 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle,
      (p_peer->num_sup_sources != BTA_AV_CO_NUM_ELEMENTS(p_peer->sources))) {
    return A2DP_FAIL;
  }
  APPL_TRACE_DEBUG("%s: last Source reached", __func__);
  APPL_TRACE_DEBUG("%s: last Source codec reached for peer %s", __func__,
                   p_peer->addr.ToString().c_str());

  // Select the Sink codec
  const BtaAvCoSep* p_source = SelectSinkCodec(p_peer);
  const BtaAvCoSep* p_source = nullptr;
  if (p_peer->acceptor) {
    UpdateAllSelectableSinkCodecs(p_peer);
    if (p_peer->p_source == nullptr) {
      // Update the selected codec
      p_peer->p_source =
          FindPeerSource(p_peer, A2DP_SinkCodecIndex(p_peer->codec_config));
    }
    p_source = p_peer->p_source;
    if (p_source == nullptr) {
      APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s",
                       __func__, p_peer->addr.ToString().c_str());
      return A2DP_FAIL;
    }
  } else {
    p_source = SelectSinkCodec(p_peer);
    if (p_source == nullptr) {
    APPL_TRACE_ERROR("%s: cannot set up codec for the peer Source", __func__);
      APPL_TRACE_ERROR("%s: cannot set up codec for the peer %s", __func__,
                       p_peer->addr.ToString().c_str());
      return A2DP_FAIL;
    }
  }

  // By default, no content protection
  *p_num_protect = 0;
@@ -1009,18 +1085,19 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle,
  }

  // If acceptor -> reconfig otherwise reply for configuration
  *p_sep_info_idx = p_source->sep_info_idx;
  APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__,
                   p_peer->addr.ToString().c_str(),
                   (p_peer->acceptor) ? "true" : "false",
                   (p_peer->reconfig_needed) ? "true" : "false");
  if (p_peer->acceptor) {
    // Stop fetching caps once we retrieved a supported codec
    APPL_TRACE_EVENT("%s: no need to fetch more SEPs", __func__);
    *p_sep_info_idx = p_peer->num_seps;
    if (p_peer->reconfig_needed) {
      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
                       bta_av_handle);
      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__,
                       bta_av_handle, p_peer->addr.ToString().c_str());
      BTA_AvReconfig(bta_av_handle, true, p_source->sep_info_idx,
                     p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst);
    }
  } else {
    *p_sep_info_idx = p_source->sep_info_idx;
    memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
  }

@@ -1314,6 +1391,8 @@ bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) {

  active_peer_ = p_peer;
  memcpy(codec_config_, active_peer_->codec_config, AVDT_CODEC_SIZE);
  APPL_TRACE_DEBUG("%s: codec = %s", __func__,
                   A2DP_CodecInfoString(codec_config_).c_str());
  ReportSourceCodecState(active_peer_);
  return true;
}
@@ -1378,16 +1457,7 @@ bool BtaAvCo::SetCodecUserConfig(

  // Find the peer SEP codec to use
  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 =
          A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
      if (peer_codec_index != codec_user_config.codec_type) continue;
      if (!AudioSepHasContentProtection(&p_peer->sinks[index])) {
        continue;
      }
      p_sink = &p_peer->sinks[index];
      break;
    }
    p_sink = FindPeerSink(p_peer, codec_user_config.codec_type);
  } else {
    // Use the current sink codec
    p_sink = p_peer->p_sink;
@@ -1430,6 +1500,7 @@ bool BtaAvCo::SetCodecUserConfig(
      goto done;
    }

    p_peer->acceptor = false;
    APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
                     p_peer->BtaAvHandle());
    BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
@@ -1495,6 +1566,7 @@ bool BtaAvCo::SetCodecAudioConfig(
      APPL_TRACE_WARNING("%s: not all peer's capabilities have been retrieved",
                         __func__);
    } else {
      p_peer->acceptor = false;
      APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
                       p_peer->BtaAvHandle());
      BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
@@ -1529,6 +1601,9 @@ bool BtaAvCo::ReportSourceCodecState(BtaAvCoPeer* p_peer) {
        __func__, p_peer->addr.ToString().c_str());
    return false;
  }
  APPL_TRACE_DEBUG("%s: peer %s codec_config=%s", __func__,
                   p_peer->addr.ToString().c_str(),
                   codec_config.ToString().c_str());
  do_in_jni_thread(
      FROM_HERE,
      base::Bind(&btif_av_report_source_codec_state, p_peer->addr, codec_config,
@@ -1620,17 +1695,13 @@ bool BtaAvCo::AudioSepHasContentProtection(const BtaAvCoSep* p_sep) {
  return true;
}

BtaAvCoSep* BtaAvCo::SelectSourceCodec(BtaAvCoPeer* p_peer) {
  BtaAvCoSep* p_sink = nullptr;
const BtaAvCoSep* BtaAvCo::SelectSourceCodec(BtaAvCoPeer* p_peer) {
  const BtaAvCoSep* p_sink = nullptr;

  // 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 : p_peer->GetCodecs()->orderedSourceCodecs()) {
    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
                     iter->name().c_str());
    UpdateSelectableSourceCodec(*iter, p_peer);
  }
  UpdateAllSelectableSourceCodecs(p_peer);

  // Select the codec
  for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) {
@@ -1650,17 +1721,13 @@ BtaAvCoSep* BtaAvCo::SelectSourceCodec(BtaAvCoPeer* p_peer) {
  return p_sink;
}

BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) {
  BtaAvCoSep* p_source = nullptr;
const BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) {
  const BtaAvCoSep* p_source = nullptr;

  // 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 : p_peer->GetCodecs()->orderedSinkCodecs()) {
    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
                     iter->name().c_str());
    UpdateSelectableSinkCodec(*iter, p_peer);
  }
  UpdateAllSelectableSinkCodecs(p_peer);

  // Select the codec
  for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) {
@@ -1680,30 +1747,70 @@ BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) {
  return p_source;
}

BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection(
    const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) {
  uint8_t new_codec_config[AVDT_CODEC_SIZE];

  APPL_TRACE_DEBUG("%s", __func__);
BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer,
                                  btav_a2dp_codec_index_t codec_index) {
  if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
    APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__,
                       p_peer->addr.ToString().c_str());
    return nullptr;
  }

  // Find the peer Sink for the codec
  BtaAvCoSep* p_sink = nullptr;
  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
    BtaAvCoSep* p_sink = &p_peer->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()) {
        A2DP_SourceCodecIndex(p_sink->codec_caps);
    if (peer_codec_index != codec_index) {
      continue;
    }
    if (!AudioSepHasContentProtection(&p_peer->sinks[index])) {
    if (!AudioSepHasContentProtection(p_sink)) {
      APPL_TRACE_DEBUG(
          "%s: peer Sink for codec %s does not support "
          "Content Protection",
          __func__, codec_config.name().c_str());
          __func__, A2DP_CodecIndexStr(codec_index));
      continue;
    }
    p_sink = &p_peer->sinks[index];
    break;
    return p_sink;
  }
  return nullptr;
}

BtaAvCoSep* BtaAvCo::FindPeerSource(BtaAvCoPeer* p_peer,
                                    btav_a2dp_codec_index_t codec_index) {
  if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
    APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__,
                       p_peer->addr.ToString().c_str());
    return nullptr;
  }

  // Find the peer Source for the codec
  for (size_t index = 0; index < p_peer->num_sup_sources; index++) {
    BtaAvCoSep* p_source = &p_peer->sources[index];
    btav_a2dp_codec_index_t peer_codec_index =
        A2DP_SinkCodecIndex(p_source->codec_caps);
    if (peer_codec_index != codec_index) {
      continue;
    }
    if (!AudioSepHasContentProtection(p_source)) {
      APPL_TRACE_DEBUG(
          "%s: peer Source for codec %s does not support "
          "Content Protection",
          __func__, A2DP_CodecIndexStr(codec_index));
      continue;
    }
    return p_source;
  }
  return nullptr;
}

const BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection(
    const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) {
  uint8_t new_codec_config[AVDT_CODEC_SIZE];

  APPL_TRACE_DEBUG("%s", __func__);

  // Find the peer Sink for the codec
  BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex());
  if (p_sink == nullptr) {
    APPL_TRACE_DEBUG("%s: peer Sink for codec %s not found", __func__,
                     codec_config.name().c_str());
@@ -1724,30 +1831,14 @@ BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection(
  return p_sink;
}

BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection(
const BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection(
    const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) {
  uint8_t new_codec_config[AVDT_CODEC_SIZE];

  APPL_TRACE_DEBUG("%s", __func__);

  // Find the peer Source for the codec
  BtaAvCoSep* p_source = nullptr;
  for (size_t index = 0; index < p_peer->num_sup_sources; index++) {
    btav_a2dp_codec_index_t peer_codec_index =
        A2DP_SinkCodecIndex(p_peer->sources[index].codec_caps);
    if (peer_codec_index != codec_config.codecIndex()) {
      continue;
    }
    if (!AudioSepHasContentProtection(&p_peer->sources[index])) {
      APPL_TRACE_DEBUG(
          "%s: peer Source for codec %s does not support "
          "Content Protection",
          __func__, codec_config.name().c_str());
      continue;
    }
    p_source = &p_peer->sources[index];
    break;
  }
  BtaAvCoSep* p_source = FindPeerSource(p_peer, codec_config.codecIndex());
  if (p_source == nullptr) {
    APPL_TRACE_DEBUG("%s: peer Source for codec %s not found", __func__,
                     codec_config.name().c_str());
@@ -1768,77 +1859,69 @@ BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection(
  return p_source;
}

bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config,
                                          BtaAvCoPeer* p_peer) {
  uint8_t new_codec_config[AVDT_CODEC_SIZE];

  APPL_TRACE_DEBUG("%s", __func__);
size_t BtaAvCo::UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer) {
  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());

  // Find the peer Sink for the codec
  const BtaAvCoSep* p_sink = nullptr;
  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;
  size_t updated_codecs = 0;
  for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) {
    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
                     iter->name().c_str());
    if (UpdateSelectableSourceCodec(*iter, p_peer)) {
      updated_codecs++;
    }
    if (!AudioSepHasContentProtection(&p_peer->sinks[index])) {
      APPL_TRACE_DEBUG(
          "%s: peer Sink for codec %s does not support "
          "Content Protection",
          __func__, codec_config.name().c_str());
      continue;
  }
    p_sink = &p_peer->sinks[index];
    break;
  return updated_codecs;
}

bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config,
                                          BtaAvCoPeer* p_peer) {
  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());

  // Find the peer Sink for the codec
  const BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex());
  if (p_sink == nullptr) {
    // The peer Sink device does not support this codec
    return false;
  }
  if (!p_peer->GetCodecs()->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());
  if (!p_peer->GetCodecs()->setPeerSinkCodecCapabilities(p_sink->codec_caps)) {
    APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s",
                       __func__, p_peer->addr.ToString().c_str(),
                       A2DP_CodecName(p_sink->codec_caps));
    return false;
  }
  return true;
}

bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config,
                                        BtaAvCoPeer* p_peer) {
  uint8_t new_codec_config[AVDT_CODEC_SIZE];

  APPL_TRACE_DEBUG("%s", __func__);
size_t BtaAvCo::UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer) {
  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());

  // Find the peer Source for the codec
  const BtaAvCoSep* p_source = nullptr;
  for (size_t index = 0; index < p_peer->num_sup_sources; index++) {
    btav_a2dp_codec_index_t peer_codec_index =
        A2DP_SinkCodecIndex(p_peer->sources[index].codec_caps);
    if (peer_codec_index != codec_config.codecIndex()) {
      continue;
  size_t updated_codecs = 0;
  for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) {
    APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
                     iter->name().c_str());
    if (UpdateSelectableSinkCodec(*iter, p_peer)) {
      updated_codecs++;
    }
    if (!AudioSepHasContentProtection(&p_peer->sources[index])) {
      APPL_TRACE_DEBUG(
          "%s: peer Source for codec %s does not support "
          "Content Protection",
          __func__, codec_config.name().c_str());
      continue;
  }
    p_source = &p_peer->sources[index];
    break;
  return updated_codecs;
}

bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config,
                                        BtaAvCoPeer* p_peer) {
  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());

  // Find the peer Source for the codec
  const BtaAvCoSep* p_source =
      FindPeerSource(p_peer, codec_config.codecIndex());
  if (p_source == nullptr) {
    // The peer Source device does not support this codec
    return false;
  }
  if (!p_peer->GetCodecs()->setSinkCodecConfig(
          p_source->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());
  if (!p_peer->GetCodecs()->setPeerSourceCodecCapabilities(
          p_source->codec_caps)) {
    APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s",
                       __func__, p_peer->addr.ToString().c_str(),
                       A2DP_CodecName(p_source->codec_caps));
    return false;
  }
  return true;
@@ -1882,23 +1965,8 @@ bool BtaAvCo::SetCodecOtaConfig(BtaAvCoPeer* p_peer,
  *p_restart_output = false;

  // Find the peer SEP codec to use
  btav_a2dp_codec_index_t ota_codec_index =
      A2DP_SourceCodecIndex(p_ota_codec_config);
  if (ota_codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
    APPL_TRACE_WARNING("%s: invalid peer codec config", __func__);
    return false;
  }
  const BtaAvCoSep* p_sink = nullptr;
  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 != ota_codec_index) continue;
    if (!AudioSepHasContentProtection(&p_peer->sinks[index])) {
      continue;
    }
    p_sink = &p_peer->sinks[index];
    break;
  }
  const BtaAvCoSep* p_sink =
      FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_ota_codec_config));
  if ((p_peer->num_sup_sinks > 0) && (p_sink == nullptr)) {
    // There are no peer SEPs if we didn't do the discovery procedure yet.
    // We have all the information we need from the peer, so we can
Loading