From e86055ad44f7c38b87152e816c7bb28f60910b86 Mon Sep 17 00:00:00 2001
From: Pavlin Radoslavov <pavlin@google.com>
Date: Mon, 9 Apr 2018 18:01:41 -0700
Subject: [PATCH] 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
---
 system/bta/av/bta_av_aact.cc               |  24 +-
 system/btif/co/bta_av_co.cc                | 368 ++++++++++++---------
 system/stack/a2dp/a2dp_aac.cc              |  72 +++-
 system/stack/a2dp/a2dp_codec_config.cc     |  22 ++
 system/stack/a2dp/a2dp_sbc.cc              |  80 ++++-
 system/stack/a2dp/a2dp_vendor_aptx.cc      | 120 +++++--
 system/stack/a2dp/a2dp_vendor_aptx_hd.cc   | 133 ++++++--
 system/stack/a2dp/a2dp_vendor_ldac.cc      | 150 +++++++--
 system/stack/include/a2dp_aac.h            |   2 +
 system/stack/include/a2dp_codec_api.h      |  16 +
 system/stack/include/a2dp_sbc.h            |   2 +
 system/stack/include/a2dp_vendor_aptx.h    |   2 +
 system/stack/include/a2dp_vendor_aptx_hd.h |   2 +
 system/stack/include/a2dp_vendor_ldac.h    |   2 +
 14 files changed, 737 insertions(+), 258 deletions(-)

diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index ba4bbdd0e6f..c339e88ac01 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -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,
-                       &p_scb->sep_info_idx, p_info->seid, &cfg.num_protect,
-                       cfg.protect_info);
-
-  p_scb->sep_info_idx++;
-  APPL_TRACE_DEBUG("%s: result: sep_info_idx:%d", __func__,
-                   p_scb->sep_info_idx);
+  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) != A2DP_SUCCESS) {
+    p_scb->sep_info_idx++;
+    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",
diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc
index d01707cfc16..364991957e0 100644
--- a/system/btif/co/bta_av_co.cc
+++ b/system/btif/co/bta_av_co.cc
@@ -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,13 +937,31 @@ 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);
-  if (p_sink == nullptr) {
-    APPL_TRACE_ERROR("%s: cannot set up codec for the peer Sink", __func__);
-    return A2DP_FAIL;
+  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 peer %s", __func__,
+                       p_peer->addr.ToString().c_str());
+      return A2DP_FAIL;
+    }
   }
 
   // By default, no content protection
@@ -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,13 +1050,31 @@ 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);
-  if (p_source == nullptr) {
-    APPL_TRACE_ERROR("%s: cannot set up codec for the peer Source", __func__);
-    return A2DP_FAIL;
+  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 %s", __func__,
+                       p_peer->addr.ToString().c_str());
+      return A2DP_FAIL;
+    }
   }
 
   // By default, no content protection
@@ -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;
+    }
+    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;
     }
-    p_sink = &p_peer->sinks[index];
-    break;
+    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;
 }
 
+size_t BtaAvCo::UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+
+  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++;
+    }
+  }
+  return updated_codecs;
+}
+
 bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config,
                                           BtaAvCoPeer* p_peer) {
-  uint8_t new_codec_config[AVDT_CODEC_SIZE];
-
-  APPL_TRACE_DEBUG("%s", __func__);
+  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;
-    }
-    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;
-  }
+  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;
 }
 
+size_t BtaAvCo::UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str());
+
+  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++;
+    }
+  }
+  return updated_codecs;
+}
+
 bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config,
                                         BtaAvCoPeer* p_peer) {
-  uint8_t new_codec_config[AVDT_CODEC_SIZE];
-
-  APPL_TRACE_DEBUG("%s", __func__);
+  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;
-    }
-    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;
-  }
+  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
diff --git a/system/stack/a2dp/a2dp_aac.cc b/system/stack/a2dp/a2dp_aac.cc
index 4a29b78d8da..b9dbfbeaf1c 100644
--- a/system/stack/a2dp/a2dp_aac.cc
+++ b/system/stack/a2dp/a2dp_aac.cc
@@ -1295,7 +1295,7 @@ bool A2dpCodecConfigAacBase::setCodecConfig(const uint8_t* p_peer_codec_info,
   if (codec_user_config_.codec_specific_4 != 0)
     codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
 
-  // Create a local copy of the peer codec capability, and the
+  // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
     status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
@@ -1324,6 +1324,76 @@ fail:
          sizeof(ota_codec_peer_config_));
   return false;
 }
