From a00df11d9881f6a19e510a652445cbe320d83717 Mon Sep 17 00:00:00 2001
From: Omer Osman <omerosman@google.com>
Date: Mon, 8 Aug 2022 04:06:09 +0000
Subject: [PATCH] Add support for Opus over A2DP

This CL provides support for IETF RFC 2012-6716 Opus as a BT A2DP codec
for source or sink devices to the AOSP BT stack. During AVDTP handshake
for A2DP, codec capabilities are negotiated between the source and sink
devices, and the connection is established accordingly. The CL provides
support for Opus codec selection through Developer Options.

The Opus codec provides a highly optimized perceptual coding
implementation, with the following core features:

* Hybrid, Music (CELT) and Speech (SILK) modes
* Scalable Bitrate from 6 - 510 kbps
* Framesizes from 2.5 - 60ms
* Support for Packet Loss Concealment
* High efficiency coding with 3 byte frames to encode silence

The core function calls for the codec are:

opus_encode (OpusEncoder *st,
            const opus_int16 *pcm,
            int frame_size,
            unsigned char *data,
            opus_int32 max_data_bytes)

opus_decode (OpusDecoder *st,
            const unsigned char *data,
            opus_int32 len,
            opus_int16 *pcm,
            int frame_size,
            int decode_fec)

The majority of this CL implements the addition of the vendor codec in
the A2DP stack, interfacing of the audio through the A2DP HAL, and codec
capability negotiation over AVDTP.

Bug: 226441860
Test: atest net_test_stack:StackA2dpTest and bds-dev sink
Tag: #feature
Ignore-AOSP-First: TM QPR1 Feature
Change-Id: I05ecf07ab01f8045166b3d2da60fc2315c743cd2
---
 system/audio_hal_interface/fuzzer/Android.bp  |    1 +
 system/btif/Android.bp                        |    1 +
 system/build/Android.bp                       |    1 +
 system/gd/rust/topshim/facade/Android.bp      |    1 +
 system/service/Android.bp                     |    2 +
 system/stack/Android.bp                       |    5 +
 system/stack/a2dp/a2dp_codec_config.cc        |   12 +-
 system/stack/a2dp/a2dp_vendor.cc              |  128 +-
 system/stack/a2dp/a2dp_vendor_opus.cc         | 1332 +++++++++++++++++
 system/stack/a2dp/a2dp_vendor_opus_decoder.cc |  159 ++
 system/stack/a2dp/a2dp_vendor_opus_encoder.cc |  532 +++++++
 system/stack/include/a2dp_error_codes.h       |    3 +
 system/stack/include/a2dp_vendor_opus.h       |  255 ++++
 .../include/a2dp_vendor_opus_constants.h      |   66 +
 .../stack/include/a2dp_vendor_opus_decoder.h  |   45 +
 .../stack/include/a2dp_vendor_opus_encoder.h  |   59 +
 system/stack/test/fuzzers/Android.bp          |    1 +
 system/stack/test/stack_a2dp_test.cc          |  125 +-
 system/test/headless/Android.bp               |    1 +
 system/test/suite/Android.bp                  |    1 +
 20 files changed, 2720 insertions(+), 10 deletions(-)
 create mode 100644 system/stack/a2dp/a2dp_vendor_opus.cc
 create mode 100644 system/stack/a2dp/a2dp_vendor_opus_decoder.cc
 create mode 100644 system/stack/a2dp/a2dp_vendor_opus_encoder.cc
 create mode 100644 system/stack/include/a2dp_vendor_opus.h
 create mode 100644 system/stack/include/a2dp_vendor_opus_constants.h
 create mode 100644 system/stack/include/a2dp_vendor_opus_decoder.h
 create mode 100644 system/stack/include/a2dp_vendor_opus_encoder.h

diff --git a/system/audio_hal_interface/fuzzer/Android.bp b/system/audio_hal_interface/fuzzer/Android.bp
index ac74f1382fc..844fdd35846 100644
--- a/system/audio_hal_interface/fuzzer/Android.bp
+++ b/system/audio_hal_interface/fuzzer/Android.bp
@@ -72,6 +72,7 @@ cc_defaults {
         "libudrv-uipc",
         "libbt-common",
         "liblc3",
+        "libopus",
         "libstatslog_bt",
         "libvndksupport",
         "libprocessgroup",
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index 079d12cc04e..0a43f060177 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -238,6 +238,7 @@ cc_test {
         "libFraunhoferAAC",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libosi",
         "libudrv-uipc",
    ],
diff --git a/system/build/Android.bp b/system/build/Android.bp
index 9a0c996a7d1..79f7d65632e 100644
--- a/system/build/Android.bp
+++ b/system/build/Android.bp
@@ -207,6 +207,7 @@ fluoride_defaults {
         "libFraunhoferAAC",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libprotobuf-cpp-lite",
         "libstatslog_bt",
         "libudrv-uipc",
diff --git a/system/gd/rust/topshim/facade/Android.bp b/system/gd/rust/topshim/facade/Android.bp
index 5d2b06b2ca7..058b781b3bc 100644
--- a/system/gd/rust/topshim/facade/Android.bp
+++ b/system/gd/rust/topshim/facade/Android.bp
@@ -55,6 +55,7 @@ rust_binary_host {
         "libFraunhoferAAC",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libudrv-uipc",
         "libbluetooth_gd", // Gabeldorsche
         "libbluetooth-dumpsys",
diff --git a/system/service/Android.bp b/system/service/Android.bp
index 91dcff058dd..560ab2b8330 100644
--- a/system/service/Android.bp
+++ b/system/service/Android.bp
@@ -119,6 +119,7 @@ cc_binary {
         "libFraunhoferAAC",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libosi",
         "libudrv-uipc",
     ],
@@ -202,6 +203,7 @@ cc_test {
         "libFraunhoferAAC",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libosi",
         "libudrv-uipc",
     ],
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index 8d1b8e54472..94e0f4ea80f 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -55,6 +55,7 @@ cc_library_static {
         "external/aac/libSYS/include",
         "external/libldac/inc",
         "external/libldac/abr/inc",
+        "external/libopus/include",
         "packages/modules/Bluetooth/system",
         "packages/modules/Bluetooth/system/gd",
         "packages/modules/Bluetooth/system/vnd/include",
@@ -85,6 +86,9 @@ cc_library_static {
         "a2dp/a2dp_vendor_ldac.cc",
         "a2dp/a2dp_vendor_ldac_decoder.cc",
         "a2dp/a2dp_vendor_ldac_encoder.cc",
+        "a2dp/a2dp_vendor_opus.cc",
+        "a2dp/a2dp_vendor_opus_encoder.cc",
+        "a2dp/a2dp_vendor_opus_decoder.cc",
         "avct/avct_api.cc",
         "avct/avct_bcb_act.cc",
         "avct/avct_ccb.cc",
@@ -268,6 +272,7 @@ cc_test {
         "libbtdevice",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libosi",
         "libudrv-uipc",
         "libbt-protos-lite",
diff --git a/system/stack/a2dp/a2dp_codec_config.cc b/system/stack/a2dp/a2dp_codec_config.cc
index 52e0f6fcb19..b7b970fbe48 100644
--- a/system/stack/a2dp/a2dp_codec_config.cc
+++ b/system/stack/a2dp/a2dp_codec_config.cc
@@ -33,6 +33,7 @@
 #include "a2dp_vendor_aptx.h"
 #include "a2dp_vendor_aptx_hd.h"
 #include "a2dp_vendor_ldac.h"
+#include "a2dp_vendor_opus.h"
 #endif
 
 #include "bta/av/bta_av_int.h"
@@ -111,7 +112,7 @@ void A2dpCodecConfig::setDefaultCodecPriority() {
 A2dpCodecConfig* A2dpCodecConfig::createCodec(
     btav_a2dp_codec_index_t codec_index,
     btav_a2dp_codec_priority_t codec_priority) {
-  LOG_INFO("%s: codec %s", __func__, A2DP_CodecIndexStr(codec_index));
+  LOG_INFO("%s", A2DP_CodecIndexStr(codec_index));
 
   A2dpCodecConfig* codec_config = nullptr;
   switch (codec_index) {
@@ -140,6 +141,12 @@ A2dpCodecConfig* A2dpCodecConfig::createCodec(
     case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
       codec_config = new A2dpCodecConfigLdacSink(codec_priority);
       break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
+      codec_config = new A2dpCodecConfigOpusSource(codec_priority);
+      break;
+    case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
+      codec_config = new A2dpCodecConfigOpusSink(codec_priority);
+      break;
 #endif
     case BTAV_A2DP_CODEC_INDEX_MAX:
     default:
@@ -586,6 +593,9 @@ bool A2dpCodecs::init() {
       } else if (strcmp(tok, "ldac") == 0) {
         LOG_INFO("%s: LDAC offload supported", __func__);
         offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC] = true;
+      } else if (strcmp(tok, "opus") == 0) {
+        LOG_INFO("%s: Opus offload supported", __func__);
+        offload_codec_support[BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS] = true;
 #endif
       }
       tok = strtok_r(NULL, "-", &tmp_token);
diff --git a/system/stack/a2dp/a2dp_vendor.cc b/system/stack/a2dp/a2dp_vendor.cc
index 30dc2069f89..cde70c1b598 100644
--- a/system/stack/a2dp/a2dp_vendor.cc
+++ b/system/stack/a2dp/a2dp_vendor.cc
@@ -25,6 +25,7 @@
 #include "a2dp_vendor_aptx.h"
 #include "a2dp_vendor_aptx_hd.h"
 #include "a2dp_vendor_ldac.h"
+#include "a2dp_vendor_opus.h"
 #include "bt_target.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
@@ -51,6 +52,11 @@ bool A2DP_IsVendorSourceCodecValid(const uint8_t* p_codec_info) {
     return A2DP_IsVendorSourceCodecValidLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_IsVendorSourceCodecValidOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return false;
@@ -68,6 +74,11 @@ bool A2DP_IsVendorSinkCodecValid(const uint8_t* p_codec_info) {
     return A2DP_IsVendorSinkCodecValidLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_IsVendorSinkCodecValidOpus(p_codec_info);
+  }
+
   return false;
 }
 
@@ -83,6 +94,11 @@ bool A2DP_IsVendorPeerSourceCodecValid(const uint8_t* p_codec_info) {
     return A2DP_IsVendorPeerSourceCodecValidLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_IsVendorPeerSourceCodecValidOpus(p_codec_info);
+  }
+
   return false;
 }
 
@@ -107,6 +123,11 @@ bool A2DP_IsVendorPeerSinkCodecValid(const uint8_t* p_codec_info) {
     return A2DP_IsVendorPeerSinkCodecValidLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_IsVendorPeerSinkCodecValidOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return false;
@@ -124,6 +145,11 @@ bool A2DP_IsVendorSinkCodecSupported(const uint8_t* p_codec_info) {
     return A2DP_IsVendorSinkCodecSupportedLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_IsVendorSinkCodecSupportedOpus(p_codec_info);
+  }
+
   return false;
 }
 
@@ -139,6 +165,11 @@ bool A2DP_IsVendorPeerSourceCodecSupported(const uint8_t* p_codec_info) {
     return A2DP_IsPeerSourceCodecSupportedLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_IsPeerSourceCodecSupportedOpus(p_codec_info);
+  }
+
   return false;
 }
 
@@ -185,6 +216,12 @@ bool A2DP_VendorUsesRtpHeader(bool content_protection_enabled,
                                         p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorUsesRtpHeaderOpus(content_protection_enabled,
+                                        p_codec_info);
+  }
+
   // Add checks based on <content_protection_enabled, vendor_id, codec_id>
 
   return true;
@@ -211,6 +248,11 @@ const char* A2DP_VendorCodecName(const uint8_t* p_codec_info) {
     return A2DP_VendorCodecNameLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorCodecNameOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return "UNKNOWN VENDOR CODEC";
@@ -250,6 +292,11 @@ bool A2DP_VendorCodecTypeEquals(const uint8_t* p_codec_info_a,
     return A2DP_VendorCodecTypeEqualsLdac(p_codec_info_a, p_codec_info_b);
   }
 
+  // Check for Opus
+  if (vendor_id_a == A2DP_OPUS_VENDOR_ID && codec_id_a == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorCodecTypeEqualsOpus(p_codec_info_a, p_codec_info_b);
+  }
+
   // OPTIONAL: Add extra vendor-specific checks based on the
   // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
 
@@ -290,6 +337,11 @@ bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
     return A2DP_VendorCodecEqualsLdac(p_codec_info_a, p_codec_info_b);
   }
 
+  // Check for Opus
+  if (vendor_id_a == A2DP_OPUS_VENDOR_ID && codec_id_a == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorCodecEqualsOpus(p_codec_info_a, p_codec_info_b);
+  }
+
   // Add extra vendor-specific checks based on the
   // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
 
@@ -317,6 +369,11 @@ int A2DP_VendorGetBitRate(const uint8_t* p_codec_info) {
     return A2DP_VendorGetBitRateLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetBitRateOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return -1;
@@ -343,6 +400,11 @@ int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info) {
     return A2DP_VendorGetTrackSampleRateLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetTrackSampleRateOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return -1;
@@ -369,6 +431,11 @@ int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info) {
     return A2DP_VendorGetTrackBitsPerSampleLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetTrackBitsPerSampleOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return -1;
@@ -395,6 +462,11 @@ int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info) {
     return A2DP_VendorGetTrackChannelCountLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetTrackChannelCountOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return -1;
@@ -412,6 +484,11 @@ int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info) {
     return A2DP_VendorGetSinkTrackChannelTypeLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetSinkTrackChannelTypeOpus(p_codec_info);
+  }
+
   return -1;
 }
 
@@ -439,6 +516,11 @@ bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
     return A2DP_VendorGetPacketTimestampLdac(p_codec_info, p_data, p_timestamp);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetPacketTimestampOpus(p_codec_info, p_data, p_timestamp);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return false;
@@ -469,6 +551,12 @@ bool A2DP_VendorBuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
                                            frames_per_packet);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorBuildCodecHeaderOpus(p_codec_info, p_buf,
+                                           frames_per_packet);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return false;
@@ -496,6 +584,11 @@ const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
     return A2DP_VendorGetEncoderInterfaceLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetEncoderInterfaceOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return NULL;
@@ -514,6 +607,11 @@ const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
     return A2DP_VendorGetDecoderInterfaceLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorGetDecoderInterfaceOpus(p_codec_info);
+  }
+
   return NULL;
 }
 
@@ -538,6 +636,11 @@ bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info) {
     return A2DP_VendorAdjustCodecLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorAdjustCodecOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return false;
@@ -565,6 +668,11 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndex(
     return A2DP_VendorSourceCodecIndexLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorSourceCodecIndexOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return BTAV_A2DP_CODEC_INDEX_MAX;
@@ -582,6 +690,11 @@ btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndex(const uint8_t* p_codec_info) {
     return A2DP_VendorSinkCodecIndexLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorSinkCodecIndexOpus(p_codec_info);
+  }
+
   return BTAV_A2DP_CODEC_INDEX_MAX;
 }
 
@@ -604,11 +717,9 @@ const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
       return "LC3 not implemented";
     case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
-      // TODO(b/226441860): in-progress
-      return "Opus";
+      return A2DP_VendorCodecIndexStrOpus();
     case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
-      // TODO(b/226441860): in-progress
-      return "Opus SINK";
+      return A2DP_VendorCodecIndexStrOpusSink();
     // Add a switch statement for each vendor-specific codec
     case BTAV_A2DP_CODEC_INDEX_MAX:
       break;
@@ -637,9 +748,9 @@ bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
     case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
       break;  // not implemented
     case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
-      // TODO(b/226441860): in-progress
+      return A2DP_VendorInitCodecConfigOpus(p_cfg);
     case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
-      // TODO(b/226441860): in-progress
+      return A2DP_VendorInitCodecConfigOpusSink(p_cfg);
     // Add a switch statement for each vendor-specific codec
     case BTAV_A2DP_CODEC_INDEX_MAX:
       break;
@@ -669,6 +780,11 @@ std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info) {
     return A2DP_VendorCodecInfoStringLdac(p_codec_info);
   }
 
+  // Check for Opus
+  if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
+    return A2DP_VendorCodecInfoStringOpus(p_codec_info);
+  }
+
   // Add checks based on <vendor_id, codec_id>
 
   return "Unsupported codec vendor_id: " + loghex(vendor_id) +
diff --git a/system/stack/a2dp/a2dp_vendor_opus.cc b/system/stack/a2dp/a2dp_vendor_opus.cc
new file mode 100644
index 00000000000..8390035b0a4
--- /dev/null
+++ b/system/stack/a2dp/a2dp_vendor_opus.cc
@@ -0,0 +1,1332 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ *
+ *  Utility functions to help build and parse the Opus Codec Information
+ *  Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_vendor_opus"
+
+#include "a2dp_vendor_opus.h"
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_opus_decoder.h"
+#include "a2dp_vendor_opus_encoder.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btif_av_co.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+// data type for the Opus Codec Information Element */
+// NOTE: bits_per_sample and frameSize for Opus encoder initialization.
+typedef struct {
+  uint32_t vendorId;
+  uint16_t codecId;    /* Codec ID for Opus */
+  uint8_t sampleRate;  /* Sampling Frequency */
+  uint8_t channelMode; /* STEREO/DUAL/MONO */
+  btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+  uint8_t future1; /* codec_specific_1 framesize */
+  uint8_t future2; /* codec_specific_2 */
+  uint8_t future3; /* codec_specific_3 */
+  uint8_t future4; /* codec_specific_4 */
+} tA2DP_OPUS_CIE;
+
+/* Opus Source codec capabilities */
+static const tA2DP_OPUS_CIE a2dp_opus_source_caps = {
+    A2DP_OPUS_VENDOR_ID,  // vendorId
+    A2DP_OPUS_CODEC_ID,   // codecId
+    // sampleRate
+    (A2DP_OPUS_SAMPLING_FREQ_48000),
+    // channelMode
+    (A2DP_OPUS_CHANNEL_MODE_STEREO),
+    // bits_per_sample
+    (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16),
+    // future 1 frameSize
+    (A2DP_OPUS_20MS_FRAMESIZE),
+    // future 2
+    0x00,
+    // future 3
+    0x00,
+    // future 4
+    0x00};
+
+/* Opus Sink codec capabilities */
+static const tA2DP_OPUS_CIE a2dp_opus_sink_caps = {
+    A2DP_OPUS_VENDOR_ID,  // vendorId
+    A2DP_OPUS_CODEC_ID,   // codecId
+    // sampleRate
+    (A2DP_OPUS_SAMPLING_FREQ_48000),
+    // channelMode
+    (A2DP_OPUS_CHANNEL_MODE_STEREO),
+    // bits_per_sample
+    (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16),
+    // future 1 frameSize
+    (A2DP_OPUS_20MS_FRAMESIZE),
+    // future 2
+    0x00,
+    // future 3
+    0x00,
+    // future 4
+    0x00};
+
+/* Default Opus codec configuration */
+static const tA2DP_OPUS_CIE a2dp_opus_default_config = {
+    A2DP_OPUS_VENDOR_ID,                 // vendorId
+    A2DP_OPUS_CODEC_ID,                  // codecId
+    A2DP_OPUS_SAMPLING_FREQ_48000,       // sampleRate
+    A2DP_OPUS_CHANNEL_MODE_STEREO,       // channelMode
+    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16,  // bits_per_sample
+    A2DP_OPUS_20MS_FRAMESIZE,            // frameSize
+    0x00,                                // future 2
+    0x00,                                // future 3
+    0x00                                 // future 4
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_opus = {
+    a2dp_vendor_opus_encoder_init,
+    a2dp_vendor_opus_encoder_cleanup,
+    a2dp_vendor_opus_feeding_reset,
+    a2dp_vendor_opus_feeding_flush,
+    a2dp_vendor_opus_get_encoder_interval_ms,
+    a2dp_vendor_opus_get_effective_frame_size,
+    a2dp_vendor_opus_send_frames,
+    a2dp_vendor_opus_set_transmit_queue_length};
+
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_opus = {
+    a2dp_vendor_opus_decoder_init,          a2dp_vendor_opus_decoder_cleanup,
+    a2dp_vendor_opus_decoder_decode_packet, a2dp_vendor_opus_decoder_start,
+    a2dp_vendor_opus_decoder_suspend,       a2dp_vendor_opus_decoder_configure,
+};
+
+UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityOpus(
+    const tA2DP_OPUS_CIE* p_cap, const uint8_t* p_codec_info,
+    bool is_peer_codec_info);
+
+// Builds the Opus Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the Opus Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoOpus(uint8_t media_type,
+                                       const tA2DP_OPUS_CIE* p_ie,
+                                       uint8_t* p_result) {
+  if (p_ie == NULL || p_result == NULL) {
+    LOG_ERROR("invalid information element");
+    return A2DP_INVALID_PARAMS;
+  }
+
+  *p_result++ = A2DP_OPUS_CODEC_LEN;
+  *p_result++ = (media_type << 4);
+  *p_result++ = A2DP_MEDIA_CT_NON_A2DP;
+
+  // Vendor ID and Codec ID
+  *p_result++ = (uint8_t)(p_ie->vendorId & 0x000000FF);
+  *p_result++ = (uint8_t)((p_ie->vendorId & 0x0000FF00) >> 8);
+  *p_result++ = (uint8_t)((p_ie->vendorId & 0x00FF0000) >> 16);
+  *p_result++ = (uint8_t)((p_ie->vendorId & 0xFF000000) >> 24);
+  *p_result++ = (uint8_t)(p_ie->codecId & 0x00FF);
+  *p_result++ = (uint8_t)((p_ie->codecId & 0xFF00) >> 8);
+
+  *p_result = 0;
+  *p_result |= (uint8_t)(p_ie->channelMode) & A2DP_OPUS_CHANNEL_MODE_MASK;
+  if ((*p_result & A2DP_OPUS_CHANNEL_MODE_MASK) == 0) {
+    LOG_ERROR("channelmode 0x%X setting failed", (p_ie->channelMode));
+    return A2DP_INVALID_PARAMS;
+  }
+
+  *p_result |= ((uint8_t)(p_ie->future1) & A2DP_OPUS_FRAMESIZE_MASK);
+  if ((*p_result & A2DP_OPUS_FRAMESIZE_MASK) == 0) {
+    LOG_ERROR("frameSize 0x%X setting failed", (p_ie->future1));
+    return A2DP_INVALID_PARAMS;
+  }
+
+  *p_result |= ((uint8_t)(p_ie->sampleRate) & A2DP_OPUS_SAMPLING_FREQ_MASK);
+  if ((*p_result & A2DP_OPUS_SAMPLING_FREQ_MASK) == 0) {
+    LOG_ERROR("samplerate 0x%X setting failed", (p_ie->sampleRate));
+    return A2DP_INVALID_PARAMS;
+  }
+
+  p_result++;
+
+  return A2DP_SUCCESS;
+}
+
+// Parses the Opus Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_capability| is true, the byte sequence is
+// codec capabilities, otherwise is codec configuration.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoOpus(tA2DP_OPUS_CIE* p_ie,
+                                       const uint8_t* p_codec_info,
+                                       bool is_capability) {
+  uint8_t losc;
+  uint8_t media_type;
+  tA2DP_CODEC_TYPE codec_type;
+
+  if (p_ie == NULL || p_codec_info == NULL) {
+    LOG_ERROR("unable to parse information element");
+    return A2DP_INVALID_PARAMS;
+  }
+
+  // Check the codec capability length
+  losc = *p_codec_info++;
+  if (losc != A2DP_OPUS_CODEC_LEN) {
+    LOG_ERROR("invalid codec ie length %d", losc);
+    return A2DP_WRONG_CODEC;
+  }
+
+  media_type = (*p_codec_info++) >> 4;
+  codec_type = *p_codec_info++;
+  /* Check the Media Type and Media Codec Type */
+  if (media_type != AVDT_MEDIA_TYPE_AUDIO ||
+      codec_type != A2DP_MEDIA_CT_NON_A2DP) {
+    LOG_ERROR("invalid codec");
+    return A2DP_WRONG_CODEC;
+  }
+
+  // Check the Vendor ID and Codec ID */
+  p_ie->vendorId = (*p_codec_info & 0x000000FF) |
+                   (*(p_codec_info + 1) << 8 & 0x0000FF00) |
+                   (*(p_codec_info + 2) << 16 & 0x00FF0000) |
+                   (*(p_codec_info + 3) << 24 & 0xFF000000);
+  p_codec_info += 4;
+  p_ie->codecId =
+      (*p_codec_info & 0x00FF) | (*(p_codec_info + 1) << 8 & 0xFF00);
+  p_codec_info += 2;
+  if (p_ie->vendorId != A2DP_OPUS_VENDOR_ID ||
+      p_ie->codecId != A2DP_OPUS_CODEC_ID) {
+    LOG_ERROR("wrong vendor or codec id");
+    return A2DP_WRONG_CODEC;
+  }
+
+  p_ie->channelMode = *p_codec_info & A2DP_OPUS_CHANNEL_MODE_MASK;
+  p_ie->future1 = *p_codec_info & A2DP_OPUS_FRAMESIZE_MASK;
+  p_ie->sampleRate = *p_codec_info & A2DP_OPUS_SAMPLING_FREQ_MASK;
+  p_ie->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+
+  if (is_capability) {
+    // NOTE: The checks here are very liberal. We should be using more
+    // pedantic checks specific to the SRC or SNK as specified in the spec.
+    if (A2DP_BitsSet(p_ie->sampleRate) == A2DP_SET_ZERO_BIT) {
+      LOG_ERROR("invalid sample rate 0x%X", p_ie->sampleRate);
+      return A2DP_BAD_SAMP_FREQ;
+    }
+    if (A2DP_BitsSet(p_ie->channelMode) == A2DP_SET_ZERO_BIT) {
+      LOG_ERROR("invalid channel mode");
+      return A2DP_BAD_CH_MODE;
+    }
+
+    return A2DP_SUCCESS;
+  }
+
+  if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT) {
+    LOG_ERROR("invalid sampling frequency 0x%X", p_ie->sampleRate);
+    return A2DP_BAD_SAMP_FREQ;
+  }
+  if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT) {
+    LOG_ERROR("invalid channel mode.");
+    return A2DP_BAD_CH_MODE;
+  }
+
+  return A2DP_SUCCESS;
+}
+
+// Build the Opus Media Payload Header.
+// |p_dst| points to the location where the header should be written to.
+// If |frag| is true, the media payload frame is fragmented.
+// |start| is true for the first packet of a fragmented frame.
+// |last| is true for the last packet of a fragmented frame.
+// If |frag| is false, |num| is the number of number of frames in the packet,
+// otherwise is the number of remaining fragments (including this one).
+static void A2DP_BuildMediaPayloadHeaderOpus(uint8_t* p_dst, bool frag,
+                                             bool start, bool last,
+                                             uint8_t num) {
+  if (p_dst == NULL) return;
+
+  *p_dst = 0;
+  if (frag) *p_dst |= A2DP_OPUS_HDR_F_MSK;
+  if (start) *p_dst |= A2DP_OPUS_HDR_S_MSK;
+  if (last) *p_dst |= A2DP_OPUS_HDR_L_MSK;
+  *p_dst |= (A2DP_OPUS_HDR_NUM_MSK & num);
+}
+
+bool A2DP_IsVendorSourceCodecValidOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorSinkCodecValidOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSourceCodecValidOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSinkCodecValidOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorSinkCodecSupportedOpus(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityOpus(&a2dp_opus_sink_caps, p_codec_info,
+                                             false) == A2DP_SUCCESS;
+}
+bool A2DP_IsPeerSourceCodecSupportedOpus(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityOpus(&a2dp_opus_sink_caps, p_codec_info,
+                                             true) == A2DP_SUCCESS;
+}
+
+// Checks whether A2DP Opus codec configuration matches with a device's codec
+// capabilities. |p_cap| is the Opus codec configuration. |p_codec_info| is
+// the device's codec capabilities.
+// If |is_capability| is true, the byte sequence is codec capabilities,
+// otherwise is codec configuration.
+// |p_codec_info| contains the codec capabilities for a peer device that
+// is acting as an A2DP source.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityOpus(
+    const tA2DP_OPUS_CIE* p_cap, const uint8_t* p_codec_info,
+    bool is_capability) {
+  tA2DP_STATUS status;
+  tA2DP_OPUS_CIE cfg_cie;
+
+  /* parse configuration */
+  status = A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, is_capability);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR("parsing failed %d", status);
+    return status;
+  }
+
+  /* verify that each parameter is in range */
+
+  LOG_VERBOSE("SAMPLING FREQ peer: 0x%x, capability 0x%x", cfg_cie.sampleRate,
+              p_cap->sampleRate);
+  LOG_VERBOSE("CH_MODE peer: 0x%x, capability 0x%x", cfg_cie.channelMode,
+              p_cap->channelMode);
+  LOG_VERBOSE("FRAMESIZE peer: 0x%x, capability 0x%x", cfg_cie.future1,
+              p_cap->future1);
+
+  /* sampling frequency */
+  if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) return A2DP_NS_SAMP_FREQ;
+
+  /* channel mode */
+  if ((cfg_cie.channelMode & p_cap->channelMode) == 0) return A2DP_NS_CH_MODE;
+
+  /* frameSize */
+  if ((cfg_cie.future1 & p_cap->future1) == 0) return A2DP_NS_FRAMESIZE;
+
+  return A2DP_SUCCESS;
+}
+
+bool A2DP_VendorUsesRtpHeaderOpus(UNUSED_ATTR bool content_protection_enabled,
+                                  UNUSED_ATTR const uint8_t* p_codec_info) {
+  return true;
+}
+
+const char* A2DP_VendorCodecNameOpus(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return "Opus";
+}
+
+bool A2DP_VendorCodecTypeEqualsOpus(const uint8_t* p_codec_info_a,
+                                    const uint8_t* p_codec_info_b) {
+  tA2DP_OPUS_CIE Opus_cie_a;
+  tA2DP_OPUS_CIE Opus_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoOpus(&Opus_cie_a, p_codec_info_a, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoOpus(&Opus_cie_b, p_codec_info_b, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return false;
+  }
+
+  return true;
+}
+
+bool A2DP_VendorCodecEqualsOpus(const uint8_t* p_codec_info_a,
+                                const uint8_t* p_codec_info_b) {
+  tA2DP_OPUS_CIE Opus_cie_a;
+  tA2DP_OPUS_CIE Opus_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoOpus(&Opus_cie_a, p_codec_info_a, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoOpus(&Opus_cie_b, p_codec_info_b, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return false;
+  }
+
+  return (Opus_cie_a.sampleRate == Opus_cie_b.sampleRate) &&
+         (Opus_cie_a.channelMode == Opus_cie_b.channelMode) &&
+         (Opus_cie_a.future1 == Opus_cie_b.future1);
+}
+
+int A2DP_VendorGetBitRateOpus(const uint8_t* p_codec_info) {
+  int channel_count = A2DP_VendorGetTrackChannelCountOpus(p_codec_info);
+  int framesize = A2DP_VendorGetFrameSizeOpus(p_codec_info);
+  int samplerate = A2DP_VendorGetTrackSampleRateOpus(p_codec_info);
+
+  // in milliseconds
+  switch ((framesize * 1000) / samplerate) {
+    case 20:
+      if (channel_count == 2) {
+        return 256000;
+      } else if (channel_count == 1) {
+        return 128000;
+      } else
+        return -1;
+    default:
+      return -1;
+  }
+}
+
+int A2DP_VendorGetTrackSampleRateOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE Opus_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return -1;
+  }
+
+  switch (Opus_cie.sampleRate) {
+    case A2DP_OPUS_SAMPLING_FREQ_48000:
+      return 48000;
+  }
+
+  return -1;
+}
+
+int A2DP_VendorGetTrackBitsPerSampleOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE Opus_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return -1;
+  }
+
+  switch (Opus_cie.bits_per_sample) {
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+      return 16;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      return 24;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      return 32;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+    default:
+      LOG_ERROR("Invalid bit depth setting");
+      return -1;
+  }
+}
+
+int A2DP_VendorGetTrackChannelCountOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE Opus_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return -1;
+  }
+
+  switch (Opus_cie.channelMode) {
+    case A2DP_OPUS_CHANNEL_MODE_MONO:
+      return 1;
+    case A2DP_OPUS_CHANNEL_MODE_STEREO:
+    case A2DP_OPUS_CHANNEL_MODE_DUAL_MONO:
+      return 2;
+    default:
+      LOG_ERROR("Invalid channel setting");
+  }
+
+  return -1;
+}
+
+int A2DP_VendorGetSinkTrackChannelTypeOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE Opus_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return -1;
+  }
+
+  switch (Opus_cie.channelMode) {
+    case A2DP_OPUS_CHANNEL_MODE_MONO:
+      return 1;
+    case A2DP_OPUS_CHANNEL_MODE_STEREO:
+      return 2;
+  }
+
+  return -1;
+}
+
+int A2DP_VendorGetChannelModeCodeOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE Opus_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return -1;
+  }
+
+  switch (Opus_cie.channelMode) {
+    case A2DP_OPUS_CHANNEL_MODE_MONO:
+    case A2DP_OPUS_CHANNEL_MODE_STEREO:
+      return Opus_cie.channelMode;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_VendorGetFrameSizeOpus(const uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE Opus_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR("cannot decode codec information: %d", a2dp_status);
+    return -1;
+  }
+  int samplerate = A2DP_VendorGetTrackSampleRateOpus(p_codec_info);
+
+  switch (Opus_cie.future1) {
+    case A2DP_OPUS_20MS_FRAMESIZE:
+      if (samplerate == 48000) {
+        return 960;
+      }
+  }
+
+  return -1;
+}
+
+bool A2DP_VendorGetPacketTimestampOpus(UNUSED_ATTR const uint8_t* p_codec_info,
+                                       const uint8_t* p_data,
+                                       uint32_t* p_timestamp) {
+  *p_timestamp = *(const uint32_t*)p_data;
+  return true;
+}
+
+bool A2DP_VendorBuildCodecHeaderOpus(UNUSED_ATTR const uint8_t* p_codec_info,
+                                     BT_HDR* p_buf,
+                                     uint16_t frames_per_packet) {
+  uint8_t* p;
+
+  p_buf->offset -= A2DP_OPUS_MPL_HDR_LEN;
+  p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+  p_buf->len += A2DP_OPUS_MPL_HDR_LEN;
+
+  A2DP_BuildMediaPayloadHeaderOpus(p, false, false, false,
+                                   (uint8_t)frames_per_packet);
+
+  return true;
+}
+
+std::string A2DP_VendorCodecInfoStringOpus(const uint8_t* p_codec_info) {
+  std::stringstream res;
+  std::string field;
+  tA2DP_STATUS a2dp_status;
+  tA2DP_OPUS_CIE Opus_cie;
+
+  a2dp_status = A2DP_ParseInfoOpus(&Opus_cie, p_codec_info, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    res << "A2DP_ParseInfoOpus fail: " << loghex(a2dp_status);
+    return res.str();
+  }
+
+  res << "\tname: Opus\n";
+
+  // Sample frequency
+  field.clear();
+  AppendField(&field, (Opus_cie.sampleRate == 0), "NONE");
+  AppendField(&field, (Opus_cie.sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000),
+              "48000");
+  res << "\tsamp_freq: " << field << " (" << loghex(Opus_cie.sampleRate)
+      << ")\n";
+
+  // Channel mode
+  field.clear();
+  AppendField(&field, (Opus_cie.channelMode == 0), "NONE");
+  AppendField(&field, (Opus_cie.channelMode & A2DP_OPUS_CHANNEL_MODE_MONO),
+              "Mono");
+  AppendField(&field, (Opus_cie.channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO),
+              "Stereo");
+  res << "\tch_mode: " << field << " (" << loghex(Opus_cie.channelMode)
+      << ")\n";
+
+  // Framesize
+  field.clear();
+  AppendField(&field, (Opus_cie.future1 == 0), "NONE");
+  AppendField(&field, (Opus_cie.future1 & A2DP_OPUS_20MS_FRAMESIZE), "20ms");
+  AppendField(&field, (Opus_cie.future1 & A2DP_OPUS_10MS_FRAMESIZE), "10ms");
+  res << "\tframesize: " << field << " (" << loghex(Opus_cie.future1) << ")\n";
+
+  return res.str();
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceOpus(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsVendorSourceCodecValidOpus(p_codec_info)) return NULL;
+
+  return &a2dp_encoder_interface_opus;
+}
+
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceOpus(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsVendorSinkCodecValidOpus(p_codec_info)) return NULL;
+
+  return &a2dp_decoder_interface_opus;
+}
+
+bool A2DP_VendorAdjustCodecOpus(uint8_t* p_codec_info) {
+  tA2DP_OPUS_CIE cfg_cie;
+
+  // Nothing to do: just verify the codec info is valid
+  if (A2DP_ParseInfoOpus(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+    return false;
+
+  return true;
+}
+
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexOpus(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS;
+}
+
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexOpus(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return BTAV_A2DP_CODEC_INDEX_SINK_OPUS;
+}
+
+const char* A2DP_VendorCodecIndexStrOpus(void) { return "Opus"; }
+
+const char* A2DP_VendorCodecIndexStrOpusSink(void) { return "Opus SINK"; }
+
+bool A2DP_VendorInitCodecConfigOpus(AvdtpSepConfig* p_cfg) {
+  if (A2DP_BuildInfoOpus(AVDT_MEDIA_TYPE_AUDIO, &a2dp_opus_source_caps,
+                         p_cfg->codec_info) != A2DP_SUCCESS) {
+    return false;
+  }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  /* Content protection info - support SCMS-T */
+  uint8_t* p = p_cfg->protect_info;
+  *p++ = AVDT_CP_LOSC;
+  UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+  p_cfg->num_protect = 1;
+#endif
+
+  return true;
+}
+
+bool A2DP_VendorInitCodecConfigOpusSink(AvdtpSepConfig* p_cfg) {
+  return A2DP_BuildInfoOpus(AVDT_MEDIA_TYPE_AUDIO, &a2dp_opus_sink_caps,
+                            p_cfg->codec_info) == A2DP_SUCCESS;
+}
+
+UNUSED_ATTR static void build_codec_config(const tA2DP_OPUS_CIE& config_cie,
+                                           btav_a2dp_codec_config_t* result) {
+  if (config_cie.sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000)
+    result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+
+  result->bits_per_sample = config_cie.bits_per_sample;
+
+  if (config_cie.channelMode & A2DP_OPUS_CHANNEL_MODE_MONO)
+    result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  if (config_cie.channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+    result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  if (config_cie.future1 & A2DP_OPUS_20MS_FRAMESIZE)
+    result->codec_specific_1 |= BTAV_A2DP_CODEC_FRAME_SIZE_20MS;
+  if (config_cie.future1 & A2DP_OPUS_10MS_FRAMESIZE)
+    result->codec_specific_1 |= BTAV_A2DP_CODEC_FRAME_SIZE_10MS;
+}
+
+A2dpCodecConfigOpusSource::A2dpCodecConfigOpusSource(
+    btav_a2dp_codec_priority_t codec_priority)
+    : A2dpCodecConfigOpusBase(BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS,
+                              A2DP_VendorCodecIndexStrOpus(), codec_priority,
+                              true) {
+  // Compute the local capability
+  if (a2dp_opus_source_caps.sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000) {
+    codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  }
+  codec_local_capability_.bits_per_sample =
+      a2dp_opus_source_caps.bits_per_sample;
+  if (a2dp_opus_source_caps.channelMode & A2DP_OPUS_CHANNEL_MODE_MONO) {
+    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (a2dp_opus_source_caps.channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+    codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+}
+
+A2dpCodecConfigOpusSource::~A2dpCodecConfigOpusSource() {}
+
+bool A2dpCodecConfigOpusSource::init() {
+  if (!isValid()) return false;
+
+  return true;
+}
+
+bool A2dpCodecConfigOpusSource::useRtpHeaderMarkerBit() const { return false; }
+
+//
+// Selects the best sample rate from |sampleRate|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_sample_rate(uint8_t sampleRate,
+                                    tA2DP_OPUS_CIE* p_result,
+                                    btav_a2dp_codec_config_t* p_codec_config) {
+  if (sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000) {
+    p_result->sampleRate = A2DP_OPUS_SAMPLING_FREQ_48000;
+    p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+    return true;
+  }
+  return false;
+}
+
+//
+// Selects the audio sample rate from |p_codec_audio_config|.
+// |sampleRate| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_sample_rate(
+    const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t sampleRate,
+    tA2DP_OPUS_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+  switch (p_codec_audio_config->sample_rate) {
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+      if (sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000) {
+        p_result->sampleRate = A2DP_OPUS_SAMPLING_FREQ_48000;
+        p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+      break;
+  }
+
+  return false;
+}
+
+//
+// Selects the best bits per sample from |bits_per_sample|.
+// |bits_per_sample| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_bits_per_sample(
+    btav_a2dp_codec_bits_per_sample_t bits_per_sample, tA2DP_OPUS_CIE* p_result,
+    btav_a2dp_codec_config_t* p_codec_config) {
+  if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+    p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+    p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+    return true;
+  }
+  if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+    p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+    p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+    return true;
+  }
+  if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+    p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+    p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+    return true;
+  }
+  return false;
+}
+
+//
+// Selects the audio bits per sample from |p_codec_audio_config|.
+// |bits_per_sample| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_bits_per_sample(
+    const btav_a2dp_codec_config_t* p_codec_audio_config,
+    btav_a2dp_codec_bits_per_sample_t bits_per_sample, tA2DP_OPUS_CIE* p_result,
+    btav_a2dp_codec_config_t* p_codec_config) {
+  switch (p_codec_audio_config->bits_per_sample) {
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+      if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+        p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+        p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+        p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+        p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+        p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+        p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+      break;
+  }
+  return false;
+}
+
+//
+// Selects the best channel mode from |channelMode|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_channel_mode(uint8_t channelMode,
+                                     tA2DP_OPUS_CIE* p_result,
+                                     btav_a2dp_codec_config_t* p_codec_config) {
+  if (channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+    p_result->channelMode = A2DP_OPUS_CHANNEL_MODE_STEREO;
+    p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+    return true;
+  }
+  if (channelMode & A2DP_OPUS_CHANNEL_MODE_MONO) {
+    p_result->channelMode = A2DP_OPUS_CHANNEL_MODE_MONO;
+    p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+    return true;
+  }
+  return false;
+}
+
+//
+// Selects the audio channel mode from |p_codec_audio_config|.
+// |channelMode| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_channel_mode(
+    const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t channelMode,
+    tA2DP_OPUS_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+  switch (p_codec_audio_config->channel_mode) {
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+      if (channelMode & A2DP_OPUS_CHANNEL_MODE_MONO) {
+        p_result->channelMode = A2DP_OPUS_CHANNEL_MODE_MONO;
+        p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+      if (channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+        p_result->channelMode = A2DP_OPUS_CHANNEL_MODE_STEREO;
+        p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+      break;
+  }
+
+  return false;
+}
+
+bool A2dpCodecConfigOpusBase::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_OPUS_CIE peer_info_cie;
+  tA2DP_OPUS_CIE result_config_cie;
+  uint8_t channelMode;
+  uint8_t sampleRate;
+  uint8_t frameSize;
+  btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+  const tA2DP_OPUS_CIE* p_a2dp_opus_caps =
+      (is_source_) ? &a2dp_opus_source_caps : &a2dp_opus_sink_caps;
+
+  btav_a2dp_codec_config_t device_codec_config_ = getCodecConfig();
+
+  LOG_INFO(
+      "AudioManager stream config %d sample rate %d bit depth %d channel "
+      "mode",
+      device_codec_config_.sample_rate, device_codec_config_.bits_per_sample,
+      device_codec_config_.channel_mode);
+
+  // Save the internal state
+  btav_a2dp_codec_config_t saved_codec_config = codec_config_;
+  btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
+  btav_a2dp_codec_config_t saved_codec_selectable_capability =
+      codec_selectable_capability_;
+  btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+  btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+  uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+  uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+  uint8_t saved_ota_codec_peer_config[AVDT_CODEC_SIZE];
+  memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+  memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+         sizeof(ota_codec_peer_capability_));
+  memcpy(saved_ota_codec_peer_config, ota_codec_peer_config_,
+         sizeof(ota_codec_peer_config_));
+
+  tA2DP_STATUS status =
+      A2DP_ParseInfoOpus(&peer_info_cie, p_peer_codec_info, is_capability);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR("can't parse peer's capabilities: error = %d", status);
+    goto fail;
+  }
+
+  //
+  // Build the preferred configuration
+  //
+  memset(&result_config_cie, 0, sizeof(result_config_cie));
+  result_config_cie.vendorId = p_a2dp_opus_caps->vendorId;
+  result_config_cie.codecId = p_a2dp_opus_caps->codecId;
+
+  //
+  // Select the sample frequency
+  //
+  sampleRate = p_a2dp_opus_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_48000:
+      if (sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000) {
+        result_config_cie.sampleRate = A2DP_OPUS_SAMPLING_FREQ_48000;
+        codec_capability_.sample_rate = codec_user_config_.sample_rate;
+        codec_config_.sample_rate = codec_user_config_.sample_rate;
+      }
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+      codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+      codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+      break;
+  }
+
+  // Select the sample frequency if there is no user preference
+  do {
+    // Compute the selectable capability
+    if (sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000) {
+      codec_selectable_capability_.sample_rate |=
+          BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+    }
+
+    if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+    // Compute the common capability
+    if (sampleRate & A2DP_OPUS_SAMPLING_FREQ_48000)
+      codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+
+    // No user preference - try the codec audio config
+    if (select_audio_sample_rate(&codec_audio_config_, sampleRate,
+                                 &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - try the default config
+    if (select_best_sample_rate(
+            a2dp_opus_default_config.sampleRate & peer_info_cie.sampleRate,
+            &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - use the best match
+    if (select_best_sample_rate(sampleRate, &result_config_cie,
+                                &codec_config_)) {
+      break;
+    }
+  } while (false);
+  if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
+    LOG_ERROR(
+        "cannot match sample frequency: local caps = 0x%x "
+        "peer info = 0x%x",
+        p_a2dp_opus_caps->sampleRate, peer_info_cie.sampleRate);
+    goto fail;
+  }
+
+  //
+  // Select the bits per sample
+  //
+  // NOTE: this information is NOT included in the Opus A2DP codec description
+  // that is sent OTA.
+  bits_per_sample = p_a2dp_opus_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:
+      if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+        result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+        codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+        codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+      }
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+      if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+        result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+        codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+        codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+      }
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+      if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+        result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+        codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+        codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+      }
+      break;
+    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+      result_config_cie.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+      codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+      codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+      break;
+  }
+
+  // Select the bits per sample if there is no user preference
+  do {
+    // Compute the selectable capability
+    codec_selectable_capability_.bits_per_sample =
+        p_a2dp_opus_caps->bits_per_sample;
+
+    if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
+      break;
+
+    // Compute the common capability
+    codec_capability_.bits_per_sample = bits_per_sample;
+
+    // No user preference - try yhe codec audio config
+    if (select_audio_bits_per_sample(&codec_audio_config_,
+                                     p_a2dp_opus_caps->bits_per_sample,
+                                     &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - try the default config
+    if (select_best_bits_per_sample(a2dp_opus_default_config.bits_per_sample,
+                                    &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - use the best match
+    if (select_best_bits_per_sample(p_a2dp_opus_caps->bits_per_sample,
+                                    &result_config_cie, &codec_config_)) {
+      break;
+    }
+  } while (false);
+  if (codec_config_.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) {
+    LOG_ERROR(
+        "cannot match bits per sample: default = 0x%x "
+        "user preference = 0x%x",
+        a2dp_opus_default_config.bits_per_sample,
+        codec_user_config_.bits_per_sample);
+    goto fail;
+  }
+
+  //
+  // Select the channel mode
+  //
+  channelMode = p_a2dp_opus_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:
+      if (channelMode & A2DP_OPUS_CHANNEL_MODE_MONO) {
+        result_config_cie.channelMode = A2DP_OPUS_CHANNEL_MODE_MONO;
+        codec_capability_.channel_mode = codec_user_config_.channel_mode;
+        codec_config_.channel_mode = codec_user_config_.channel_mode;
+      }
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+      if (channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+        result_config_cie.channelMode = A2DP_OPUS_CHANNEL_MODE_STEREO;
+        codec_capability_.channel_mode = codec_user_config_.channel_mode;
+        codec_config_.channel_mode = codec_user_config_.channel_mode;
+      }
+      break;
+    case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+      codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+      codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+      break;
+  }
+
+  // Select the channel mode if there is no user preference
+  do {
+    // Compute the selectable capability
+    if (channelMode & A2DP_OPUS_CHANNEL_MODE_MONO) {
+      codec_selectable_capability_.channel_mode |=
+          BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+    }
+    if (channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+      codec_selectable_capability_.channel_mode |=
+          BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+    }
+
+    if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+    // Compute the common capability
+    if (channelMode & A2DP_OPUS_CHANNEL_MODE_MONO)
+      codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+    if (channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+      codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+    }
+
+    // No user preference - try the codec audio config
+    if (select_audio_channel_mode(&codec_audio_config_, channelMode,
+                                  &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - try the default config
+    if (select_best_channel_mode(
+            a2dp_opus_default_config.channelMode & peer_info_cie.channelMode,
+            &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - use the best match
+    if (select_best_channel_mode(channelMode, &result_config_cie,
+                                 &codec_config_)) {
+      break;
+    }
+  } while (false);
+  if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
+    LOG_ERROR(
+        "cannot match channel mode: local caps = 0x%x "
+        "peer info = 0x%x",
+        p_a2dp_opus_caps->channelMode, peer_info_cie.channelMode);
+    goto fail;
+  }
+
+  //
+  // Select the frame size
+  //
+  frameSize = p_a2dp_opus_caps->future1 & peer_info_cie.future1;
+  codec_config_.codec_specific_1 = BTAV_A2DP_CODEC_FRAME_SIZE_NONE;
+  switch (codec_user_config_.codec_specific_1) {
+    case BTAV_A2DP_CODEC_FRAME_SIZE_20MS:
+      if (frameSize & A2DP_OPUS_20MS_FRAMESIZE) {
+        result_config_cie.future1 = A2DP_OPUS_20MS_FRAMESIZE;
+        codec_capability_.codec_specific_1 =
+            codec_user_config_.codec_specific_1;
+        codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+      }
+      break;
+    case BTAV_A2DP_CODEC_FRAME_SIZE_10MS:
+      if (frameSize & A2DP_OPUS_10MS_FRAMESIZE) {
+        result_config_cie.future1 = A2DP_OPUS_10MS_FRAMESIZE;
+        codec_capability_.codec_specific_1 =
+            codec_user_config_.codec_specific_1;
+        codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+      }
+      break;
+    case BTAV_A2DP_CODEC_FRAME_SIZE_NONE:
+      codec_capability_.codec_specific_1 = BTAV_A2DP_CODEC_FRAME_SIZE_NONE;
+      codec_config_.codec_specific_1 = BTAV_A2DP_CODEC_FRAME_SIZE_NONE;
+      break;
+  }
+
+  // No user preference - set default value
+  codec_config_.codec_specific_1 = BTAV_A2DP_CODEC_FRAME_SIZE_20MS;
+  result_config_cie.future1 = A2DP_OPUS_20MS_FRAMESIZE;
+  result_config_cie.future3 = 0x00;
+
+  if (codec_config_.codec_specific_1 == BTAV_A2DP_CODEC_FRAME_SIZE_NONE) {
+    LOG_ERROR(
+        "cannot match frame size: local caps = 0x%x "
+        "peer info = 0x%x",
+        p_a2dp_opus_caps->future1, peer_info_cie.future1);
+    goto fail;
+  }
+
+  if (A2DP_BuildInfoOpus(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+                         p_result_codec_config) != A2DP_SUCCESS) {
+    LOG_ERROR("failed to BuildInfoOpus for result_config_cie");
+    goto fail;
+  }
+
+  //
+  // Copy the codec-specific fields if they are not zero
+  //
+  if (codec_user_config_.codec_specific_1 != 0)
+    codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+  if (codec_user_config_.codec_specific_2 != 0)
+    codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
+  if (codec_user_config_.codec_specific_3 != 0)
+    codec_config_.codec_specific_3 = codec_user_config_.codec_specific_3;
+  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
+  // result codec config.
+  if (is_capability) {
+    status = A2DP_BuildInfoOpus(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                                ota_codec_peer_capability_);
+  } else {
+    status = A2DP_BuildInfoOpus(AVDT_MEDIA_TYPE_AUDIO, &peer_info_cie,
+                                ota_codec_peer_config_);
+  }
+  CHECK(status == A2DP_SUCCESS);
+
+  status = A2DP_BuildInfoOpus(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+                              ota_codec_config_);
+  CHECK(status == A2DP_SUCCESS);
+  return true;
+
+fail:
+  // Restore the internal state
+  codec_config_ = saved_codec_config;
+  codec_capability_ = saved_codec_capability;
+  codec_selectable_capability_ = saved_codec_selectable_capability;
+  codec_user_config_ = saved_codec_user_config;
+  codec_audio_config_ = saved_codec_audio_config;
+  memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+  memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+         sizeof(ota_codec_peer_capability_));
+  memcpy(ota_codec_peer_config_, saved_ota_codec_peer_config,
+         sizeof(ota_codec_peer_config_));
+  return false;
+}
+
+bool A2dpCodecConfigOpusBase::setPeerCodecCapabilities(
+    const uint8_t* p_peer_codec_capabilities) {
+  std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+  tA2DP_OPUS_CIE peer_info_cie;
+  uint8_t channelMode;
+  uint8_t sampleRate;
+  const tA2DP_OPUS_CIE* p_a2dp_opus_caps =
+      (is_source_) ? &a2dp_opus_source_caps : &a2dp_opus_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_ParseInfoOpus(&peer_info_cie, p_peer_codec_capabilities, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR("can't parse peer's capabilities: error = %d", status);
+    goto fail;
+  }
+
+  // Compute the selectable capability - sample rate
+  sampleRate = p_a2dp_opus_caps->sampleRate & peer_info_cie.sampleRate;
+  if (sampleRate & A2DP_OPUS_SAMPLING_FREQ_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 =
+      p_a2dp_opus_caps->bits_per_sample;
+
+  // Compute the selectable capability - channel mode
+  channelMode = p_a2dp_opus_caps->channelMode & peer_info_cie.channelMode;
+  if (channelMode & A2DP_OPUS_CHANNEL_MODE_MONO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  }
+  if (channelMode & A2DP_OPUS_CHANNEL_MODE_STEREO) {
+    codec_selectable_capability_.channel_mode |=
+        BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+
+  LOG_INFO("BuildInfoOpus for peer info cie for ota caps");
+  status = A2DP_BuildInfoOpus(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;
+}
+
+A2dpCodecConfigOpusSink::A2dpCodecConfigOpusSink(
+    btav_a2dp_codec_priority_t codec_priority)
+    : A2dpCodecConfigOpusBase(BTAV_A2DP_CODEC_INDEX_SINK_OPUS,
+                              A2DP_VendorCodecIndexStrOpusSink(),
+                              codec_priority, false) {}
+
+A2dpCodecConfigOpusSink::~A2dpCodecConfigOpusSink() {}
+
+bool A2dpCodecConfigOpusSink::init() {
+  if (!isValid()) return false;
+
+  return true;
+}
+
+bool A2dpCodecConfigOpusSink::useRtpHeaderMarkerBit() const { return false; }
+
+bool A2dpCodecConfigOpusSink::updateEncoderUserConfig(
+    UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+    UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+    UNUSED_ATTR bool* p_config_updated) {
+  return false;
+}
diff --git a/system/stack/a2dp/a2dp_vendor_opus_decoder.cc b/system/stack/a2dp/a2dp_vendor_opus_decoder.cc
new file mode 100644
index 00000000000..20867b5a808
--- /dev/null
+++ b/system/stack/a2dp/a2dp_vendor_opus_decoder.cc
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_opus_decoder"
+
+#include "a2dp_vendor_opus_decoder.h"
+
+#include <base/logging.h>
+#include <opus.h>
+
+#include "a2dp_vendor_opus.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+typedef struct {
+  OpusDecoder* opus_handle = nullptr;
+  bool has_opus_handle;
+  int16_t* decode_buf = nullptr;
+  decoded_data_callback_t decode_callback;
+} tA2DP_OPUS_DECODER_CB;
+
+static tA2DP_OPUS_DECODER_CB a2dp_opus_decoder_cb;
+
+void a2dp_vendor_opus_decoder_cleanup(void) {
+  if (a2dp_opus_decoder_cb.has_opus_handle) {
+    osi_free(a2dp_opus_decoder_cb.opus_handle);
+
+    if (a2dp_opus_decoder_cb.decode_buf != nullptr) {
+      memset(a2dp_opus_decoder_cb.decode_buf, 0,
+             A2DP_OPUS_DECODE_BUFFER_LENGTH);
+      osi_free(a2dp_opus_decoder_cb.decode_buf);
+      a2dp_opus_decoder_cb.decode_buf = nullptr;
+    }
+    a2dp_opus_decoder_cb.has_opus_handle = false;
+  }
+
+  return;
+}
+
+bool a2dp_vendor_opus_decoder_init(decoded_data_callback_t decode_callback) {
+  a2dp_vendor_opus_decoder_cleanup();
+
+  int32_t err_val = OPUS_OK;
+  int32_t size = 0;
+
+  size = opus_decoder_get_size(A2DP_OPUS_CODEC_OUTPUT_CHS);
+  a2dp_opus_decoder_cb.opus_handle =
+      static_cast<OpusDecoder*>(osi_malloc(size));
+  if (a2dp_opus_decoder_cb.opus_handle == nullptr) {
+    LOG_ERROR("failed to allocate opus decoder handle");
+    return false;
+  }
+  err_val = opus_decoder_init(a2dp_opus_decoder_cb.opus_handle,
+                              A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE,
+                              A2DP_OPUS_CODEC_OUTPUT_CHS);
+  if (err_val == OPUS_OK) {
+    a2dp_opus_decoder_cb.has_opus_handle = true;
+
+    a2dp_opus_decoder_cb.decode_buf =
+        static_cast<int16_t*>(osi_malloc(A2DP_OPUS_DECODE_BUFFER_LENGTH));
+
+    memset(a2dp_opus_decoder_cb.decode_buf, 0, A2DP_OPUS_DECODE_BUFFER_LENGTH);
+
+    a2dp_opus_decoder_cb.decode_callback = decode_callback;
+    LOG_INFO("decoder init success");
+    return true;
+  } else {
+    LOG_ERROR("failed to initialize Opus Decoder");
+    a2dp_opus_decoder_cb.has_opus_handle = false;
+    return false;
+  }
+
+  return false;
+}
+
+void a2dp_vendor_opus_decoder_configure(const uint8_t* p_codec_info) { return; }
+
+bool a2dp_vendor_opus_decoder_decode_packet(BT_HDR* p_buf) {
+  uint32_t frameSize;
+  uint32_t numChannels;
+  uint32_t numFrames;
+  int32_t ret_val = 0;
+  uint32_t frameLen = 0;
+
+  if (p_buf == nullptr) {
+    LOG_ERROR("Dropping packet with nullptr");
+    return false;
+  }
+
+  auto* pBuffer =
+      reinterpret_cast<unsigned char*>(p_buf->data + p_buf->offset + 1);
+  int32_t bufferSize = p_buf->len - 1;
+
+  numChannels = opus_packet_get_nb_channels(pBuffer);
+  numFrames = opus_packet_get_nb_frames(pBuffer, bufferSize);
+  frameSize = opus_packet_get_samples_per_frame(
+      pBuffer, A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE);
+  frameLen = opus_packet_get_nb_samples(pBuffer, bufferSize,
+                                        A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE);
+  uint32_t num_frames = pBuffer[0] & 0xf;
+
+  LOG_ERROR("numframes %d framesize %d framelen %d bufferSize %d", num_frames,
+            frameSize, frameLen, bufferSize);
+  LOG_ERROR("numChannels %d numFrames %d offset %d", numChannels, numFrames,
+            p_buf->offset);
+
+  for (uint32_t frame = 0; frame < numFrames; ++frame) {
+    {
+      numChannels = opus_packet_get_nb_channels(pBuffer);
+
+      ret_val = opus_decode(a2dp_opus_decoder_cb.opus_handle,
+                            reinterpret_cast<unsigned char*>(pBuffer),
+                            bufferSize, a2dp_opus_decoder_cb.decode_buf,
+                            A2DP_OPUS_DECODE_BUFFER_LENGTH, 0 /* flags */);
+
+      if (ret_val < OPUS_OK) {
+        LOG_ERROR("Opus DecodeFrame failed %d, applying concealment", ret_val);
+        ret_val = opus_decode(a2dp_opus_decoder_cb.opus_handle, NULL, 0,
+                              a2dp_opus_decoder_cb.decode_buf,
+                              A2DP_OPUS_DECODE_BUFFER_LENGTH, 0 /* flags */);
+      }
+
+      size_t frame_len =
+          ret_val * numChannels * sizeof(a2dp_opus_decoder_cb.decode_buf[0]);
+      a2dp_opus_decoder_cb.decode_callback(
+          reinterpret_cast<uint8_t*>(a2dp_opus_decoder_cb.decode_buf),
+          frame_len);
+    }
+  }
+  return true;
+}
+
+void a2dp_vendor_opus_decoder_start(void) { return; }
+
+void a2dp_vendor_opus_decoder_suspend(void) {
+  int32_t err_val = 0;
+
+  if (a2dp_opus_decoder_cb.has_opus_handle) {
+    err_val =
+        opus_decoder_ctl(a2dp_opus_decoder_cb.opus_handle, OPUS_RESET_STATE);
+    if (err_val != OPUS_OK) {
+      LOG_ERROR("failed to reset decoder");
+    }
+  }
+  return;
+}
diff --git a/system/stack/a2dp/a2dp_vendor_opus_encoder.cc b/system/stack/a2dp/a2dp_vendor_opus_encoder.cc
new file mode 100644
index 00000000000..ded13e4ae9c
--- /dev/null
+++ b/system/stack/a2dp/a2dp_vendor_opus_encoder.cc
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_vendor_opus_encoder"
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include "a2dp_vendor_opus_encoder.h"
+
+#ifndef OS_GENERIC
+#include <cutils/trace.h>
+#endif
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <opus.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_opus.h"
+#include "common/time_util.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/include/bt_hdr.h"
+
+typedef struct {
+  uint32_t sample_rate;
+  uint16_t bitrate;
+  uint16_t framesize;
+  uint8_t channel_mode;
+  uint8_t bits_per_sample;
+  uint8_t quality_mode_index;
+  int pcm_wlength;
+  uint8_t pcm_fmt;
+} tA2DP_OPUS_ENCODER_PARAMS;
+
+typedef struct {
+  float counter;
+  uint32_t bytes_per_tick;
+  uint64_t last_frame_us;
+} tA2DP_OPUS_FEEDING_STATE;
+
+typedef struct {
+  uint64_t session_start_us;
+
+  size_t media_read_total_expected_packets;
+  size_t media_read_total_expected_reads_count;
+  size_t media_read_total_expected_read_bytes;
+
+  size_t media_read_total_dropped_packets;
+  size_t media_read_total_actual_reads_count;
+  size_t media_read_total_actual_read_bytes;
+} a2dp_opus_encoder_stats_t;
+
+typedef struct {
+  a2dp_source_read_callback_t read_callback;
+  a2dp_source_enqueue_callback_t enqueue_callback;
+  uint16_t TxAaMtuSize;
+  size_t TxQueueLength;
+
+  bool use_SCMS_T;
+  bool is_peer_edr;          // True if the peer device supports EDR
+  bool peer_supports_3mbps;  // True if the peer device supports 3Mbps EDR
+  uint16_t peer_mtu;         // MTU of the A2DP peer
+  uint32_t timestamp;        // Timestamp for the A2DP frames
+
+  OpusEncoder* opus_handle;
+  bool has_opus_handle;  // True if opus_handle is valid
+
+  tA2DP_FEEDING_PARAMS feeding_params;
+  tA2DP_OPUS_ENCODER_PARAMS opus_encoder_params;
+  tA2DP_OPUS_FEEDING_STATE opus_feeding_state;
+
+  a2dp_opus_encoder_stats_t stats;
+} tA2DP_OPUS_ENCODER_CB;
+
+static tA2DP_OPUS_ENCODER_CB a2dp_opus_encoder_cb;
+
+static bool a2dp_vendor_opus_encoder_update(uint16_t peer_mtu,
+                                            A2dpCodecConfig* a2dp_codec_config,
+                                            bool* p_restart_input,
+                                            bool* p_restart_output,
+                                            bool* p_config_updated);
+static void a2dp_opus_get_num_frame_iteration(uint8_t* num_of_iterations,
+                                              uint8_t* num_of_frames,
+                                              uint64_t timestamp_us);
+static void a2dp_opus_encode_frames(uint8_t nb_frame);
+static bool a2dp_opus_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read);
+
+void a2dp_vendor_opus_encoder_cleanup(void) {
+  if (a2dp_opus_encoder_cb.has_opus_handle) {
+    osi_free(a2dp_opus_encoder_cb.opus_handle);
+    a2dp_opus_encoder_cb.has_opus_handle = false;
+    a2dp_opus_encoder_cb.opus_handle = nullptr;
+  }
+  memset(&a2dp_opus_encoder_cb, 0, sizeof(a2dp_opus_encoder_cb));
+
+  a2dp_opus_encoder_cb.stats.session_start_us =
+      bluetooth::common::time_get_os_boottime_us();
+
+  a2dp_opus_encoder_cb.timestamp = 0;
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  a2dp_opus_encoder_cb.use_SCMS_T = true;
+#else
+  a2dp_opus_encoder_cb.use_SCMS_T = false;
+#endif
+  return;
+}
+
+void a2dp_vendor_opus_encoder_init(
+    const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+    A2dpCodecConfig* a2dp_codec_config,
+    a2dp_source_read_callback_t read_callback,
+    a2dp_source_enqueue_callback_t enqueue_callback) {
+  uint32_t error_val;
+
+  a2dp_vendor_opus_encoder_cleanup();
+
+  a2dp_opus_encoder_cb.read_callback = read_callback;
+  a2dp_opus_encoder_cb.enqueue_callback = enqueue_callback;
+  a2dp_opus_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+  a2dp_opus_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+  a2dp_opus_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+
+  // NOTE: Ignore the restart_input / restart_output flags - this initization
+  // happens when the connection is (re)started.
+  bool restart_input = false;
+  bool restart_output = false;
+  bool config_updated = false;
+
+  uint32_t size = opus_encoder_get_size(A2DP_OPUS_CODEC_OUTPUT_CHS);
+  a2dp_opus_encoder_cb.opus_handle =
+      static_cast<OpusEncoder*>(osi_malloc(size));
+  if (a2dp_opus_encoder_cb.opus_handle == nullptr) {
+    LOG_ERROR("failed to allocate opus encoder handle");
+    return;
+  }
+
+  error_val = opus_encoder_init(
+      a2dp_opus_encoder_cb.opus_handle, A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE,
+      A2DP_OPUS_CODEC_OUTPUT_CHS, OPUS_APPLICATION_AUDIO);
+
+  if (error_val != OPUS_OK) {
+    LOG_ERROR(
+        "failed to init opus encoder (handle size %d, sampling rate %d, "
+        "output chs %d, error %d)",
+        size, A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE, A2DP_OPUS_CODEC_OUTPUT_CHS,
+        error_val);
+    osi_free(a2dp_opus_encoder_cb.opus_handle);
+    return;
+  } else {
+    a2dp_opus_encoder_cb.has_opus_handle = true;
+  }
+
+  a2dp_vendor_opus_encoder_update(a2dp_opus_encoder_cb.peer_mtu,
+                                  a2dp_codec_config, &restart_input,
+                                  &restart_output, &config_updated);
+
+  return;
+}
+
+bool A2dpCodecConfigOpusSource::updateEncoderUserConfig(
+    const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+    bool* p_restart_output, bool* p_config_updated) {
+  if (a2dp_opus_encoder_cb.peer_mtu == 0) {
+    LOG_ERROR(
+        "Cannot update the codec encoder for %s: "
+        "invalid peer MTU",
+        name().c_str());
+    return false;
+  }
+
+  return a2dp_vendor_opus_encoder_update(a2dp_opus_encoder_cb.peer_mtu, this,
+                                         p_restart_input, p_restart_output,
+                                         p_config_updated);
+}
+
+static bool a2dp_vendor_opus_encoder_update(uint16_t peer_mtu,
+                                            A2dpCodecConfig* a2dp_codec_config,
+                                            bool* p_restart_input,
+                                            bool* p_restart_output,
+                                            bool* p_config_updated) {
+  tA2DP_OPUS_ENCODER_PARAMS* p_encoder_params =
+      &a2dp_opus_encoder_cb.opus_encoder_params;
+  uint8_t codec_info[AVDT_CODEC_SIZE];
+  uint32_t error = 0;
+
+  *p_restart_input = false;
+  *p_restart_output = false;
+  *p_config_updated = false;
+
+  if (!a2dp_opus_encoder_cb.has_opus_handle ||
+      a2dp_opus_encoder_cb.opus_handle == NULL) {
+    LOG_ERROR("Cannot get Opus encoder handle");
+    return false;
+  }
+  CHECK(a2dp_opus_encoder_cb.opus_handle != nullptr);
+
+  if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+    LOG_ERROR(
+        "Cannot update the codec encoder for %s: "
+        "invalid codec config",
+        a2dp_codec_config->name().c_str());
+    return false;
+  }
+  const uint8_t* p_codec_info = codec_info;
+  btav_a2dp_codec_config_t codec_config = a2dp_codec_config->getCodecConfig();
+
+  // The feeding parameters
+  tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_opus_encoder_cb.feeding_params;
+  p_feeding_params->sample_rate =
+      A2DP_VendorGetTrackSampleRateOpus(p_codec_info);
+  p_feeding_params->bits_per_sample =
+      a2dp_codec_config->getAudioBitsPerSample();
+  p_feeding_params->channel_count =
+      A2DP_VendorGetTrackChannelCountOpus(p_codec_info);
+  LOG_INFO("sample_rate=%u bits_per_sample=%u channel_count=%u",
+           p_feeding_params->sample_rate, p_feeding_params->bits_per_sample,
+           p_feeding_params->channel_count);
+  a2dp_vendor_opus_feeding_reset();
+
+  // The codec parameters
+  p_encoder_params->sample_rate =
+      a2dp_opus_encoder_cb.feeding_params.sample_rate;
+  p_encoder_params->channel_mode =
+      A2DP_VendorGetChannelModeCodeOpus(p_codec_info);
+  p_encoder_params->framesize = A2DP_VendorGetFrameSizeOpus(p_codec_info);
+  p_encoder_params->bitrate = A2DP_VendorGetBitRateOpus(p_codec_info);
+
+  uint16_t mtu_size =
+      BT_DEFAULT_BUFFER_SIZE - A2DP_OPUS_OFFSET - sizeof(BT_HDR);
+  if (mtu_size < peer_mtu) {
+    a2dp_opus_encoder_cb.TxAaMtuSize = mtu_size;
+  } else {
+    a2dp_opus_encoder_cb.TxAaMtuSize = peer_mtu;
+  }
+
+  // Set the bitrate quality mode index
+  if (codec_config.codec_specific_3 != 0) {
+    p_encoder_params->quality_mode_index = codec_config.codec_specific_3 % 10;
+    LOG_INFO("setting bitrate quality mode to %d",
+             p_encoder_params->quality_mode_index);
+  } else {
+    p_encoder_params->quality_mode_index = 5;
+    LOG_INFO("setting bitrate quality mode to default %d",
+             p_encoder_params->quality_mode_index);
+  }
+
+  error = opus_encoder_ctl(
+      a2dp_opus_encoder_cb.opus_handle,
+      OPUS_SET_COMPLEXITY(p_encoder_params->quality_mode_index));
+
+  if (error != OPUS_OK) {
+    LOG_ERROR("failed to set encoder bitrate quality setting");
+    return false;
+  }
+
+  p_encoder_params->pcm_wlength =
+      a2dp_opus_encoder_cb.feeding_params.bits_per_sample >> 3;
+
+  LOG_INFO("setting bitrate to %d", p_encoder_params->bitrate);
+  error = opus_encoder_ctl(a2dp_opus_encoder_cb.opus_handle,
+                           OPUS_SET_BITRATE(p_encoder_params->bitrate));
+
+  if (error != OPUS_OK) {
+    LOG_ERROR("failed to set encoder bitrate");
+    return false;
+  }
+
+  // Set the Audio format from pcm_wlength
+  if (p_encoder_params->pcm_wlength == 2)
+    p_encoder_params->pcm_fmt = 16;
+  else if (p_encoder_params->pcm_wlength == 3)
+    p_encoder_params->pcm_fmt = 24;
+  else if (p_encoder_params->pcm_wlength == 4)
+    p_encoder_params->pcm_fmt = 32;
+
+  return true;
+}
+
+void a2dp_vendor_opus_feeding_reset(void) {
+  memset(&a2dp_opus_encoder_cb.opus_feeding_state, 0,
+         sizeof(a2dp_opus_encoder_cb.opus_feeding_state));
+
+  a2dp_opus_encoder_cb.opus_feeding_state.bytes_per_tick =
+      (a2dp_opus_encoder_cb.feeding_params.sample_rate *
+       a2dp_opus_encoder_cb.feeding_params.bits_per_sample / 8 *
+       a2dp_opus_encoder_cb.feeding_params.channel_count *
+       a2dp_vendor_opus_get_encoder_interval_ms()) /
+      1000;
+
+  return;
+}
+
+void a2dp_vendor_opus_feeding_flush(void) {
+  a2dp_opus_encoder_cb.opus_feeding_state.counter = 0.0f;
+
+  return;
+}
+
+uint64_t a2dp_vendor_opus_get_encoder_interval_ms(void) {
+  return ((a2dp_opus_encoder_cb.opus_encoder_params.framesize * 1000) /
+          a2dp_opus_encoder_cb.opus_encoder_params.sample_rate);
+}
+
+void a2dp_vendor_opus_send_frames(uint64_t timestamp_us) {
+  uint8_t nb_frame = 0;
+  uint8_t nb_iterations = 0;
+
+  a2dp_opus_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us);
+  if (nb_frame == 0) return;
+
+  for (uint8_t counter = 0; counter < nb_iterations; counter++) {
+    // Transcode frame and enqueue
+    a2dp_opus_encode_frames(nb_frame);
+  }
+
+  return;
+}
+
+// Obtains the number of frames to send and number of iterations
+// to be used. |num_of_iterations| and |num_of_frames| parameters
+// are used as output param for returning the respective values.
+static void a2dp_opus_get_num_frame_iteration(uint8_t* num_of_iterations,
+                                              uint8_t* num_of_frames,
+                                              uint64_t timestamp_us) {
+  uint32_t result = 0;
+  uint8_t nof = 0;
+  uint8_t noi = 1;
+
+  uint32_t pcm_bytes_per_frame =
+      a2dp_opus_encoder_cb.opus_encoder_params.framesize *
+      a2dp_opus_encoder_cb.feeding_params.channel_count *
+      a2dp_opus_encoder_cb.feeding_params.bits_per_sample / 8;
+
+  uint32_t us_this_tick = a2dp_vendor_opus_get_encoder_interval_ms() * 1000;
+  uint64_t now_us = timestamp_us;
+  if (a2dp_opus_encoder_cb.opus_feeding_state.last_frame_us != 0)
+    us_this_tick =
+        (now_us - a2dp_opus_encoder_cb.opus_feeding_state.last_frame_us);
+  a2dp_opus_encoder_cb.opus_feeding_state.last_frame_us = now_us;
+
+  a2dp_opus_encoder_cb.opus_feeding_state.counter +=
+      (float)a2dp_opus_encoder_cb.opus_feeding_state.bytes_per_tick *
+      us_this_tick / (a2dp_vendor_opus_get_encoder_interval_ms() * 1000);
+
+  result =
+      a2dp_opus_encoder_cb.opus_feeding_state.counter / pcm_bytes_per_frame;
+  a2dp_opus_encoder_cb.opus_feeding_state.counter -=
+      result * pcm_bytes_per_frame;
+  nof = result;
+
+  *num_of_frames = nof;
+  *num_of_iterations = noi;
+}
+
+static void a2dp_opus_encode_frames(uint8_t nb_frame) {
+  tA2DP_OPUS_ENCODER_PARAMS* p_encoder_params =
+      &a2dp_opus_encoder_cb.opus_encoder_params;
+  unsigned char* packet;
+  uint8_t remain_nb_frame = nb_frame;
+  uint16_t opus_frame_size = p_encoder_params->framesize;
+  uint8_t read_buffer[p_encoder_params->framesize *
+                      p_encoder_params->pcm_wlength *
+                      p_encoder_params->channel_mode];
+
+  int32_t out_frames = 0;
+  uint32_t written = 0;
+
+  uint32_t bytes_read = 0;
+  while (nb_frame) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+    p_buf->offset = A2DP_OPUS_OFFSET;
+    p_buf->len = 0;
+    p_buf->layer_specific = 0;
+    a2dp_opus_encoder_cb.stats.media_read_total_expected_packets++;
+
+    do {
+      //
+      // Read the PCM data and encode it
+      //
+      uint32_t temp_bytes_read = 0;
+      if (a2dp_opus_read_feeding(read_buffer, &temp_bytes_read)) {
+        bytes_read += temp_bytes_read;
+        packet = (unsigned char*)(p_buf + 1) + p_buf->offset + p_buf->len;
+
+        if (a2dp_opus_encoder_cb.opus_handle == NULL) {
+          LOG_ERROR("invalid OPUS handle");
+          a2dp_opus_encoder_cb.stats.media_read_total_dropped_packets++;
+          osi_free(p_buf);
+          return;
+        }
+
+        written =
+            opus_encode(a2dp_opus_encoder_cb.opus_handle,
+                        (const opus_int16*)&read_buffer[0], opus_frame_size,
+                        packet, (BT_DEFAULT_BUFFER_SIZE - p_buf->offset));
+
+        if (written <= 0) {
+          LOG_ERROR("OPUS encoding error");
+          a2dp_opus_encoder_cb.stats.media_read_total_dropped_packets++;
+          osi_free(p_buf);
+          return;
+        } else {
+          out_frames++;
+        }
+        p_buf->len += written;
+        nb_frame--;
+        p_buf->layer_specific += out_frames;  // added a frame to the buffer
+      } else {
+        LOG_WARN("Opus src buffer underflow %d", nb_frame);
+        a2dp_opus_encoder_cb.opus_feeding_state.counter +=
+            nb_frame * opus_frame_size *
+            a2dp_opus_encoder_cb.feeding_params.channel_count *
+            a2dp_opus_encoder_cb.feeding_params.bits_per_sample / 8;
+
+        // no more pcm to read
+        nb_frame = 0;
+      }
+    } while ((written == 0) && nb_frame);
+
+    if (p_buf->len) {
+      /*
+       * Timestamp of the media packet header represent the TS of the
+       * first frame, i.e. the timestamp before including this frame.
+       */
+      *((uint32_t*)(p_buf + 1)) = a2dp_opus_encoder_cb.timestamp;
+
+      a2dp_opus_encoder_cb.timestamp += p_buf->layer_specific * opus_frame_size;
+
+      uint8_t done_nb_frame = remain_nb_frame - nb_frame;
+      remain_nb_frame = nb_frame;
+
+      if (!a2dp_opus_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                 bytes_read))
+        return;
+    } else {
+      a2dp_opus_encoder_cb.stats.media_read_total_dropped_packets++;
+      osi_free(p_buf);
+    }
+  }
+}
+
+static bool a2dp_opus_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read) {
+  uint32_t read_size = a2dp_opus_encoder_cb.opus_encoder_params.framesize *
+                       a2dp_opus_encoder_cb.feeding_params.channel_count *
+                       a2dp_opus_encoder_cb.feeding_params.bits_per_sample / 8;
+
+  a2dp_opus_encoder_cb.stats.media_read_total_expected_reads_count++;
+  a2dp_opus_encoder_cb.stats.media_read_total_expected_read_bytes += read_size;
+
+  /* Read Data from UIPC channel */
+  uint32_t nb_byte_read =
+      a2dp_opus_encoder_cb.read_callback(read_buffer, read_size);
+  a2dp_opus_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;
+
+  if (nb_byte_read < read_size) {
+    if (nb_byte_read == 0) return false;
+
+    /* Fill the unfilled part of the read buffer with silence (0) */
+    memset(((uint8_t*)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
+    nb_byte_read = read_size;
+  }
+  a2dp_opus_encoder_cb.stats.media_read_total_actual_reads_count++;
+
+  *bytes_read = nb_byte_read;
+  return true;
+}
+
+void a2dp_vendor_opus_set_transmit_queue_length(size_t transmit_queue_length) {
+  a2dp_opus_encoder_cb.TxQueueLength = transmit_queue_length;
+
+  return;
+}
+
+uint64_t A2dpCodecConfigOpusSource::encoderIntervalMs() const {
+  return a2dp_vendor_opus_get_encoder_interval_ms();
+}
+
+int a2dp_vendor_opus_get_effective_frame_size() {
+  return a2dp_opus_encoder_cb.TxAaMtuSize;
+}
+
+void A2dpCodecConfigOpusSource::debug_codec_dump(int fd) {
+  a2dp_opus_encoder_stats_t* stats = &a2dp_opus_encoder_cb.stats;
+  tA2DP_OPUS_ENCODER_PARAMS* p_encoder_params =
+      &a2dp_opus_encoder_cb.opus_encoder_params;
+
+  A2dpCodecConfig::debug_codec_dump(fd);
+
+  dprintf(fd,
+          "  Packet counts (expected/dropped)                        : %zu / "
+          "%zu\n",
+          stats->media_read_total_expected_packets,
+          stats->media_read_total_dropped_packets);
+
+  dprintf(fd,
+          "  PCM read counts (expected/actual)                       : %zu / "
+          "%zu\n",
+          stats->media_read_total_expected_reads_count,
+          stats->media_read_total_actual_reads_count);
+
+  dprintf(fd,
+          "  PCM read bytes (expected/actual)                        : %zu / "
+          "%zu\n",
+          stats->media_read_total_expected_read_bytes,
+          stats->media_read_total_actual_read_bytes);
+
+  dprintf(fd,
+          "  OPUS transmission bitrate (Kbps)                        : %d\n",
+          p_encoder_params->bitrate);
+
+  dprintf(fd,
+          "  OPUS saved transmit queue length                        : %zu\n",
+          a2dp_opus_encoder_cb.TxQueueLength);
+
+  return;
+}
diff --git a/system/stack/include/a2dp_error_codes.h b/system/stack/include/a2dp_error_codes.h
index 0aa7105b7ac..ae5e26acf5f 100644
--- a/system/stack/include/a2dp_error_codes.h
+++ b/system/stack/include/a2dp_error_codes.h
@@ -128,6 +128,9 @@
  */
 #define A2DP_BAD_CP_FORMAT 0xE1
 
+/* Invalid framesize */
+#define A2DP_NS_FRAMESIZE 0xE2
+
 typedef uint8_t tA2DP_STATUS;
 
 #endif  // A2DP_ERROR_CODES_H
diff --git a/system/stack/include/a2dp_vendor_opus.h b/system/stack/include/a2dp_vendor_opus.h
new file mode 100644
index 00000000000..08a0b7b660f
--- /dev/null
+++ b/system/stack/include/a2dp_vendor_opus.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codec API for Opus
+//
+
+#ifndef A2DP_VENDOR_OPUS_H
+#define A2DP_VENDOR_OPUS_H
+
+#include "a2dp_codec_api.h"
+#include "a2dp_vendor_opus_constants.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigOpusBase : public A2dpCodecConfig {
+ protected:
+  A2dpCodecConfigOpusBase(btav_a2dp_codec_index_t codec_index,
+                          const std::string& name,
+                          btav_a2dp_codec_priority_t codec_priority,
+                          bool is_source)
+      : A2dpCodecConfig(codec_index, name, codec_priority),
+        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
+};
+
+class A2dpCodecConfigOpusSource : public A2dpCodecConfigOpusBase {
+ public:
+  A2dpCodecConfigOpusSource(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigOpusSource();
+
+  bool init() override;
+  uint64_t encoderIntervalMs() const;
+
+ private:
+  bool useRtpHeaderMarkerBit() const override;
+  bool updateEncoderUserConfig(
+      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+      bool* p_restart_input, bool* p_restart_output, bool* p_config_updated);
+  void debug_codec_dump(int fd) override;
+};
+
+class A2dpCodecConfigOpusSink : public A2dpCodecConfigOpusBase {
+ public:
+  A2dpCodecConfigOpusSink(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigOpusSink();
+
+  bool init() override;
+  uint64_t encoderIntervalMs() const;
+
+ private:
+  bool useRtpHeaderMarkerBit() const override;
+  bool updateEncoderUserConfig(
+      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+      bool* p_restart_input, bool* p_restart_output, bool* p_config_updated);
+};
+
+// Checks whether the codec capabilities contain a valid A2DP Opus Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid Opus
+// codec, otherwise false.
+bool A2DP_IsVendorSourceCodecValidOpus(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP Opus Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid Opus
+// codec, otherwise false.
+bool A2DP_IsVendorSinkCodecValidOpus(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP Opus Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid Opus
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSinkCodecValidOpus(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP Opus Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid Opus
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecValidOpus(const uint8_t* p_codec_info);
+
+// Checks whether A2DP Opus Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP Opus Sink codec is supported, otherwise false.
+bool A2DP_IsVendorSinkCodecSupportedOpus(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP Opus Source codec for a peer Source device is
+// supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP Opus Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedOpus(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_VendorUsesRtpHeaderOpus(bool content_protection_enabled,
+                                  const uint8_t* p_codec_info);
+
+// Gets the A2DP Opus codec name for a given |p_codec_info|.
+const char* A2DP_VendorCodecNameOpus(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP Opus codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_VendorCodecTypeEqualsOpus(const uint8_t* p_codec_info_a,
+                                    const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP Opus codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not Opus, the return value is false.
+bool A2DP_VendorCodecEqualsOpus(const uint8_t* p_codec_info_a,
+                                const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP Opus codec.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackSampleRateOpus(const uint8_t* p_codec_info);
+
+// Gets the track bits per sample value for the A2DP Opus codec.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the track bits per sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleOpus(const uint8_t* p_codec_info);
+
+// Gets the track bitrate value for the A2DP Opus codec.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetBitRateOpus(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP Opus codec.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackChannelCountOpus(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP Opus codec.
+// 1 for mono, or 3 for dual channel/stereo.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkTrackChannelTypeOpus(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP Opus codec.
+// The actual value is codec-specific - see |A2DP_OPUS_CHANNEL_MODE_*|.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetChannelModeCodeOpus(const uint8_t* p_codec_info);
+
+// Gets the framesize value (in ms) for the A2DP Opus codec.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns the framesize on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetFrameSizeOpus(const uint8_t* p_codec_info);
+
+// Gets the A2DP Opus audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorGetPacketTimestampOpus(const uint8_t* p_codec_info,
+                                       const uint8_t* p_data,
+                                       uint32_t* p_timestamp);
+
+// Builds A2DP Opus codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_VendorBuildCodecHeaderOpus(const uint8_t* p_codec_info, BT_HDR* p_buf,
+                                     uint16_t frames_per_packet);
+
+// Decodes A2DP Opus codec info into a human readable string.
+// |p_codec_info| is a pointer to the Opus codec_info to decode.
+// Returns a string describing the codec information.
+std::string A2DP_VendorCodecInfoStringOpus(const uint8_t* p_codec_info);
+
+// Gets the A2DP Opus encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP Opus encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceOpus(
+    const uint8_t* p_codec_info);
+
+// Gets the current A2DP Opus decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP Opus decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceOpus(
+    const uint8_t* p_codec_info);
+
+// Adjusts the A2DP Opus codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_VendorAdjustCodecOpus(uint8_t* p_codec_info);
+
+// Gets the A2DP Opus Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexOpus(
+    const uint8_t* p_codec_info);
+
+// Gets the A2DP Opus Sink codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexOpus(
+    const uint8_t* p_codec_info);
+
+// Gets the A2DP Opus Source codec name.
+const char* A2DP_VendorCodecIndexStrOpus(void);
+
+// Gets the A2DP Opus Sink codec name.
+const char* A2DP_VendorCodecIndexStrOpusSink(void);
+
+// Initializes A2DP Opus Source codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigOpus(AvdtpSepConfig* p_cfg);
+
+// Initializes A2DP Opus Sink codec information into |AvdtpSepConfig|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigOpusSink(AvdtpSepConfig* p_cfg);
+
+#endif  // A2DP_VENDOR_OPUS_H
diff --git a/system/stack/include/a2dp_vendor_opus_constants.h b/system/stack/include/a2dp_vendor_opus_constants.h
new file mode 100644
index 00000000000..272b04c48d3
--- /dev/null
+++ b/system/stack/include/a2dp_vendor_opus_constants.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP constants for Opus codec
+//
+
+#ifndef A2DP_VENDOR_OPUS_CONSTANTS_H
+#define A2DP_VENDOR_OPUS_CONSTANTS_H
+
+#define A2DP_OPUS_CODEC_LEN 9
+
+#define A2DP_OPUS_CODEC_OUTPUT_CHS 2
+#define A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE 48000
+#define A2DP_OPUS_CODEC_DEFAULT_FRAMESIZE 960
+#define A2DP_OPUS_DECODE_BUFFER_LENGTH \
+  (A2DP_OPUS_CODEC_OUTPUT_CHS * A2DP_OPUS_CODEC_DEFAULT_FRAMESIZE * 4)
+
+// [Octet 0-3] Vendor ID
+#define A2DP_OPUS_VENDOR_ID 0x000000E0
+// [Octet 4-5] Vendor Specific Codec ID
+#define A2DP_OPUS_CODEC_ID 0x0001
+// [Octet 6], [Bits 0,1,2] Channel Mode
+#define A2DP_OPUS_CHANNEL_MODE_MASK 0x07
+#define A2DP_OPUS_CHANNEL_MODE_MONO 0x01
+#define A2DP_OPUS_CHANNEL_MODE_STEREO 0x02
+#define A2DP_OPUS_CHANNEL_MODE_DUAL_MONO 0x04
+// [Octet 6], [Bits 3,4] Future 2, FrameSize
+#define A2DP_OPUS_FRAMESIZE_MASK 0x18
+#define A2DP_OPUS_10MS_FRAMESIZE 0x08
+#define A2DP_OPUS_20MS_FRAMESIZE 0x10
+// [Octet 6], [Bits 5] Sampling Frequency
+#define A2DP_OPUS_SAMPLING_FREQ_MASK 0x80
+#define A2DP_OPUS_SAMPLING_FREQ_48000 0x80
+// [Octet 6], [Bits 6,7] Reserved
+#define A2DP_OPUS_FUTURE_3 0x40
+#define A2DP_OPUS_FUTURE_4 0x80
+
+// Length of the Opus Media Payload header
+#define A2DP_OPUS_MPL_HDR_LEN 1
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_OPUS_OFFSET (AVDT_MEDIA_OFFSET + A2DP_OPUS_MPL_HDR_LEN + 1)
+#else
+#define A2DP_OPUS_OFFSET (AVDT_MEDIA_OFFSET + A2DP_OPUS_MPL_HDR_LEN)
+#endif
+
+#define A2DP_OPUS_HDR_F_MSK 0x80
+#define A2DP_OPUS_HDR_S_MSK 0x40
+#define A2DP_OPUS_HDR_L_MSK 0x20
+#define A2DP_OPUS_HDR_NUM_MSK 0x0F
+
+#endif
diff --git a/system/stack/include/a2dp_vendor_opus_decoder.h b/system/stack/include/a2dp_vendor_opus_decoder.h
new file mode 100644
index 00000000000..67b5bf706f3
--- /dev/null
+++ b/system/stack/include/a2dp_vendor_opus_decoder.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP Opus Decoder
+//
+
+#ifndef A2DP_VENDOR_OPUS_DECODER_H
+#define A2DP_VENDOR_OPUS_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Initialize the A2DP Opus decoder.
+bool a2dp_vendor_opus_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP Opus decoder.
+void a2dp_vendor_opus_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into
+// |a2dp_vendor_opus_decoder_init| if decoded frames are available.
+bool a2dp_vendor_opus_decoder_decode_packet(BT_HDR* p_buf);
+
+// Start the A2DP Opus decoder.
+void a2dp_vendor_opus_decoder_start(void);
+
+// Suspend the A2DP Opus decoder.
+void a2dp_vendor_opus_decoder_suspend(void);
+
+// A2DP Opus decoder configuration.
+void a2dp_vendor_opus_decoder_configure(const uint8_t* p_codec_info);
+
+#endif  // A2DP_VENDOR_OPUS_DECODER_H
diff --git a/system/stack/include/a2dp_vendor_opus_encoder.h b/system/stack/include/a2dp_vendor_opus_encoder.h
new file mode 100644
index 00000000000..0f88265f1f9
--- /dev/null
+++ b/system/stack/include/a2dp_vendor_opus_encoder.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP Opus Encoder
+//
+
+#ifndef A2DP_VENDOR_OPUS_ENCODER_H
+#define A2DP_VENDOR_OPUS_ENCODER_H
+
+#include "a2dp_codec_api.h"
+
+// Initialize the A2DP Opus encoder.
+// |p_peer_params| contains the A2DP peer information
+// The current A2DP codec config is in |a2dp_codec_config|.
+// |read_callback| is the callback for reading the input audio data.
+// |enqueue_callback| is the callback for enqueueing the encoded audio data.
+void a2dp_vendor_opus_encoder_init(
+    const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+    A2dpCodecConfig* a2dp_codec_config,
+    a2dp_source_read_callback_t read_callback,
+    a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Cleanup the A2DP Opus encoder.
+void a2dp_vendor_opus_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP Opus encoder.
+void a2dp_vendor_opus_feeding_reset(void);
+
+// Flush the feeding for the A2DP Opus encoder.
+void a2dp_vendor_opus_feeding_flush(void);
+
+// Get the A2DP Opus encoder interval (in milliseconds).
+uint64_t a2dp_vendor_opus_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP Opus encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_vendor_opus_send_frames(uint64_t timestamp_us);
+
+// Set transmit queue length for the A2DP Opus (Dynamic Bit Rate) mechanism.
+void a2dp_vendor_opus_set_transmit_queue_length(size_t transmit_queue_length);
+
+// Get the A2DP Opus encoded maximum frame size
+int a2dp_vendor_opus_get_effective_frame_size();
+
+#endif  // A2DP_VENDOR_OPUS_ENCODER_H
diff --git a/system/stack/test/fuzzers/Android.bp b/system/stack/test/fuzzers/Android.bp
index 54812c0b298..376b5ad5927 100644
--- a/system/stack/test/fuzzers/Android.bp
+++ b/system/stack/test/fuzzers/Android.bp
@@ -35,6 +35,7 @@ cc_defaults {
         "libbtdevice",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libosi",
         "libudrv-uipc",
         "libbt-protos-lite",
diff --git a/system/stack/test/stack_a2dp_test.cc b/system/stack/test/stack_a2dp_test.cc
index fe7692a8a5f..84744211185 100644
--- a/system/stack/test/stack_a2dp_test.cc
+++ b/system/stack/test/stack_a2dp_test.cc
@@ -27,6 +27,7 @@
 #include "stack/include/a2dp_codec_api.h"
 #include "stack/include/a2dp_sbc.h"
 #include "stack/include/a2dp_vendor.h"
+#include "stack/include/a2dp_vendor_opus_constants.h"
 #include "stack/include/bt_hdr.h"
 
 namespace {
@@ -187,6 +188,47 @@ const uint8_t codec_info_aac_sink_capability[AVDT_CODEC_SIZE] = {
     9                                  // Fake
 };
 
+const uint8_t codec_info_opus[AVDT_CODEC_SIZE] = {
+    A2DP_OPUS_CODEC_LEN,         // Length
+    AVDT_MEDIA_TYPE_AUDIO << 4,  // Media Type
+    A2DP_MEDIA_CT_NON_A2DP,      // Media Codec Type Vendor
+    (A2DP_OPUS_VENDOR_ID & 0x000000FF),
+    (A2DP_OPUS_VENDOR_ID & 0x0000FF00) >> 8,
+    (A2DP_OPUS_VENDOR_ID & 0x00FF0000) >> 16,
+    (A2DP_OPUS_VENDOR_ID & 0xFF000000) >> 24,
+    (A2DP_OPUS_CODEC_ID & 0x00FF),
+    (A2DP_OPUS_CODEC_ID & 0xFF00) >> 8,
+    A2DP_OPUS_CHANNEL_MODE_STEREO | A2DP_OPUS_20MS_FRAMESIZE |
+        A2DP_OPUS_SAMPLING_FREQ_48000};
+
+const uint8_t codec_info_opus_capability[AVDT_CODEC_SIZE] = {
+    A2DP_OPUS_CODEC_LEN,         // Length
+    AVDT_MEDIA_TYPE_AUDIO << 4,  // Media Type
+    A2DP_MEDIA_CT_NON_A2DP,      // Media Codec Type Vendor
+    (A2DP_OPUS_VENDOR_ID & 0x000000FF),
+    (A2DP_OPUS_VENDOR_ID & 0x0000FF00) >> 8,
+    (A2DP_OPUS_VENDOR_ID & 0x00FF0000) >> 16,
+    (A2DP_OPUS_VENDOR_ID & 0xFF000000) >> 24,
+    (A2DP_OPUS_CODEC_ID & 0x00FF),
+    (A2DP_OPUS_CODEC_ID & 0xFF00) >> 8,
+    A2DP_OPUS_CHANNEL_MODE_MONO | A2DP_OPUS_CHANNEL_MODE_STEREO |
+        A2DP_OPUS_10MS_FRAMESIZE | A2DP_OPUS_20MS_FRAMESIZE |
+        A2DP_OPUS_SAMPLING_FREQ_48000};
+
+const uint8_t codec_info_opus_sink_capability[AVDT_CODEC_SIZE] = {
+    A2DP_OPUS_CODEC_LEN,         // Length
+    AVDT_MEDIA_TYPE_AUDIO << 4,  // Media Type
+    A2DP_MEDIA_CT_NON_A2DP,      // Media Codec Type Vendor
+    (A2DP_OPUS_VENDOR_ID & 0x000000FF),
+    (A2DP_OPUS_VENDOR_ID & 0x0000FF00) >> 8,
+    (A2DP_OPUS_VENDOR_ID & 0x00FF0000) >> 16,
+    (A2DP_OPUS_VENDOR_ID & 0xFF000000) >> 24,
+    (A2DP_OPUS_CODEC_ID & 0x00FF),
+    (A2DP_OPUS_CODEC_ID & 0xFF00) >> 8,
+    A2DP_OPUS_CHANNEL_MODE_MONO | A2DP_OPUS_CHANNEL_MODE_STEREO |
+        A2DP_OPUS_10MS_FRAMESIZE | A2DP_OPUS_20MS_FRAMESIZE |
+        A2DP_OPUS_SAMPLING_FREQ_48000};
+
 const uint8_t codec_info_non_a2dp[AVDT_CODEC_SIZE] = {
     8,              // Length
     0,              // Media Type: AVDT_MEDIA_TYPE_AUDIO
@@ -265,10 +307,11 @@ class StackA2dpTest : public ::testing::Test {
           supported = has_shared_library(LDAC_DECODER_LIB_NAME);
           break;
         case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
+          break;
         case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
-          // TODO(b/226441860): in-progress
         case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
-          // TODO(b/226441860): in-progress
+          supported = true;
+          break;
         case BTAV_A2DP_CODEC_INDEX_MAX:
           // Needed to avoid using "default:" case so we can capture when
           // a new codec is added, and it can be included here.
@@ -386,6 +429,32 @@ TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
   EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
 }
 
+TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_opus) {
+  ASSERT_TRUE(A2DP_IsVendorSourceCodecValid(codec_info_opus));
+  ASSERT_TRUE(A2DP_IsVendorSourceCodecValid(codec_info_opus_capability));
+  ASSERT_TRUE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus));
+  ASSERT_TRUE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus_capability));
+
+  ASSERT_TRUE(A2DP_IsVendorSinkCodecValid(codec_info_opus_sink_capability));
+  ASSERT_TRUE(A2DP_IsVendorPeerSinkCodecValid(codec_info_opus_sink_capability));
+
+  // Test with invalid Opus configuration
+  uint8_t codec_info_opus_invalid[AVDT_CODEC_SIZE];
+  memcpy(codec_info_opus_invalid, codec_info_opus, sizeof(codec_info_opus));
+  codec_info_opus_invalid[0] = 0;  // Corrupt the Length field
+  ASSERT_FALSE(A2DP_IsVendorSourceCodecValid(codec_info_opus_invalid));
+  ASSERT_FALSE(A2DP_IsVendorSinkCodecValid(codec_info_opus_invalid));
+  ASSERT_FALSE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus_invalid));
+  ASSERT_FALSE(A2DP_IsVendorPeerSinkCodecValid(codec_info_opus_invalid));
+
+  memcpy(codec_info_opus_invalid, codec_info_opus, sizeof(codec_info_opus));
+  codec_info_opus_invalid[1] = 0xff;  // Corrupt the Media Type field
+  ASSERT_FALSE(A2DP_IsVendorSourceCodecValid(codec_info_opus_invalid));
+  ASSERT_FALSE(A2DP_IsVendorSinkCodecValid(codec_info_opus_invalid));
+  ASSERT_FALSE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus_invalid));
+  ASSERT_FALSE(A2DP_IsVendorPeerSinkCodecValid(codec_info_opus_invalid));
+}
+
 TEST_F(StackA2dpTest, test_a2dp_get_codec_type) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(codec_info_sbc);
   EXPECT_EQ(codec_type, A2DP_MEDIA_CT_SBC);