+bool A2dpCodecConfigAacBase::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_AAC_CIE peer_info_cie;
+  uint8_t channelMode;
+  uint16_t sampleRate;
+  const tA2DP_AAC_CIE* p_a2dp_aac_caps =
+      (is_source_) ? &a2dp_aac_source_caps : &a2dp_aac_sink_caps;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoAac(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = p_a2dp_aac_caps->sampleRate & peer_info_cie.sampleRate;
+  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;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      p_a2dp_aac_caps->bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = p_a2dp_aac_caps->channelMode & peer_info_cie.channelMode;
+  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;
+  }
+
+  status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                             ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
 
 A2dpCodecConfigAacSink::A2dpCodecConfigAacSink(
     btav_a2dp_codec_priority_t codec_priority)
diff --git a/system/stack/a2dp/a2dp_codec_config.cc b/system/stack/a2dp/a2dp_codec_config.cc
index 21813cd479b..1279cebc393 100644
--- a/system/stack/a2dp/a2dp_codec_config.cc
+++ b/system/stack/a2dp/a2dp_codec_config.cc
@@ -908,6 +908,28 @@ fail:
   return false;
 }
 
+bool A2dpCodecs::setPeerSinkCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+  if (!A2DP_IsPeerSinkCodecValid(p_peer_codec_capabilities)) return false;
+  A2dpCodecConfig* a2dp_codec_config =
+      findSourceCodecConfig(p_peer_codec_capabilities);
+  if (a2dp_codec_config == nullptr) return false;
+  return a2dp_codec_config->setPeerCodecCapabilities(p_peer_codec_capabilities);
+}
+
+bool A2dpCodecs::setPeerSourceCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+  if (!A2DP_IsPeerSourceCodecValid(p_peer_codec_capabilities)) return false;
+  A2dpCodecConfig* a2dp_codec_config =
+      findSinkCodecConfig(p_peer_codec_capabilities);
+  if (a2dp_codec_config == nullptr) return false;
+  return a2dp_codec_config->setPeerCodecCapabilities(p_peer_codec_capabilities);
+}
+
 bool A2dpCodecs::getCodecConfigAndCapabilities(
     btav_a2dp_codec_config_t* p_codec_config,
     std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,
diff --git a/system/stack/a2dp/a2dp_sbc.cc b/system/stack/a2dp/a2dp_sbc.cc
index 565a67de910..43f7625ba48 100644
--- a/system/stack/a2dp/a2dp_sbc.cc
+++ b/system/stack/a2dp/a2dp_sbc.cc
@@ -1425,12 +1425,13 @@ bool A2dpCodecConfigSbcBase::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    memcpy(ota_codec_peer_capability_, p_peer_codec_info,
-           sizeof(ota_codec_peer_capability_));
+    status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                               ota_codec_peer_capability_);
   } else {
-    memcpy(ota_codec_peer_config_, p_peer_codec_info,
-           sizeof(ota_codec_peer_config_));
+    status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                               ota_codec_peer_config_);
   }
+  CHECK(status == A2DP_SUCCESS);
   status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
                              ota_codec_config_);
   CHECK(status == A2DP_SUCCESS);
@@ -1451,6 +1452,77 @@ fail:
   return false;
 }
 