@@ -393,6 +462,9 @@ TEST_F(StackA2dpTest, test_a2dp_get_codec_type) {
   codec_type = A2DP_GetCodecType(codec_info_aac);
   EXPECT_EQ(codec_type, A2DP_MEDIA_CT_AAC);
 
+  codec_type = A2DP_GetCodecType(codec_info_opus);
+  ASSERT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
+
   codec_type = A2DP_GetCodecType(codec_info_non_a2dp);
   EXPECT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
 }
@@ -443,6 +515,9 @@ TEST_F(StackA2dpTest, test_a2dp_uses_rtp_header) {
   EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_aac));
   EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_aac));
 
+  ASSERT_TRUE(A2DP_VendorUsesRtpHeader(true, codec_info_opus));
+  ASSERT_TRUE(A2DP_VendorUsesRtpHeader(false, codec_info_opus));
+
   EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_non_a2dp));
   EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_non_a2dp));
 }
@@ -473,6 +548,9 @@ TEST_F(StackA2dpTest, test_a2dp_codec_name) {
   EXPECT_STREQ(A2DP_CodecName(codec_info_aac), "AAC");
   EXPECT_STREQ(A2DP_CodecName(codec_info_aac_capability), "AAC");
   EXPECT_STREQ(A2DP_CodecName(codec_info_aac_sink_capability), "AAC");
+  ASSERT_STREQ(A2DP_CodecName(codec_info_opus), "Opus");
+  ASSERT_STREQ(A2DP_CodecName(codec_info_opus_capability), "Opus");
+  ASSERT_STREQ(A2DP_CodecName(codec_info_opus_sink_capability), "Opus");
   EXPECT_STREQ(A2DP_CodecName(codec_info_non_a2dp), "UNKNOWN VENDOR CODEC");
 
   // Test all unknown codecs
@@ -496,11 +574,19 @@ TEST_F(StackA2dpTest, test_a2dp_codec_type_equals) {
   EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_capability));
   EXPECT_TRUE(
       A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_sink_capability));
+
   EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_capability));
   EXPECT_TRUE(
       A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_sink_capability));
+
+  ASSERT_TRUE(
+      A2DP_VendorCodecTypeEquals(codec_info_opus, codec_info_opus_capability));
+  ASSERT_TRUE(A2DP_VendorCodecTypeEquals(codec_info_opus,
+                                         codec_info_opus_sink_capability));
+
   EXPECT_TRUE(
       A2DP_CodecTypeEquals(codec_info_non_a2dp, codec_info_non_a2dp_fake));
+
   EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_non_a2dp));
   EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_non_a2dp));
   EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_aac));
@@ -509,6 +595,7 @@ TEST_F(StackA2dpTest, test_a2dp_codec_type_equals) {
 TEST_F(StackA2dpTest, test_a2dp_codec_equals) {
   uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
   uint8_t codec_info_aac_test[AVDT_CODEC_SIZE];
+  uint8_t codec_info_opus_test[AVDT_CODEC_SIZE];
   uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
 
   // Test two identical SBC codecs
@@ -521,6 +608,11 @@ TEST_F(StackA2dpTest, test_a2dp_codec_equals) {
   memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
   EXPECT_TRUE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
 
+  // Test two identical Opus codecs
+  memset(codec_info_opus_test, 0xAB, sizeof(codec_info_opus_test));
+  memcpy(codec_info_opus_test, codec_info_opus, sizeof(codec_info_opus));
+  ASSERT_TRUE(A2DP_VendorCodecEquals(codec_info_opus, codec_info_opus_test));
+
   // Test two identical non-A2DP codecs that are not recognized
   memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
   memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
@@ -529,7 +621,8 @@ TEST_F(StackA2dpTest, test_a2dp_codec_equals) {
 
   // Test two codecs that have different types
   EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_non_a2dp));
-  EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_aac));
+  ASSERT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_aac));
+  ASSERT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_opus));
 
   // Test two SBC codecs that are slightly different
   memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