+bool A2dpCodecConfigSbcBase::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_SBC_CIE peer_info_cie;
+  uint8_t samp_freq;
+  uint8_t ch_mode;
+  const tA2DP_SBC_CIE* p_a2dp_sbc_caps =
+      (is_source_) ? &a2dp_sbc_source_caps : &a2dp_sbc_sink_caps;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoSbc(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  samp_freq = p_a2dp_sbc_caps->samp_freq & peer_info_cie.samp_freq;
+  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;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      p_a2dp_sbc_caps->bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  ch_mode = p_a2dp_sbc_caps->ch_mode & peer_info_cie.ch_mode;
+  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;
+  }
+
+  status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                             ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
+
 A2dpCodecConfigSbcSink::A2dpCodecConfigSbcSink(
     btav_a2dp_codec_priority_t codec_priority)
     : A2dpCodecConfigSbcBase(BTAV_A2DP_CODEC_INDEX_SINK_SBC, "SBC(Sink)",
diff --git a/system/stack/a2dp/a2dp_vendor_aptx.cc b/system/stack/a2dp/a2dp_vendor_aptx.cc
index 48e9b967bba..7017f06635b 100644
--- a/system/stack/a2dp/a2dp_vendor_aptx.cc
+++ b/system/stack/a2dp/a2dp_vendor_aptx.cc
@@ -49,7 +49,7 @@ typedef struct {
 } tA2DP_APTX_CIE;
 
 /* aptX Source codec capabilities */
-static const tA2DP_APTX_CIE a2dp_aptx_caps = {
+static const tA2DP_APTX_CIE a2dp_aptx_source_caps = {
     A2DP_APTX_VENDOR_ID,                                       /* vendorId */
     A2DP_APTX_CODEC_ID_BLUETOOTH,                              /* codecId */
     (A2DP_APTX_SAMPLERATE_44100 | A2DP_APTX_SAMPLERATE_48000), /* sampleRate */
@@ -401,7 +401,7 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptx(
 const char* A2DP_VendorCodecIndexStrAptx(void) { return "aptX"; }
 
 bool A2DP_VendorInitCodecConfigAptx(AvdtpSepConfig* p_cfg) {
-  if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_caps,
+  if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_source_caps,
                          p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -422,17 +422,18 @@ A2dpCodecConfigAptx::A2dpCodecConfigAptx(
     : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX",
                       codec_priority) {
   // Compute the local capability
-  if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+  if (a2dp_aptx_source_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+  if (a2dp_aptx_source_caps.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_aptx_caps.bits_per_sample;
-  if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_aptx_source_caps.bits_per_sample;
+  if (a2dp_aptx_source_caps.channelMode & A2DP_APTX_CHANNELS_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_STEREO) {
+  if (a2dp_aptx_source_caps.channelMode & A2DP_APTX_CHANNELS_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
@@ -597,7 +598,7 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
                                          bool is_capability,
                                          uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_APTX_CIE sink_info_cie;
+  tA2DP_APTX_CIE peer_info_cie;
   tA2DP_APTX_CIE result_config_cie;
   uint8_t sampleRate;
   uint8_t channelMode;
@@ -619,9 +620,9 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoAptx(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoAptx(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -630,13 +631,13 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_aptx_caps.vendorId;
-  result_config_cie.codecId = a2dp_aptx_caps.codecId;
+  result_config_cie.vendorId = a2dp_aptx_source_caps.vendorId;
+  result_config_cie.codecId = a2dp_aptx_source_caps.codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_aptx_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = a2dp_aptx_source_caps.sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -693,7 +694,7 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_aptx_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_aptx_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -706,9 +707,10 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_caps.sampleRate, sink_info_cie.sampleRate);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_source_caps.sampleRate,
+              peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -735,7 +737,7 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_aptx_caps.bits_per_sample;
+        a2dp_aptx_source_caps.bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -769,7 +771,7 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
   //
   // Select the channel mode
   //
-  channelMode = a2dp_aptx_caps.channelMode & sink_info_cie.channelMode;
+  channelMode = a2dp_aptx_source_caps.channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -820,7 +822,7 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_aptx_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_aptx_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -833,17 +835,20 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_caps.channelMode, sink_info_cie.channelMode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_source_caps.channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
   //
   // Set the rest of the fields as bit-wise AND operation
   //
-  result_config_cie.future1 = a2dp_aptx_caps.future1 & sink_info_cie.future1;
-  result_config_cie.future2 = a2dp_aptx_caps.future2 & sink_info_cie.future2;
+  result_config_cie.future1 =
+      a2dp_aptx_source_caps.future1 & peer_info_cie.future1;
+  result_config_cie.future2 =
+      a2dp_aptx_source_caps.future2 & peer_info_cie.future2;
 
   if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
                          p_result_codec_config) != A2DP_SUCCESS) {
@@ -865,10 +870,10 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -892,3 +897,64 @@ fail:
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+bool A2dpCodecConfigAptx::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_APTX_CIE peer_info_cie;
+  uint8_t sampleRate;
+  uint8_t channelMode;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoAptx(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = a2dp_aptx_source_caps.sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      a2dp_aptx_source_caps.bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = a2dp_aptx_source_caps.channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_APTX_CHANNELS_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_APTX_CHANNELS_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                              ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc
index 3a85b72ea02..798e4fd218d 100644
--- a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc
+++ b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc
@@ -51,7 +51,7 @@ typedef struct {
 } tA2DP_APTX_HD_CIE;
 
 /* aptX-HD Source codec capabilities */
-static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_caps = {
+static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_source_caps = {
     A2DP_APTX_HD_VENDOR_ID,          /* vendorId */
     A2DP_APTX_HD_CODEC_ID_BLUETOOTH, /* codecId */
     (A2DP_APTX_HD_SAMPLERATE_44100 |
@@ -418,7 +418,7 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptxHd(
 const char* A2DP_VendorCodecIndexStrAptxHd(void) { return "aptX-HD"; }
 
 bool A2DP_VendorInitCodecConfigAptxHd(AvdtpSepConfig* p_cfg) {
-  if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_hd_caps,
+  if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_hd_source_caps,
                            p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -439,17 +439,18 @@ A2dpCodecConfigAptxHd::A2dpCodecConfigAptxHd(
     : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD",
                       codec_priority) {
   // Compute the local capability
-  if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+  if (a2dp_aptx_hd_source_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+  if (a2dp_aptx_hd_source_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_aptx_hd_caps.bits_per_sample;
-  if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_aptx_hd_source_caps.bits_per_sample;
+  if (a2dp_aptx_hd_source_caps.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+  if (a2dp_aptx_hd_source_caps.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
@@ -614,7 +615,7 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
                                            bool is_capability,
                                            uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_APTX_HD_CIE sink_info_cie;
+  tA2DP_APTX_HD_CIE peer_info_cie;
   tA2DP_APTX_HD_CIE result_config_cie;
   uint8_t sampleRate;
   uint8_t channelMode;
@@ -636,9 +637,9 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoAptxHd(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoAptxHd(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -647,13 +648,13 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_aptx_hd_caps.vendorId;
-  result_config_cie.codecId = a2dp_aptx_hd_caps.codecId;
+  result_config_cie.vendorId = a2dp_aptx_hd_source_caps.vendorId;
+  result_config_cie.codecId = a2dp_aptx_hd_source_caps.codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_aptx_hd_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = a2dp_aptx_hd_source_caps.sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -710,7 +711,7 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_aptx_hd_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_aptx_hd_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -723,9 +724,10 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_hd_caps.sampleRate, sink_info_cie.sampleRate);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_hd_source_caps.sampleRate,
+              peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -752,7 +754,7 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_aptx_hd_caps.bits_per_sample;
+        a2dp_aptx_hd_source_caps.bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -786,7 +788,8 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   //
   // Select the channel mode
   //
-  channelMode = a2dp_aptx_hd_caps.channelMode & sink_info_cie.channelMode;
+  channelMode =
+      a2dp_aptx_hd_source_caps.channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -837,7 +840,7 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_aptx_hd_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_aptx_hd_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -850,10 +853,10 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_aptx_hd_caps.channelMode,
-              sink_info_cie.channelMode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_aptx_hd_source_caps.channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
@@ -861,17 +864,17 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Set the rest of the fields as bit-wise AND operation
   //
   result_config_cie.acl_sprint_reserved0 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved0 &
-      sink_info_cie.acl_sprint_reserved0;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved0 &
+      peer_info_cie.acl_sprint_reserved0;
   result_config_cie.acl_sprint_reserved1 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved1 &
-      sink_info_cie.acl_sprint_reserved1;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved1 &
+      peer_info_cie.acl_sprint_reserved1;
   result_config_cie.acl_sprint_reserved2 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved2 &
-      sink_info_cie.acl_sprint_reserved2;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved2 &
+      peer_info_cie.acl_sprint_reserved2;
   result_config_cie.acl_sprint_reserved3 =
-      a2dp_aptx_hd_caps.acl_sprint_reserved3 &
-      sink_info_cie.acl_sprint_reserved3;
+      a2dp_aptx_hd_source_caps.acl_sprint_reserved3 &
+      peer_info_cie.acl_sprint_reserved3;
 
   if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
                            p_result_codec_config) != A2DP_SUCCESS) {
@@ -893,10 +896,10 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Create a local copy of the peer codec capability/config, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                   ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                   ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -919,3 +922,65 @@ fail:
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+bool A2dpCodecConfigAptxHd::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_APTX_HD_CIE peer_info_cie;
+  uint8_t sampleRate;
+  uint8_t channelMode;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoAptxHd(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = a2dp_aptx_hd_source_caps.sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      a2dp_aptx_hd_source_caps.bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode =
+      a2dp_aptx_hd_source_caps.channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                                ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
diff --git a/system/stack/a2dp/a2dp_vendor_ldac.cc b/system/stack/a2dp/a2dp_vendor_ldac.cc
index 5eb0c7d8423..266db81a897 100644
--- a/system/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/system/stack/a2dp/a2dp_vendor_ldac.cc
@@ -48,7 +48,7 @@ typedef struct {
 } tA2DP_LDAC_CIE;
 
 /* LDAC Source codec capabilities */
-static const tA2DP_LDAC_CIE a2dp_ldac_caps = {
+static const tA2DP_LDAC_CIE a2dp_ldac_source_caps = {
     A2DP_LDAC_VENDOR_ID,  // vendorId
     A2DP_LDAC_CODEC_ID,   // codecId
     // sampleRate
@@ -501,7 +501,7 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(
 const char* A2DP_VendorCodecIndexStrLdac(void) { return "LDAC"; }
 
 bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) {
-  if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_caps,
+  if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_source_caps,
                          p_cfg->codec_info) != A2DP_SUCCESS) {
     return false;
   }
@@ -547,32 +547,33 @@ A2dpCodecConfigLdac::A2dpCodecConfigLdac(
     : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC",
                       codec_priority) {
   // Compute the local capability
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
   }
-  if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+  if (a2dp_ldac_source_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
   }
-  codec_local_capability_.bits_per_sample = a2dp_ldac_caps.bits_per_sample;
-  if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+  codec_local_capability_.bits_per_sample =
+      a2dp_ldac_source_caps.bits_per_sample;
+  if (a2dp_ldac_source_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
   }
-  if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+  if (a2dp_ldac_source_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
-  if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+  if (a2dp_ldac_source_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
     codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
   }
 }
@@ -825,7 +826,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
                                          bool is_capability,
                                          uint8_t* p_result_codec_config) {
   std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
-  tA2DP_LDAC_CIE sink_info_cie;
+  tA2DP_LDAC_CIE peer_info_cie;
   tA2DP_LDAC_CIE result_config_cie;
   uint8_t channelMode;
   uint8_t sampleRate;
@@ -848,9 +849,9 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
          sizeof(ota_codec_peer_config_));
 
   tA2DP_STATUS status =
-      A2DP_ParseInfoLdac(&sink_info_cie, p_peer_codec_info, is_capability);
+      A2DP_ParseInfoLdac(&peer_info_cie, p_peer_codec_info, is_capability);
   if (status != A2DP_SUCCESS) {
-    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
               __func__, status);
     goto fail;
   }
@@ -859,13 +860,13 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Build the preferred configuration
   //
   memset(&result_config_cie, 0, sizeof(result_config_cie));
-  result_config_cie.vendorId = a2dp_ldac_caps.vendorId;
-  result_config_cie.codecId = a2dp_ldac_caps.codecId;
+  result_config_cie.vendorId = a2dp_ldac_source_caps.vendorId;
+  result_config_cie.codecId = a2dp_ldac_source_caps.codecId;
 
   //
   // Select the sample frequency
   //
-  sampleRate = a2dp_ldac_caps.sampleRate & sink_info_cie.sampleRate;
+  sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
   codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
   switch (codec_user_config_.sample_rate) {
     case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
@@ -969,7 +970,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - try the default config
     if (select_best_sample_rate(
-            a2dp_ldac_default_config.sampleRate & sink_info_cie.sampleRate,
+            a2dp_ldac_default_config.sampleRate & peer_info_cie.sampleRate,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -982,9 +983,10 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   } while (false);
   if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match sample frequency: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_ldac_caps.sampleRate, sink_info_cie.sampleRate);
+              "%s: cannot match sample frequency: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_ldac_source_caps.sampleRate,
+              peer_info_cie.sampleRate);
     goto fail;
   }
 
@@ -993,7 +995,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   //
   // NOTE: this information is NOT included in the LDAC A2DP codec description
   // that is sent OTA.
-  bits_per_sample = a2dp_ldac_caps.bits_per_sample;
+  bits_per_sample = a2dp_ldac_source_caps.bits_per_sample;
   codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
   switch (codec_user_config_.bits_per_sample) {
     case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
@@ -1028,7 +1030,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   do {
     // Compute the selectable capability
     codec_selectable_capability_.bits_per_sample =
-        a2dp_ldac_caps.bits_per_sample;
+        a2dp_ldac_source_caps.bits_per_sample;
 
     if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
       break;
@@ -1038,7 +1040,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - the the codec audio config
     if (select_audio_bits_per_sample(&codec_audio_config_,
-                                     a2dp_ldac_caps.bits_per_sample,
+                                     a2dp_ldac_source_caps.bits_per_sample,
                                      &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1050,7 +1052,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
     }
 
     // No user preference - use the best match
-    if (select_best_bits_per_sample(a2dp_ldac_caps.bits_per_sample,
+    if (select_best_bits_per_sample(a2dp_ldac_source_caps.bits_per_sample,
                                     &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1067,7 +1069,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   //
   // Select the channel mode
   //
-  channelMode = a2dp_ldac_caps.channelMode & sink_info_cie.channelMode;
+  channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
   codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
   switch (codec_user_config_.channel_mode) {
     case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
@@ -1131,7 +1133,7 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
 
     // No user preference - try the default config
     if (select_best_channel_mode(
-            a2dp_ldac_default_config.channelMode & sink_info_cie.channelMode,
+            a2dp_ldac_default_config.channelMode & peer_info_cie.channelMode,
             &result_config_cie, &codec_config_)) {
       break;
     }
@@ -1144,9 +1146,10 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   } while (false);
   if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
     LOG_ERROR(LOG_TAG,
-              "%s: cannot match channel mode: source caps = 0x%x "
-              "sink info = 0x%x",
-              __func__, a2dp_ldac_caps.channelMode, sink_info_cie.channelMode);
+              "%s: cannot match channel mode: local caps = 0x%x "
+              "peer info = 0x%x",
+              __func__, a2dp_ldac_source_caps.channelMode,
+              peer_info_cie.channelMode);
     goto fail;
   }
 
@@ -1170,10 +1173,10 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
   // Create a local copy of the peer codec capability, and the
   // result codec config.
   if (is_capability) {
-    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_capability_);
   } else {
-    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+    status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
                                 ota_codec_peer_config_);
   }
   CHECK(status == A2DP_SUCCESS);
@@ -1196,3 +1199,84 @@ fail:
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+bool A2dpCodecConfigLdac::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_LDAC_CIE peer_info_cie;
+  uint8_t channelMode;
+  uint8_t sampleRate;
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoLdac(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = a2dp_ldac_source_caps.sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+  }
+  if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+    codec_selectable_capability_.sample_rate |=
+        BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+  }
+
+  // Compute the selectable capability - bits per sample
+  codec_selectable_capability_.bits_per_sample =
+      a2dp_ldac_source_caps.bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = a2dp_ldac_source_caps.channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+  if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                              ota_codec_peer_capability_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  return false;
+}
diff --git a/system/stack/include/a2dp_aac.h b/system/stack/include/a2dp_aac.h
index 6b0be673893..45849669bcc 100644
--- a/system/stack/include/a2dp_aac.h
+++ b/system/stack/include/a2dp_aac.h
@@ -35,6 +35,8 @@ class A2dpCodecConfigAacBase : public A2dpCodecConfig {
         is_source_(is_source) {}
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool is_source_;  // True if local is Source
diff --git a/system/stack/include/a2dp_codec_api.h b/system/stack/include/a2dp_codec_api.h
index 40742bf7a3b..38a2089731f 100644
--- a/system/stack/include/a2dp_codec_api.h
+++ b/system/stack/include/a2dp_codec_api.h
@@ -191,6 +191,12 @@ class A2dpCodecConfig {
       bool* p_restart_input, bool* p_restart_output,
       bool* p_config_updated) = 0;
 
+  // Sets the codec capabilities for a peer.
+  // |p_peer_codec_capabiltities| is the peer codec capabilities to set.
+  // Returns true on success, otherwise false.
+  virtual bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) = 0;
+
   // Constructor where |codec_index| is the unique index that identifies the
   // codec. The user-friendly name is |name|.
   // The default codec priority is |codec_priority|. If the value is
@@ -414,6 +420,16 @@ class A2dpCodecs {
                          uint8_t* p_result_codec_config, bool* p_restart_input,
                          bool* p_restart_output, bool* p_config_updated);
 
+  // Sets the codec capabilities for a Sink peer.
+  // |p_peer_codec_capabiltities| is the peer codec capabilities to set.
+  // Returns true on success, otherwise false.
+  bool setPeerSinkCodecCapabilities(const uint8_t* p_peer_codec_capabilities);
+
+  // Sets the codec capabilities for a Source peer.
+  // |p_peer_codec_capabiltities| is the peer codec capabilities to set.
+  // Returns true on success, otherwise false.
+  bool setPeerSourceCodecCapabilities(const uint8_t* p_peer_codec_capabilities);
+
   // Gets the current codec configuration and the capabilities of
   // all configured codecs.
   // The current codec configuration is stored in |p_codec_config|.
diff --git a/system/stack/include/a2dp_sbc.h b/system/stack/include/a2dp_sbc.h
index ad37d452eb0..6f601b49a71 100644
--- a/system/stack/include/a2dp_sbc.h
+++ b/system/stack/include/a2dp_sbc.h
@@ -35,6 +35,8 @@ class A2dpCodecConfigSbcBase : public A2dpCodecConfig {
         is_source_(is_source) {}
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool is_source_;  // True if local is Source
diff --git a/system/stack/include/a2dp_vendor_aptx.h b/system/stack/include/a2dp_vendor_aptx.h
index 516814ea9ae..bc1ab56c2b0 100644
--- a/system/stack/include/a2dp_vendor_aptx.h
+++ b/system/stack/include/a2dp_vendor_aptx.h
@@ -34,6 +34,8 @@ class A2dpCodecConfigAptx : public A2dpCodecConfig {
   period_ms_t encoderIntervalMs() const override;
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
diff --git a/system/stack/include/a2dp_vendor_aptx_hd.h b/system/stack/include/a2dp_vendor_aptx_hd.h
index b343fd1fd6a..1276097f082 100644
--- a/system/stack/include/a2dp_vendor_aptx_hd.h
+++ b/system/stack/include/a2dp_vendor_aptx_hd.h
@@ -34,6 +34,8 @@ class A2dpCodecConfigAptxHd : public A2dpCodecConfig {
   period_ms_t encoderIntervalMs() const override;
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
diff --git a/system/stack/include/a2dp_vendor_ldac.h b/system/stack/include/a2dp_vendor_ldac.h
index 3d3f81c194d..3f8c3b58cc4 100644
--- a/system/stack/include/a2dp_vendor_ldac.h
+++ b/system/stack/include/a2dp_vendor_ldac.h
@@ -34,6 +34,8 @@ class A2dpCodecConfigLdac : public A2dpCodecConfig {
   period_ms_t encoderIntervalMs() const override;
   bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
                       uint8_t* p_result_codec_config) override;
+  bool setPeerCodecCapabilities(
+      const uint8_t* p_peer_codec_capabilities) override;
 
  private:
   bool useRtpHeaderMarkerBit() const override;
-- 
GitLab