@@ -567,12 +660,14 @@ TEST_F(StackA2dpTest, test_a2dp_codec_equals) {
 TEST_F(StackA2dpTest, test_a2dp_get_track_sample_rate) {
   EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_sbc), 44100);
   EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_aac), 44100);
+  ASSERT_EQ(A2DP_VendorGetTrackSampleRate(codec_info_opus), 48000);
   EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_track_channel_count) {
   EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_sbc), 2);
   EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_aac), 2);
+  ASSERT_EQ(A2DP_VendorGetTrackChannelCount(codec_info_opus), 2);
   EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_non_a2dp), -1);
 }
 
@@ -625,6 +720,7 @@ TEST_F(StackA2dpTest, test_a2dp_get_max_bitpool_sbc) {
 TEST_F(StackA2dpTest, test_a2dp_get_sink_track_channel_type) {
   EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_sbc), 3);
   EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), 3);
+  ASSERT_EQ(A2DP_VendorGetSinkTrackChannelType(codec_info_opus), 2);
   EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
 }
 
@@ -669,6 +765,13 @@ TEST_F(StackA2dpTest, test_a2dp_get_packet_timestamp) {
   EXPECT_TRUE(A2DP_GetPacketTimestamp(codec_info_aac, a2dp_data, &timestamp));
   EXPECT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
 
+  memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+  *p_ts = 0x12345678;
+  timestamp = 0xFFFFFFFF;
+  ASSERT_TRUE(
+      A2DP_VendorGetPacketTimestamp(codec_info_opus, a2dp_data, &timestamp));
+  ASSERT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
+
   memset(a2dp_data, 0xAB, sizeof(a2dp_data));
   *p_ts = 0x12345678;
   timestamp = 0xFFFFFFFF;
@@ -761,6 +864,12 @@ TEST_F(StackA2dpTest, test_a2dp_source_codec_index) {
             BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
   EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_sink_capability),
             BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+  ASSERT_EQ(A2DP_VendorSourceCodecIndex(codec_info_opus),
+            BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
+  ASSERT_EQ(A2DP_VendorSourceCodecIndex(codec_info_opus_capability),
+            BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
+  ASSERT_EQ(A2DP_VendorSourceCodecIndex(codec_info_opus_sink_capability),
+            BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
   EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_non_a2dp),
             BTAV_A2DP_CODEC_INDEX_MAX);
 }
@@ -779,6 +888,12 @@ TEST_F(StackA2dpTest, test_a2dp_sink_codec_index) {
             BTAV_A2DP_CODEC_INDEX_SINK_AAC);
   EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac_sink_capability),
             BTAV_A2DP_CODEC_INDEX_SINK_AAC);
+  ASSERT_EQ(A2DP_VendorSinkCodecIndex(codec_info_opus),
+            BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
+  ASSERT_EQ(A2DP_VendorSinkCodecIndex(codec_info_opus_capability),
+            BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
+  ASSERT_EQ(A2DP_VendorSinkCodecIndex(codec_info_opus_sink_capability),
+            BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
   EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_non_a2dp),
             BTAV_A2DP_CODEC_INDEX_MAX);
 }
@@ -788,6 +903,10 @@ TEST_F(StackA2dpTest, test_a2dp_codec_index_str) {
   EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC), "SBC");
   EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SINK_SBC), "SBC SINK");
   EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC), "AAC");
+  ASSERT_STREQ(A2DP_VendorCodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS),
+               "Opus");
+  ASSERT_STREQ(A2DP_VendorCodecIndexStr(BTAV_A2DP_CODEC_INDEX_SINK_OPUS),
+               "Opus SINK");
 
   // Test that the unknown codec string has not changed
   EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_MAX),
diff --git a/system/test/headless/Android.bp b/system/test/headless/Android.bp
index 92c6302ccf8..5e009487acf 100644
--- a/system/test/headless/Android.bp
+++ b/system/test/headless/Android.bp
@@ -66,6 +66,7 @@ cc_test {
         "libFraunhoferAAC",
         "libg722codec",
         "liblc3",
+        "libopus",
         "libosi",
         "libprotobuf-cpp-lite",
         "libudrv-uipc",
diff --git a/system/test/suite/Android.bp b/system/test/suite/Android.bp
index c39b1eb2048..30f6f20c0bc 100644
--- a/system/test/suite/Android.bp
+++ b/system/test/suite/Android.bp
@@ -90,6 +90,7 @@ cc_defaults {
         "libg722codec",
         "libgmock",
         "liblc3",
+        "libopus",
         "libosi",
         "libstatslog_bt",
         "libc++fs",
-- 
GitLab