Integration of the AAC codec for A2DP source

Also:
 - Implemented data fragmentation inside bta_av_data_path()
   that is RTP compatible.
 - Do not use the codec_type when composing the RTP payload type
   per RFC 3016, Section 4.2. That value doesn't have actual meaning
   in the context of the Bluetooth supported codecs, and is ambiguous:
   all vendor codecs map to the same value 0xFF.
 - Updated support function A2DP_BitsSet() so it works for
   up to 64-bit integers.
 - Updated a log message inside l2c_data_write() to print
   packet length and peer MTU on error.

Test: A2DP streaming to AAC headsets
Bug: 30958229
Change-Id: I1b530f1c5c495b8231fd68bed788d4567096683d
diff --git a/stack/Android.bp b/stack/Android.bp
index 899407b..f0353cc 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -20,6 +20,8 @@
         "srvc",
     ],
     include_dirs: [
+        "external/aac/libAACenc/include",
+        "external/aac/libSYS/include",
         "external/libldac/inc",
         "system/bt",
         "system/bt/btcore/include",
@@ -34,6 +36,8 @@
         "system/bt/utils/include",
     ],
     srcs: [
+        "a2dp/a2dp_aac.cc",
+        "a2dp/a2dp_aac_encoder.cc",
         "a2dp/a2dp_api.cc",
         "a2dp/a2dp_codec_config.cc",
         "a2dp/a2dp_sbc.cc",
@@ -162,7 +166,10 @@
         "srvc/srvc_dis.cc",
         "srvc/srvc_eng.cc",
     ],
-    static_libs: ["libbt-hci"],
+    static_libs: [
+        "libbt-hci",
+        "libFraunhoferAAC",
+    ],
     shared_libs: [
         "libcutils",
         "liblog",
@@ -191,6 +198,7 @@
     static_libs: [
         "libbt-stack",
         "libbt-sbc-encoder",
+        "libFraunhoferAAC",
         "libosi",
     ],
 }
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
new file mode 100644
index 0000000..23207d0
--- /dev/null
+++ b/stack/a2dp/a2dp_aac.cc
@@ -0,0 +1,1175 @@
+/*
+ * Copyright (C) 2016 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 AAC Codec Information
+ *  Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_aac"
+
+#include "bt_target.h"
+
+#include "a2dp_aac.h"
+
+#include <string.h>
+
+#include <base/logging.h>
+#include "a2dp_aac_encoder.h"
+#include "bt_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define A2DP_AAC_DEFAULT_BITRATE 320000  // 320 kbps
+#define A2DP_AAC_MIN_BITRATE 64000       // 64 kbps
+
+// data type for the AAC Codec Information Element */
+// NOTE: bits_per_sample is needed only for AAC encoder initialization.
+typedef struct {
+  uint8_t objectType;             /* Object Type */
+  uint16_t sampleRate;            /* Sampling Frequency */
+  uint8_t channelMode;            /* STEREO/MONO */
+  uint8_t variableBitRateSupport; /* Variable Bit Rate Support*/
+  uint32_t bitRate;               /* Bit rate */
+  btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+} tA2DP_AAC_CIE;
+
+/* AAC Source codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_caps = {
+    // objectType
+    A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+    // sampleRate
+    (A2DP_AAC_SAMPLING_FREQ_44100 | A2DP_AAC_SAMPLING_FREQ_48000 |
+     A2DP_AAC_SAMPLING_FREQ_88200 | A2DP_AAC_SAMPLING_FREQ_96000),
+    // channelMode
+    A2DP_AAC_CHANNEL_MODE_STEREO,
+    // variableBitRateSupport
+    A2DP_AAC_VARIABLE_BIT_RATE_DISABLED,
+    // bitRate
+    A2DP_AAC_DEFAULT_BITRATE,
+    // bits_per_sample
+    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+
+/* Default AAC codec configuration */
+static const tA2DP_AAC_CIE a2dp_aac_default_config = {
+    A2DP_AAC_OBJECT_TYPE_MPEG2_LC,        // objectType
+    A2DP_AAC_SAMPLING_FREQ_44100,         // sampleRate
+    A2DP_AAC_CHANNEL_MODE_STEREO,         // channelMode
+    A2DP_AAC_VARIABLE_BIT_RATE_DISABLED,  // variableBitRateSupport
+    A2DP_AAC_DEFAULT_BITRATE,             // bitRate
+    BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16    // bits_per_sample
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_aac = {
+    a2dp_aac_encoder_init,
+    a2dp_aac_encoder_cleanup,
+    a2dp_aac_feeding_reset,
+    a2dp_aac_feeding_flush,
+    a2dp_aac_get_encoder_interval_ms,
+    a2dp_aac_send_frames,
+    a2dp_aac_debug_codec_dump};
+
+UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
+    const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
+    bool is_peer_codec_info);
+
+// Builds the AAC 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 AAC 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_BuildInfoAac(uint8_t media_type,
+                                      const tA2DP_AAC_CIE* p_ie,
+                                      uint8_t* p_result) {
+  if (p_ie == NULL || p_result == NULL) {
+    return A2DP_INVALID_PARAMS;
+  }
+
+  *p_result++ = A2DP_AAC_CODEC_LEN;
+  *p_result++ = (media_type << 4);
+  *p_result++ = A2DP_MEDIA_CT_AAC;
+
+  // Object Type
+  if (p_ie->objectType == 0) return A2DP_INVALID_PARAMS;
+  *p_result++ = p_ie->objectType;
+
+  // Sampling Frequency
+  if (p_ie->sampleRate == 0) return A2DP_INVALID_PARAMS;
+  *p_result++ = (uint8_t)(p_ie->sampleRate & A2DP_AAC_SAMPLING_FREQ_MASK0);
+  *p_result = (uint8_t)((p_ie->sampleRate & A2DP_AAC_SAMPLING_FREQ_MASK1) >> 8);
+
+  // Channel Mode
+  if (p_ie->channelMode == 0) return A2DP_INVALID_PARAMS;
+  *p_result++ |= (p_ie->channelMode & A2DP_AAC_CHANNEL_MODE_MASK);
+
+  // Variable Bit Rate Support
+  *p_result = (p_ie->variableBitRateSupport & A2DP_AAC_VARIABLE_BIT_RATE_MASK);
+
+  // Bit Rate
+  *p_result++ |= (uint8_t)((p_ie->bitRate & A2DP_AAC_BIT_RATE_MASK0) >> 16);
+  *p_result++ = (uint8_t)((p_ie->bitRate & A2DP_AAC_BIT_RATE_MASK1) >> 8);
+  *p_result++ = (uint8_t)(p_ie->bitRate & A2DP_AAC_BIT_RATE_MASK2);
+
+  return A2DP_SUCCESS;
+}
+
+// Parses the AAC 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_ParseInfoAac(tA2DP_AAC_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) return A2DP_INVALID_PARAMS;
+
+  // Check the codec capability length
+  losc = *p_codec_info++;
+  if (losc != A2DP_AAC_CODEC_LEN) 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_AAC) {
+    return A2DP_WRONG_CODEC;
+  }
+
+  p_ie->objectType = *p_codec_info++;
+  p_ie->sampleRate = (*p_codec_info & A2DP_AAC_SAMPLING_FREQ_MASK0) |
+                     (*(p_codec_info + 1) << 8 & A2DP_AAC_SAMPLING_FREQ_MASK1);
+  p_codec_info++;
+  p_ie->channelMode = *p_codec_info & A2DP_AAC_CHANNEL_MODE_MASK;
+  p_codec_info++;
+
+  p_ie->variableBitRateSupport =
+      *p_codec_info & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
+
+  p_ie->bitRate = ((*p_codec_info) << 16 & A2DP_AAC_BIT_RATE_MASK0) |
+                  (*(p_codec_info + 1) << 8 & A2DP_AAC_BIT_RATE_MASK1) |
+                  (*(p_codec_info + 2) & A2DP_AAC_BIT_RATE_MASK2);
+  p_codec_info += 3;
+
+  if (is_capability) return A2DP_SUCCESS;
+
+  if (A2DP_BitsSet(p_ie->objectType) != A2DP_SET_ONE_BIT)
+    return A2DP_BAD_OBJ_TYPE;
+  if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
+    return A2DP_BAD_SAMP_FREQ;
+  if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT)
+    return A2DP_BAD_CH_MODE;
+
+  return A2DP_SUCCESS;
+}
+
+bool A2DP_IsSourceCodecValidAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return false;
+}
+
+bool A2DP_IsPeerSourceCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return false;
+}
+
+bool A2DP_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecSupportedAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return false;
+}
+
+bool A2DP_IsPeerSourceCodecSupportedAac(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return false;
+}
+
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(UNUSED_ATTR const uint8_t* p_src_cap,
+                                         UNUSED_ATTR uint8_t* p_pref_cfg) {
+  return A2DP_NS_CODEC_TYPE;
+}
+
+// Checks whether A2DP AAC codec configuration matches with a device's codec
+// capabilities. |p_cap| is the AAC 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_CodecInfoMatchesCapabilityAac(
+    const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
+    bool is_capability) {
+  tA2DP_STATUS status;
+  tA2DP_AAC_CIE cfg_cie;
+
+  /* parse configuration */
+  status = A2DP_ParseInfoAac(&cfg_cie, p_codec_info, is_capability);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+    return status;
+  }
+
+  /* verify that each parameter is in range */
+
+  LOG_DEBUG(LOG_TAG, "%s: Object Type peer: 0x%x, capability 0x%x", __func__,
+            cfg_cie.objectType, p_cap->objectType);
+  LOG_DEBUG(LOG_TAG, "%s: Sample Rate peer: %u, capability %u", __func__,
+            cfg_cie.sampleRate, p_cap->sampleRate);
+  LOG_DEBUG(LOG_TAG, "%s: Channel Mode peer: 0x%x, capability 0x%x", __func__,
+            cfg_cie.channelMode, p_cap->channelMode);
+  LOG_DEBUG(
+      LOG_TAG, "%s: Variable Bit Rate Support peer: 0x%x, capability 0x%x",
+      __func__, cfg_cie.variableBitRateSupport, p_cap->variableBitRateSupport);
+  LOG_DEBUG(LOG_TAG, "%s: Bit Rate peer: %u, capability %u", __func__,
+            cfg_cie.bitRate, p_cap->bitRate);
+
+  /* Object Type */
+  if ((cfg_cie.objectType & p_cap->objectType) == 0) return A2DP_BAD_OBJ_TYPE;
+
+  /* Sample Rate */
+  if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) return A2DP_BAD_SAMP_FREQ;
+
+  /* Channel Mode */
+  if ((cfg_cie.channelMode & p_cap->channelMode) == 0) return A2DP_NS_CH_MODE;
+
+  return A2DP_SUCCESS;
+}
+
+bool A2DP_UsesRtpHeaderAac(UNUSED_ATTR bool content_protection_enabled,
+                           UNUSED_ATTR const uint8_t* p_codec_info) {
+  return true;
+}
+
+const char* A2DP_CodecNameAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return "AAC";
+}
+
+bool A2DP_CodecTypeEqualsAac(const uint8_t* p_codec_info_a,
+                             const uint8_t* p_codec_info_b) {
+  tA2DP_AAC_CIE aac_cie_a;
+  tA2DP_AAC_CIE aac_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoAac(&aac_cie_a, p_codec_info_a, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoAac(&aac_cie_b, p_codec_info_b, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+
+  return true;
+}
+
+bool A2DP_CodecEqualsAac(const uint8_t* p_codec_info_a,
+                         const uint8_t* p_codec_info_b) {
+  tA2DP_AAC_CIE aac_cie_a;
+  tA2DP_AAC_CIE aac_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoAac(&aac_cie_a, p_codec_info_a, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoAac(&aac_cie_b, p_codec_info_b, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+
+  return (aac_cie_a.objectType == aac_cie_b.objectType) &&
+         (aac_cie_a.sampleRate == aac_cie_b.sampleRate) &&
+         (aac_cie_a.channelMode == aac_cie_b.channelMode) &&
+         (aac_cie_a.variableBitRateSupport ==
+          aac_cie_b.variableBitRateSupport) &&
+         (aac_cie_a.bitRate == aac_cie_b.bitRate);
+}
+
+int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (aac_cie.sampleRate) {
+    case A2DP_AAC_SAMPLING_FREQ_8000:
+      return 8000;
+    case A2DP_AAC_SAMPLING_FREQ_11025:
+      return 11025;
+    case A2DP_AAC_SAMPLING_FREQ_12000:
+      return 12000;
+    case A2DP_AAC_SAMPLING_FREQ_16000:
+      return 16000;
+    case A2DP_AAC_SAMPLING_FREQ_22050:
+      return 22050;
+    case A2DP_AAC_SAMPLING_FREQ_24000:
+      return 24000;
+    case A2DP_AAC_SAMPLING_FREQ_32000:
+      return 32000;
+    case A2DP_AAC_SAMPLING_FREQ_44100:
+      return 44100;
+    case A2DP_AAC_SAMPLING_FREQ_48000:
+      return 48000;
+    case A2DP_AAC_SAMPLING_FREQ_64000:
+      return 64000;
+    case A2DP_AAC_SAMPLING_FREQ_88200:
+      return 88200;
+    case A2DP_AAC_SAMPLING_FREQ_96000:
+      return 96000;
+  }
+
+  return -1;
+}
+
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  // NOTE: Hard-coded value - currently the AAC encoder library
+  // is compiled with 16 bits per sample
+  return 16;
+}
+
+int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (aac_cie.channelMode) {
+    case A2DP_AAC_CHANNEL_MODE_MONO:
+      return 1;
+    case A2DP_AAC_CHANNEL_MODE_STEREO:
+      return 2;
+  }
+
+  return -1;
+}
+
+int A2DP_GetSinkTrackChannelTypeAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return -1;
+}
+
+int A2DP_GetSinkFramesCountToProcessAac(
+    UNUSED_ATTR uint64_t time_interval_ms,
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return -1;
+}
+
+int A2DP_GetObjectTypeCodeAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (aac_cie.objectType) {
+    case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+    case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+    case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+    case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+      return aac_cie.objectType;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetChannelModeCodeAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (aac_cie.channelMode) {
+    case A2DP_AAC_CHANNEL_MODE_MONO:
+    case A2DP_AAC_CHANNEL_MODE_STEREO:
+      return aac_cie.channelMode;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetVariableBitRateSupportAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (aac_cie.variableBitRateSupport) {
+    case A2DP_AAC_VARIABLE_BIT_RATE_ENABLED:
+    case A2DP_AAC_VARIABLE_BIT_RATE_DISABLED:
+      return aac_cie.variableBitRateSupport;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetBitRateAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  return aac_cie.bitRate;
+}
+
+bool A2DP_GetPacketTimestampAac(const uint8_t* p_codec_info,
+                                const uint8_t* p_data, uint32_t* p_timestamp) {
+  // TODO: Is this function really codec-specific?
+  *p_timestamp = *(const uint32_t*)p_data;
+  return true;
+}
+
+bool A2DP_BuildCodecHeaderAac(UNUSED_ATTR const uint8_t* p_codec_info,
+                              UNUSED_ATTR BT_HDR* p_buf,
+                              UNUSED_ATTR uint16_t frames_per_packet) {
+  return true;
+}
+
+void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
+  tA2DP_STATUS a2dp_status;
+  tA2DP_AAC_CIE aac_cie;
+
+  LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+  a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAac fail:%d", __func__, a2dp_status);
+    return;
+  }
+
+  LOG_DEBUG(LOG_TAG, "\tobjectType: 0x%x", aac_cie.objectType);
+  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG2_LC) {
+    LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-2 AAC LC)");
+  }
+  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LC) {
+    LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-4 AAC LC)");
+  }
+  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LTP) {
+    LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-4 AAC LTP)");
+  }
+  if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE) {
+    LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-4 AAC Scalable)");
+  }
+
+  LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", aac_cie.sampleRate);
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_8000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (8000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_11025) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (11025)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_12000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (12000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_16000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (16000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_22050) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (22050)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_24000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (24000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_32000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (32000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (44100)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (48000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_64000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (64000)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (88200)");
+  }
+  if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq: (96000)");
+  }
+
+  LOG_DEBUG(LOG_TAG, "\tch_mode: 0x%x", aac_cie.channelMode);
+  if (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_MONO) {
+    LOG_DEBUG(LOG_TAG, "\tch_mode: (Mono)");
+  }
+  if (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_STEREO) {
+    LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
+  }
+
+  LOG_DEBUG(LOG_TAG, "\tvariableBitRateSupport: %s",
+            (aac_cie.variableBitRateSupport != 0) ? "true" : "false");
+
+  LOG_DEBUG(LOG_TAG, "\tbitRate: %u", aac_cie.bitRate);
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsSourceCodecValidAac(p_codec_info)) return NULL;
+
+  return &a2dp_encoder_interface_aac;
+}
+
+bool A2DP_AdjustCodecAac(uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE cfg_cie;
+
+  // Nothing to do: just verify the codec info is valid
+  if (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+    return false;
+
+  return true;
+}
+
+btav_a2dp_codec_index_t A2DP_SourceCodecIndexAac(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  return BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+}
+
+const char* A2DP_CodecIndexStrAac(void) { return "AAC"; }
+
+bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg) {
+  if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_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;
+}
+
+UNUSED_ATTR static void build_codec_config(const tA2DP_AAC_CIE& config_cie,
+                                           btav_a2dp_codec_config_t* result) {
+  if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100)
+    result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+  if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000)
+    result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+  if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200)
+    result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+  if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000)
+    result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+
+  result->bits_per_sample = config_cie.bits_per_sample;
+
+  if (config_cie.channelMode & A2DP_AAC_CHANNEL_MODE_MONO)
+    result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+  if (config_cie.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+    result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+  }
+}
+
+A2dpCodecConfigAac::A2dpCodecConfigAac()
+    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC") {}
+
+A2dpCodecConfigAac::~A2dpCodecConfigAac() {}
+
+bool A2dpCodecConfigAac::init() {
+  if (!isValid()) return false;
+
+  // Load the encoder
+  if (!A2DP_LoadEncoderAac()) {
+    LOG_ERROR(LOG_TAG, "%s: cannot load the encoder", __func__);
+    return false;
+  }
+
+  return true;
+}
+
+//
+// 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(uint16_t sampleRate,
+                                    tA2DP_AAC_CIE* p_result,
+                                    btav_a2dp_codec_config_t* p_codec_config) {
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+    p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_96000;
+    p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+    return true;
+  }
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+    p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_88200;
+    p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+    return true;
+  }
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+    p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_48000;
+    p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+    return true;
+  }
+  if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+    p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+    p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+    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, uint16_t sampleRate,
+    tA2DP_AAC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+  switch (p_codec_audio_config->sample_rate) {
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+        p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+        p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+        p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_48000;
+        p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+        p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_88200;
+        p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+        return true;
+      }
+      break;
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+        p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_96000;
+        p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+        return true;
+      }
+      break;
+    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_AAC_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_AAC_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_AAC_CIE* p_result,
+                                     btav_a2dp_codec_config_t* p_codec_config) {
+  if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+    p_result->channelMode = A2DP_AAC_CHANNEL_MODE_STEREO;
+    p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+    return true;
+  }
+  if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+    p_result->channelMode = A2DP_AAC_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_AAC_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_AAC_CHANNEL_MODE_MONO) {
+        p_result->channelMode = A2DP_AAC_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_AAC_CHANNEL_MODE_STEREO) {
+        p_result->channelMode = A2DP_AAC_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 A2dpCodecConfigAac::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_AAC_CIE sink_info_cie;
+  tA2DP_AAC_CIE result_config_cie;
+  uint8_t channelMode;
+  uint16_t sampleRate;
+  btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+
+  // 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_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_ParseInfoAac(&sink_info_cie, p_peer_codec_info, is_capability);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+              __func__, status);
+    goto fail;
+  }
+
+  //
+  // Build the preferred configuration
+  //
+  memset(&result_config_cie, 0, sizeof(result_config_cie));
+
+  // NOTE: Always assign the Object Type and Variable Bit Rate Support.
+  result_config_cie.objectType = a2dp_aac_caps.objectType;
+  result_config_cie.variableBitRateSupport =
+      a2dp_aac_caps.variableBitRateSupport;
+
+  // Set the bit rate to the smaller of the local and peer bit rate
+  // However, make sure the bit rate doesn't go beyond a certain threshold
+  result_config_cie.bitRate =
+      std::min(a2dp_aac_caps.bitRate, sink_info_cie.bitRate);
+  result_config_cie.bitRate = std::max(
+      result_config_cie.bitRate, static_cast<uint32_t>(A2DP_AAC_MIN_BITRATE));
+
+  //
+  // Select the sample frequency
+  //
+  sampleRate = a2dp_aac_caps.sampleRate & sink_info_cie.sampleRate;
+  codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+  switch (codec_user_config_.sample_rate) {
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+        result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+        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_48000:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+        result_config_cie.sampleRate = A2DP_AAC_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_88200:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+        result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_88200;
+        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_96000:
+      if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+        result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_96000;
+        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_176400:
+    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+    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 {
+    if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+    // Compute the common capability
+    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100)
+      codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000)
+      codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200)
+      codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+    if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000)
+      codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+
+    // 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_aac_default_config.sampleRate & sink_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(LOG_TAG,
+              "%s: cannot match sample frequency: source caps = 0x%x "
+              "sink info = 0x%x",
+              __func__, a2dp_aac_caps.sampleRate, sink_info_cie.sampleRate);
+    goto fail;
+  }
+
+  //
+  // Select the bits per sample
+  //
+  // NOTE: this information is NOT included in the AAC A2DP codec description
+  // that is sent OTA.
+  bits_per_sample = a2dp_aac_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 {
+    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 - the the codec audio config
+    if (select_audio_bits_per_sample(&codec_audio_config_,
+                                     a2dp_aac_caps.bits_per_sample,
+                                     &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - try the default config
+    if (select_best_bits_per_sample(a2dp_aac_default_config.bits_per_sample,
+                                    &result_config_cie, &codec_config_)) {
+      break;
+    }
+
+    // No user preference - use the best match
+    if (select_best_bits_per_sample(a2dp_aac_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(LOG_TAG,
+              "%s: cannot match bits per sample: default = 0x%x "
+              "user preference = 0x%x",
+              __func__, a2dp_aac_default_config.bits_per_sample,
+              codec_user_config_.bits_per_sample);
+    goto fail;
+  }
+
+  //
+  // Select the channel mode
+  //
+  channelMode = a2dp_aac_caps.channelMode & sink_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_AAC_CHANNEL_MODE_MONO) {
+        result_config_cie.channelMode = A2DP_AAC_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_AAC_CHANNEL_MODE_STEREO) {
+        result_config_cie.channelMode = A2DP_AAC_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 {
+    if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+    // Compute the common capability
+    if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO)
+      codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+    if (channelMode & A2DP_AAC_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_aac_default_config.channelMode & sink_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(LOG_TAG,
+              "%s: cannot match channel mode: source caps = 0x%x "
+              "sink info = 0x%x",
+              __func__, a2dp_aac_caps.channelMode, sink_info_cie.channelMode);
+    goto fail;
+  }
+
+  if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+                        p_result_codec_config) != A2DP_SUCCESS) {
+    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_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+                               ota_codec_peer_capability_);
+  } else {
+    status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+                               ota_codec_peer_config_);
+  }
+  CHECK(status == A2DP_SUCCESS);
+  status = A2DP_BuildInfoAac(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_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;
+}
diff --git a/stack/a2dp/a2dp_aac_encoder.cc b/stack/a2dp/a2dp_aac_encoder.cc
new file mode 100644
index 0000000..cdf5156
--- /dev/null
+++ b/stack/a2dp/a2dp_aac_encoder.cc
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2016 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_aac_encoder"
+
+#include "a2dp_aac_encoder.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <aacenc_lib.h>
+#include <base/logging.h>
+
+#include "a2dp_aac.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Encoder for AAC Source Codec
+//
+
+#define STATS_UPDATE_MAX(current_value_storage, new_value) \
+  do {                                                     \
+    if ((new_value) > (current_value_storage))             \
+      (current_value_storage) = (new_value);               \
+  } while (0)
+
+// A2DP AAC encoder interval in milliseconds
+#define A2DP_AAC_ENCODER_INTERVAL_MS 20
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_AAC_OFFSET (AVDT_MEDIA_OFFSET + 1)
+#else
+#define A2DP_AAC_OFFSET AVDT_MEDIA_OFFSET
+#endif
+
+typedef struct {
+  uint32_t sample_rate;
+  uint8_t channel_mode;
+  uint8_t bits_per_sample;
+  uint32_t frame_length;         // Samples per channel in a frame
+  uint8_t input_channels_n;      // Number of channels
+  int max_encoded_buffer_bytes;  // Max encoded bytes per frame
+} tA2DP_AAC_ENCODER_PARAMS;
+
+typedef struct {
+  uint32_t counter;
+  uint32_t bytes_per_tick; /* pcm bytes read each media task tick */
+  uint64_t last_frame_us;
+} tA2DP_AAC_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_aac_encoder_stats_t;
+
+typedef struct {
+  a2dp_source_read_callback_t read_callback;
+  a2dp_source_enqueue_callback_t enqueue_callback;
+  uint16_t TxAaMtuSize;
+
+  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
+
+  HANDLE_AACENCODER aac_handle;
+  bool has_aac_handle;  // True if aac_handle is valid
+
+  tA2DP_FEEDING_PARAMS feeding_params;
+  tA2DP_AAC_ENCODER_PARAMS aac_encoder_params;
+  tA2DP_AAC_FEEDING_STATE aac_feeding_state;
+
+  a2dp_aac_encoder_stats_t stats;
+} tA2DP_AAC_ENCODER_CB;
+
+static tA2DP_AAC_ENCODER_CB a2dp_aac_encoder_cb;
+
+static void a2dp_aac_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_aac_get_num_frame_iteration(uint8_t* num_of_iterations,
+                                             uint8_t* num_of_frames,
+                                             uint64_t timestamp_us);
+static void a2dp_aac_encode_frames(uint8_t nb_frame);
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer);
+
+bool A2DP_LoadEncoderAac(void) {
+  // Nothing to do - the library is statically linked
+  return true;
+}
+
+void A2DP_UnloadEncoderAac(void) {
+  // Nothing to do - the library is statically linked
+  if (a2dp_aac_encoder_cb.has_aac_handle)
+    aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
+  memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
+}
+
+void a2dp_aac_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) {
+  if (a2dp_aac_encoder_cb.has_aac_handle)
+    aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
+  memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
+
+  a2dp_aac_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+  a2dp_aac_encoder_cb.read_callback = read_callback;
+  a2dp_aac_encoder_cb.enqueue_callback = enqueue_callback;
+  a2dp_aac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+  a2dp_aac_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+  a2dp_aac_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+  a2dp_aac_encoder_cb.timestamp = 0;
+
+  a2dp_aac_encoder_cb.use_SCMS_T = false;  // TODO: should be a parameter
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  a2dp_aac_encoder_cb.use_SCMS_T = true;
+#endif
+
+  // 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;
+  a2dp_aac_encoder_update(a2dp_aac_encoder_cb.peer_mtu, a2dp_codec_config,
+                          &restart_input, &restart_output, &config_updated);
+}
+
+bool A2dpCodecConfigAac::updateEncoderUserConfig(
+    const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+    bool* p_restart_output, bool* p_config_updated) {
+  a2dp_aac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+  a2dp_aac_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+  a2dp_aac_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+  a2dp_aac_encoder_cb.timestamp = 0;
+
+  if (a2dp_aac_encoder_cb.peer_mtu == 0) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot update the codec encoder for %s: "
+              "invalid peer MTU",
+              __func__, name().c_str());
+    return false;
+  }
+
+  a2dp_aac_encoder_update(a2dp_aac_encoder_cb.peer_mtu, this, p_restart_input,
+                          p_restart_output, p_config_updated);
+  return true;
+}
+
+// Update the A2DP AAC encoder.
+// |peer_mtu| is the peer MTU.
+// |a2dp_codec_config| is the A2DP codec to use for the update.
+static void a2dp_aac_encoder_update(uint16_t peer_mtu,
+                                    A2dpCodecConfig* a2dp_codec_config,
+                                    bool* p_restart_input,
+                                    bool* p_restart_output,
+                                    bool* p_config_updated) {
+  tA2DP_AAC_ENCODER_PARAMS* p_encoder_params =
+      &a2dp_aac_encoder_cb.aac_encoder_params;
+  uint8_t codec_info[AVDT_CODEC_SIZE];
+  AACENC_ERROR aac_error;
+  int aac_param_value;
+
+  *p_restart_input = false;
+  *p_restart_output = false;
+  *p_config_updated = false;
+
+  if (!a2dp_aac_encoder_cb.has_aac_handle) {
+    AACENC_ERROR aac_error = aacEncOpen(&a2dp_aac_encoder_cb.aac_handle, 0,
+                                        2 /* max 2 channels: stereo */);
+    if (aac_error != AACENC_OK) {
+      LOG_ERROR(LOG_TAG, "%s: Cannot open AAC encoder handle: AAC error 0x%x",
+                __func__, aac_error);
+      return;  // TODO: Return an error?
+    }
+    a2dp_aac_encoder_cb.has_aac_handle = true;
+  }
+
+  if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot update the codec encoder for %s: "
+              "invalid codec config",
+              __func__, a2dp_codec_config->name().c_str());
+    return;
+  }
+  const uint8_t* p_codec_info = codec_info;
+
+  // The feeding parameters
+  tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_aac_encoder_cb.feeding_params;
+  p_feeding_params->sample_rate = A2DP_GetTrackSampleRateAac(p_codec_info);
+  p_feeding_params->bits_per_sample =
+      a2dp_codec_config->getAudioBitsPerSample();
+  p_feeding_params->channel_count = A2DP_GetTrackChannelCountAac(p_codec_info);
+  LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
+            __func__, p_feeding_params->sample_rate,
+            p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+
+  // The codec parameters
+  p_encoder_params->sample_rate =
+      a2dp_aac_encoder_cb.feeding_params.sample_rate;
+  p_encoder_params->channel_mode = A2DP_GetChannelModeCodeAac(p_codec_info);
+
+  uint16_t mtu_size = BT_DEFAULT_BUFFER_SIZE - A2DP_AAC_OFFSET - sizeof(BT_HDR);
+  if (mtu_size < peer_mtu) {
+    a2dp_aac_encoder_cb.TxAaMtuSize = mtu_size;
+  } else {
+    a2dp_aac_encoder_cb.TxAaMtuSize = peer_mtu;
+  }
+
+  LOG_DEBUG(LOG_TAG, "%s: MTU=%d, peer_mtu=%d", __func__,
+            a2dp_aac_encoder_cb.TxAaMtuSize, peer_mtu);
+  LOG_DEBUG(LOG_TAG, "%s: sample_rate: %d channel_mode: %d ", __func__,
+            p_encoder_params->sample_rate, p_encoder_params->channel_mode);
+
+  // Set the encoder's parameters: Audio Object Type - MANDATORY
+  // A2DP_AAC_OBJECT_TYPE_MPEG2_LC -> AOT_AAC_LC
+  // A2DP_AAC_OBJECT_TYPE_MPEG4_LC -> AOT_AAC_LC
+  // A2DP_AAC_OBJECT_TYPE_MPEG4_LTP -> AOT_AAC_LTP
+  // A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE -> AOT_AAC_SCAL
+  aac_param_value = AOT_AAC_LC;
+  int object_type = A2DP_GetObjectTypeCodeAac(p_codec_info);
+  switch (object_type) {
+    case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+      aac_param_value = AOT_AAC_LC;
+      break;
+    case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+      aac_param_value = AOT_AAC_LC;
+      break;
+    case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+      aac_param_value = AOT_AAC_LTP;
+      break;
+    case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+      aac_param_value = AOT_AAC_SCAL;
+      break;
+    default:
+      LOG_ERROR(LOG_TAG,
+                "%s: Cannot set AAC parameter AACENC_AOT: "
+                "invalid object type %d",
+                __func__, object_type);
+      return;  // TODO: Return an error?
+  }
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle, AACENC_AOT,
+                                  aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_AOT to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Set the encoder's parameters: Bit Rate - MANDATORY
+  aac_param_value = A2DP_GetBitRateAac(p_codec_info);
+  if (aac_param_value == -1) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_BITRATE: "
+              "invalid codec bit rate",
+              __func__);
+    return;  // TODO: Return an error?
+  }
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+                                  AACENC_BITRATE, aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_BITRATE to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Set the encoder's parameters: Sample Rate - MANDATORY
+  aac_param_value = A2DP_GetTrackSampleRateAac(p_codec_info);
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+                                  AACENC_SAMPLERATE, aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_SAMPLERATE to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Set the encoder's parameters: Channel Mode - MANDATORY
+  if (A2DP_GetTrackChannelCountAac(p_codec_info) == 1) {
+    aac_param_value = MODE_1;  // Mono
+  } else {
+    aac_param_value = MODE_2;  // Stereo
+  }
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+                                  AACENC_CHANNELMODE, aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_CHANNELMODE to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Set the encoder's parameters: Transport Type
+  aac_param_value = TT_MP4_LATM_MCP1;  // muxConfigPresent = 1
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+                                  AACENC_TRANSMUX, aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_TRANSMUX to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Set the encoder's parameters: Header Period
+  aac_param_value = 1;
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+                                  AACENC_HEADER_PERIOD, aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_HEADER_PERIOD to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Set the encoder's parameters: Variable Bit Rate Support
+  aac_param_value = A2DP_GetVariableBitRateSupportAac(p_codec_info);
+  if (aac_param_value == -1) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_BITRATEMODE: "
+              "invalid codec bit rate mode",
+              __func__);
+    return;  // TODO: Return an error?
+  }
+  aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+                                  AACENC_BITRATEMODE, aac_param_value);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot set AAC parameter AACENC_BITRATEMODE to %d: "
+              "AAC error 0x%x",
+              __func__, aac_param_value, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Mark the end of setting the encoder's parameters
+  aac_error =
+      aacEncEncode(a2dp_aac_encoder_cb.aac_handle, NULL, NULL, NULL, NULL);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot complete setting the AAC parameters: AAC error 0x%x",
+              __func__, aac_error);
+    return;  // TODO: Return an error?
+  }
+
+  // Retrieve the encoder info so we can save the frame length
+  AACENC_InfoStruct aac_info;
+  aac_error = aacEncInfo(a2dp_aac_encoder_cb.aac_handle, &aac_info);
+  if (aac_error != AACENC_OK) {
+    LOG_ERROR(LOG_TAG,
+              "%s: Cannot retrieve the AAC encoder info: AAC error 0x%x",
+              __func__, aac_error);
+    return;  // TODO: Return an error?
+  }
+  p_encoder_params->frame_length = aac_info.frameLength;
+  p_encoder_params->input_channels_n = aac_info.inputChannels;
+  p_encoder_params->max_encoded_buffer_bytes = aac_info.maxOutBufBytes;
+  LOG_DEBUG(LOG_TAG,
+            "%s: AAC frame_length = %u input_channels_n = %u "
+            "max_encoded_buffer_bytes = %d",
+            __func__, p_encoder_params->frame_length,
+            p_encoder_params->input_channels_n,
+            p_encoder_params->max_encoded_buffer_bytes);
+}
+
+void a2dp_aac_encoder_cleanup(void) {
+  if (a2dp_aac_encoder_cb.has_aac_handle)
+    aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
+  memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
+}
+
+void a2dp_aac_feeding_reset(void) {
+  /* By default, just clear the entire state */
+  memset(&a2dp_aac_encoder_cb.aac_feeding_state, 0,
+         sizeof(a2dp_aac_encoder_cb.aac_feeding_state));
+
+  a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick =
+      (a2dp_aac_encoder_cb.feeding_params.sample_rate *
+       a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8 *
+       a2dp_aac_encoder_cb.feeding_params.channel_count *
+       A2DP_AAC_ENCODER_INTERVAL_MS) /
+      1000;
+
+  LOG_DEBUG(LOG_TAG, "%s: PCM bytes per tick %u", __func__,
+            a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick);
+}
+
+void a2dp_aac_feeding_flush(void) {
+  a2dp_aac_encoder_cb.aac_feeding_state.counter = 0;
+}
+
+period_ms_t a2dp_aac_get_encoder_interval_ms(void) {
+  return A2DP_AAC_ENCODER_INTERVAL_MS;
+}
+
+void a2dp_aac_send_frames(uint64_t timestamp_us) {
+  uint8_t nb_frame = 0;
+  uint8_t nb_iterations = 0;
+
+  a2dp_aac_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us);
+  LOG_VERBOSE(LOG_TAG, "%s: Sending %d frames per iteration, %d iterations",
+              __func__, nb_frame, nb_iterations);
+  if (nb_frame == 0) return;
+
+  for (uint8_t counter = 0; counter < nb_iterations; counter++) {
+    // Transcode frame and enqueue
+    a2dp_aac_encode_frames(nb_frame);
+  }
+}
+
+// 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_aac_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_aac_encoder_cb.aac_encoder_params.frame_length *
+      a2dp_aac_encoder_cb.feeding_params.channel_count *
+      a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8;
+  LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__,
+              pcm_bytes_per_frame);
+
+  uint32_t us_this_tick = A2DP_AAC_ENCODER_INTERVAL_MS * 1000;
+  uint64_t now_us = timestamp_us;
+  if (a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us != 0)
+    us_this_tick =
+        (now_us - a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us);
+  a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us = now_us;
+
+  a2dp_aac_encoder_cb.aac_feeding_state.counter +=
+      a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick * us_this_tick /
+      (A2DP_AAC_ENCODER_INTERVAL_MS * 1000);
+
+#if 1
+  result = a2dp_aac_encoder_cb.aac_feeding_state.counter / pcm_bytes_per_frame;
+  a2dp_aac_encoder_cb.aac_feeding_state.counter -= result * pcm_bytes_per_frame;
+  nof = result;
+
+  LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u",
+              __func__, nof, noi);
+
+  *num_of_frames = nof;
+  *num_of_iterations = noi;
+
+#else
+  pcm_bytes_per_frame = 800;
+  result = a2dp_aac_encoder_cb.aac_feeding_state.counter / pcm_bytes_per_frame;
+  nof = result;
+  noi = 1;
+
+  a2dp_aac_encoder_cb.aac_feeding_state.counter -= result * pcm_bytes_per_frame;
+
+  LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u",
+              __func__, nof, noi);
+
+  *num_of_frames = nof;
+  *num_of_iterations = noi;
+
+#endif
+}
+
+static void a2dp_aac_encode_frames(uint8_t nb_frame) {
+  tA2DP_AAC_ENCODER_PARAMS* p_encoder_params =
+      &a2dp_aac_encoder_cb.aac_encoder_params;
+  tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_aac_encoder_cb.feeding_params;
+  uint8_t remain_nb_frame = nb_frame;
+  uint8_t read_buffer[BT_DEFAULT_BUFFER_SIZE];
+  int pcm_bytes_per_frame = p_encoder_params->frame_length *
+                            p_feeding_params->channel_count *
+                            p_feeding_params->bits_per_sample / 8;
+  CHECK(pcm_bytes_per_frame <= static_cast<int>(sizeof(read_buffer)));
+
+  // Setup the input buffer
+  AACENC_BufDesc in_buf_desc;
+  void* in_buf_vector[1] = {nullptr};
+  int in_buf_identifiers[1] = {IN_AUDIO_DATA};
+  int in_buf_sizes[1] = {pcm_bytes_per_frame};
+  int in_buf_element_sizes[1] = {p_feeding_params->bits_per_sample / 8};
+  in_buf_desc.numBufs = 1;
+  in_buf_desc.bufs = in_buf_vector;
+  in_buf_desc.bufferIdentifiers = in_buf_identifiers;
+  in_buf_desc.bufSizes = in_buf_sizes;
+  in_buf_desc.bufElSizes = in_buf_element_sizes;
+
+  // Setup the output buffer (partially)
+  AACENC_BufDesc out_buf_desc;
+  void* out_buf_vector[1] = {nullptr};
+  int out_buf_identifiers[1] = {OUT_BITSTREAM_DATA};
+  int out_buf_sizes[1] = {p_encoder_params->max_encoded_buffer_bytes};
+  // NOTE: out_buf_element_sizes below is probably unused by the encoder
+  int out_buf_element_sizes[1] = {p_feeding_params->bits_per_sample / 8};
+  out_buf_desc.numBufs = 1;
+  out_buf_desc.bufs = out_buf_vector;
+  out_buf_desc.bufferIdentifiers = out_buf_identifiers;
+  out_buf_desc.bufSizes = out_buf_sizes;
+  out_buf_desc.bufElSizes = out_buf_element_sizes;
+  CHECK(p_encoder_params->max_encoded_buffer_bytes <=
+        static_cast<int>(BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR)));
+
+  AACENC_InArgs aac_in_args;
+  aac_in_args.numInSamples =
+      p_encoder_params->frame_length * p_feeding_params->channel_count;
+  aac_in_args.numAncBytes = 0;
+
+  AACENC_OutArgs aac_out_args = {
+      .numOutBytes = 0, .numInSamples = 0, .numAncBytes = 0};
+
+  uint32_t count;
+  int written = 0;
+
+  while (nb_frame) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+
+    /* Init buffer */
+    p_buf->offset = A2DP_AAC_OFFSET;
+    p_buf->len = 0;
+    p_buf->layer_specific = 0;
+
+    count = 0;
+    do {
+      /* Read PCM data */
+      if (a2dp_aac_read_feeding(read_buffer)) {
+        uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
+        if (!a2dp_aac_encoder_cb.has_aac_handle) {
+          LOG_ERROR(LOG_TAG, "%s: invalid AAC handle", __func__);
+          osi_free(p_buf);
+          return;
+        }
+        in_buf_vector[0] = read_buffer;
+        out_buf_vector[0] = packet + count;
+        AACENC_ERROR aac_error =
+            aacEncEncode(a2dp_aac_encoder_cb.aac_handle, &in_buf_desc,
+                         &out_buf_desc, &aac_in_args, &aac_out_args);
+        if (aac_error != AACENC_OK) {
+          LOG_ERROR(LOG_TAG, "%s: AAC encoding error: 0x%x", __func__,
+                    aac_error);
+          osi_free(p_buf);
+          return;
+        }
+        written = aac_out_args.numOutBytes;
+        count += written;
+        p_buf->len += written;
+        nb_frame--;
+        p_buf->layer_specific++;  // added a frame to the buffer
+      } else {
+        LOG_WARN(LOG_TAG, "%s: underflow %d", __func__, nb_frame);
+        a2dp_aac_encoder_cb.aac_feeding_state.counter +=
+            nb_frame * p_encoder_params->frame_length *
+            p_feeding_params->channel_count *
+            p_feeding_params->bits_per_sample / 8;
+
+        // no more pcm to read
+        nb_frame = 0;
+      }
+    } while ((written == 0) && nb_frame);
+
+    // NOTE: We don't check whether the packet will fit in the MTU,
+    // because AAC doesn't give us control over the encoded frame size.
+    // If the packet is larger than the MTU, it will be fragmented before
+    // transmission.
+    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_aac_encoder_cb.timestamp;
+
+      a2dp_aac_encoder_cb.timestamp +=
+          p_buf->layer_specific * p_encoder_params->frame_length;
+
+      uint8_t done_nb_frame = remain_nb_frame - nb_frame;
+      remain_nb_frame = nb_frame;
+      if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+    } else {
+      osi_free(p_buf);
+    }
+  }
+}
+
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer) {
+  uint32_t read_size = a2dp_aac_encoder_cb.aac_encoder_params.frame_length *
+                       a2dp_aac_encoder_cb.feeding_params.channel_count *
+                       a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8;
+
+  /* Read Data from UIPC channel */
+  uint32_t nb_byte_read =
+      a2dp_aac_encoder_cb.read_callback(read_buffer, read_size);
+
+  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;
+  }
+  return true;
+}
+
+void a2dp_aac_debug_codec_dump(int fd) {
+  a2dp_aac_encoder_stats_t* stats = &a2dp_aac_encoder_cb.stats;
+
+  dprintf(fd, "\nA2DP AAC State:\n");
+
+  dprintf(fd,
+          "  Packets expected/dropped                                : %zu / "
+          "%zu\n",
+          stats->media_read_total_expected_packets,
+          stats->media_read_total_dropped_packets);
+
+  dprintf(fd,
+          "  PCM reads count 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);
+}
diff --git a/stack/a2dp/a2dp_api.cc b/stack/a2dp/a2dp_api.cc
index b8fe869..a52924a 100644
--- a/stack/a2dp/a2dp_api.cc
+++ b/stack/a2dp/a2dp_api.cc
@@ -348,16 +348,10 @@
  *                  A2DP_SET_ZERO_BIT, if all bits clear
  *                  A2DP_SET_MULTL_BIT, if multiple bits are set
  *****************************************************************************/
-uint8_t A2DP_BitsSet(uint8_t num) {
-  uint8_t count;
-  uint8_t res;
-  if (num == 0)
-    res = A2DP_SET_ZERO_BIT;
-  else {
-    count = (num & (num - 1));
-    res = ((count == 0) ? A2DP_SET_ONE_BIT : A2DP_SET_MULTL_BIT);
-  }
-  return res;
+uint8_t A2DP_BitsSet(uint64_t num) {
+  if (num == 0) return A2DP_SET_ZERO_BIT;
+  if ((num & (num - 1)) == 0) return A2DP_SET_ONE_BIT;
+  return A2DP_SET_MULTL_BIT;
 }
 
 /*******************************************************************************
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 69659ce..fb86eee 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -24,6 +24,7 @@
 
 #include <base/logging.h>
 
+#include "a2dp_aac.h"
 #include "a2dp_sbc.h"
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx.h"
@@ -85,6 +86,9 @@
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
       codec_config = new A2dpCodecConfigSbcSink();
       break;
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      codec_config = new A2dpCodecConfigAac();
+      break;
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       codec_config = new A2dpCodecConfigAptx();
       break;
@@ -550,6 +554,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_IsSourceCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_IsSourceCodecValidAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_IsVendorSourceCodecValid(p_codec_info);
     default:
@@ -567,6 +573,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_IsSinkCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_IsSinkCodecValidAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_IsVendorSinkCodecValid(p_codec_info);
     default:
@@ -584,6 +592,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_IsPeerSourceCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_IsPeerSourceCodecValidAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_IsVendorPeerSourceCodecValid(p_codec_info);
     default:
@@ -601,6 +611,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_IsPeerSinkCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_IsPeerSinkCodecValidAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_IsVendorPeerSinkCodecValid(p_codec_info);
     default:
@@ -618,6 +630,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_IsSinkCodecSupportedSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_IsSinkCodecSupportedAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_IsVendorSinkCodecSupported(p_codec_info);
     default:
@@ -636,6 +650,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_IsPeerSourceCodecSupportedSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_IsPeerSourceCodecSupportedAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_IsVendorPeerSourceCodecSupported(p_codec_info);
     default:
@@ -659,6 +675,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_BuildSrc2SinkConfigSbc(p_src_cap, p_pref_cfg);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_BuildSrc2SinkConfigAac(p_src_cap, p_pref_cfg);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorBuildSrc2SinkConfig(p_src_cap, p_pref_cfg);
     default:
@@ -691,6 +709,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_CodecNameSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_CodecNameAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorCodecName(p_codec_info);
     default:
@@ -711,6 +731,8 @@
   switch (codec_type_a) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_CodecTypeEqualsSbc(p_codec_info_a, p_codec_info_b);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_CodecTypeEqualsAac(p_codec_info_a, p_codec_info_b);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorCodecTypeEquals(p_codec_info_a, p_codec_info_b);
     default:
@@ -731,6 +753,8 @@
   switch (codec_type_a) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_CodecEqualsSbc(p_codec_info_a, p_codec_info_b);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_CodecEqualsAac(p_codec_info_a, p_codec_info_b);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorCodecEquals(p_codec_info_a, p_codec_info_b);
     default:
@@ -749,6 +773,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetTrackSampleRateSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetTrackSampleRateAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetTrackSampleRate(p_codec_info);
     default:
@@ -767,6 +793,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetTrackBitsPerSampleAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetTrackBitsPerSample(p_codec_info);
     default:
@@ -785,6 +813,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetTrackChannelCountSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetTrackChannelCountAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetTrackChannelCount(p_codec_info);
     default:
@@ -803,6 +833,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetSinkTrackChannelTypeSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetSinkTrackChannelTypeAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetSinkTrackChannelType(p_codec_info);
     default:
@@ -823,6 +855,9 @@
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetSinkFramesCountToProcessSbc(time_interval_ms,
                                                  p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetSinkFramesCountToProcessAac(time_interval_ms,
+                                                 p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetSinkFramesCountToProcess(time_interval_ms,
                                                     p_codec_info);
@@ -841,6 +876,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetPacketTimestampSbc(p_codec_info, p_data, p_timestamp);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetPacketTimestampAac(p_codec_info, p_data, p_timestamp);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetPacketTimestamp(p_codec_info, p_data, p_timestamp);
     default:
@@ -858,6 +895,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_BuildCodecHeaderSbc(p_codec_info, p_buf, frames_per_packet);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_BuildCodecHeaderAac(p_codec_info, p_buf, frames_per_packet);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorBuildCodecHeader(p_codec_info, p_buf,
                                          frames_per_packet);
@@ -878,6 +917,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_GetEncoderInterfaceSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetEncoderInterfaceAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorGetEncoderInterface(p_codec_info);
     default:
@@ -894,6 +935,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_AdjustCodecSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_AdjustCodecAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorAdjustCodec(p_codec_info);
     default:
@@ -912,6 +955,8 @@
   switch (codec_type) {
     case A2DP_MEDIA_CT_SBC:
       return A2DP_SourceCodecIndexSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_SourceCodecIndexAac(p_codec_info);
     case A2DP_MEDIA_CT_NON_A2DP:
       return A2DP_VendorSourceCodecIndex(p_codec_info);
     default:
@@ -928,6 +973,8 @@
       return A2DP_CodecIndexStrSbc();
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
       return A2DP_CodecIndexStrSbcSink();
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      return A2DP_CodecIndexStrAac();
     default:
       break;
   }
@@ -952,6 +999,8 @@
       return A2DP_InitCodecConfigSbc(p_cfg);
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
       return A2DP_InitCodecConfigSbcSink(p_cfg);
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      return A2DP_InitCodecConfigAac(p_cfg);
     default:
       break;
   }
diff --git a/stack/a2dp/a2dp_vendor.cc b/stack/a2dp/a2dp_vendor.cc
index a49d76f..e1d88b1 100644
--- a/stack/a2dp/a2dp_vendor.cc
+++ b/stack/a2dp/a2dp_vendor.cc
@@ -532,7 +532,8 @@
   switch (codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
-      break;  // This is not a vendor-specific codec
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      break;  // These are not vendor-specific codecs
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       return A2DP_VendorCodecIndexStrAptx();
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
@@ -553,7 +554,8 @@
   switch (codec_index) {
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
-      break;  // This is not a vendor-specific codec
+    case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+      break;  // These are not vendor-specific codecs
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       return A2DP_VendorInitCodecConfigAptx(p_cfg);
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
diff --git a/stack/include/a2dp_aac.h b/stack/include/a2dp_aac.h
new file mode 100644
index 0000000..42483c6
--- /dev/null
+++ b/stack/include/a2dp_aac.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 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 AAC
+//
+
+#ifndef A2DP_AAC_H
+#define A2DP_AAC_H
+
+#include "a2dp_aac_constants.h"
+#include "a2dp_codec_api.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigAac : public A2dpCodecConfig {
+ public:
+  A2dpCodecConfigAac();
+  virtual ~A2dpCodecConfigAac();
+
+  bool init() override;
+  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+                      uint8_t* p_result_codec_config) override;
+
+ private:
+  bool updateEncoderUserConfig(
+      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+      bool* p_restart_input, bool* p_restart_output,
+      bool* p_config_updated) override;
+};
+
+// Checks whether the codec capabilities contain a valid A2DP AAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC
+// codec, otherwise false.
+bool A2DP_IsSourceCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP AAC Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC codec,
+// otherwise false.
+bool A2DP_IsSinkCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP AAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC codec,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP AAC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC
+// codec, otherwise false.
+bool A2DP_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether A2DP AAC Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP AAC Sink codec is supported, otherwise false.
+bool A2DP_IsSinkCodecSupportedAac(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP AAC 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 AAC Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedAac(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_UsesRtpHeaderAac(bool content_protection_enabled,
+                           const uint8_t* p_codec_info);
+
+// Builds A2DP preferred AAC Sink capability from AAC Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(const uint8_t* p_src_cap,
+                                         uint8_t* p_pref_cfg);
+
+// Gets the A2DP AAC codec name for a given |p_codec_info|.
+const char* A2DP_CodecNameAac(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP AAC 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_CodecTypeEqualsAac(const uint8_t* p_codec_info_a,
+                             const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP AAC 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 AAC, the return value is false.
+bool A2DP_CodecEqualsAac(const uint8_t* p_codec_info_a,
+                         const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP AAC Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// AAC sink codec. |time_interval_ms| is the time interval (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkFramesCountToProcessAac(uint64_t time_interval_ms,
+                                        const uint8_t* p_codec_info);
+
+// Gets the object type code for the A2DP AAC codec.
+// The actual value is codec-specific - see |A2DP_AAC_OBJECT_TYPE_*|.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the object type code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetObjectTypeCodeAac(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP AAC codec.
+// The actual value is codec-specific - see |A2DP_AAC_CHANNEL_MODE_*|.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetChannelModeCodeAac(const uint8_t* p_codec_info);
+
+// Gets the variable bit rate support for the A2DP AAC codec.
+// The actual value is codec-specific - see |A2DP_AAC_VARIABLE_BIT_RATE_*|.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the variable bit rate support on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetVariableBitRateSupportAac(const uint8_t* p_codec_info);
+
+// Gets the bit rate for the A2DP AAC codec.
+// The actual value is codec-specific - for AAC it is in bits per second.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the bit rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetBitRateAac(const uint8_t* p_codec_info);
+
+// Gets the A2DP AAC 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_GetPacketTimestampAac(const uint8_t* p_codec_info,
+                                const uint8_t* p_data, uint32_t* p_timestamp);
+
+// Builds A2DP AAC 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_BuildCodecHeaderAac(const uint8_t* p_codec_info, BT_HDR* p_buf,
+                              uint16_t frames_per_packet);
+
+// Decodes and displays AAC codec info (for debugging).
+// |p_codec_info| is a pointer to the AAC codec_info to decode and display.
+void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info);
+
+// Gets the A2DP AAC 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 AAC encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
+    const uint8_t* p_codec_info);
+
+// Adjusts the A2DP AAC 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_AdjustCodecAac(uint8_t* p_codec_info);
+
+// Gets the A2DP AAC 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_SourceCodecIndexAac(const uint8_t* p_codec_info);
+
+// Gets the A2DP AAC Source codec name.
+const char* A2DP_CodecIndexStrAac(void);
+
+// Initializes A2DP AAC Source codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg);
+
+#endif  // A2DP_AAC_H
diff --git a/stack/include/a2dp_aac_constants.h b/stack/include/a2dp_aac_constants.h
new file mode 100644
index 0000000..6102f92
--- /dev/null
+++ b/stack/include/a2dp_aac_constants.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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 AAC codec
+//
+
+#ifndef A2DP_AAC_CONSTANTS_H
+#define A2DP_AAC_CONSTANTS_H
+
+// AAC codec specific settings
+#define A2DP_AAC_CODEC_LEN 8
+
+// [Octet 0] Object Type
+#define A2DP_AAC_OBJECT_TYPE_MPEG2_LC 0x80  /* MPEG-2 Low Complexity */
+#define A2DP_AAC_OBJECT_TYPE_MPEG4_LC 0x40  /* MPEG-4 Low Complexity */
+#define A2DP_AAC_OBJECT_TYPE_MPEG4_LTP 0x20 /* MPEG-4 Long Term Prediction */
+#define A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE 0x10
+// [Octet 1] Sampling Frequency - 8000 to 44100
+#define A2DP_AAC_SAMPLING_FREQ_MASK0 0xFF
+#define A2DP_AAC_SAMPLING_FREQ_8000 0x80
+#define A2DP_AAC_SAMPLING_FREQ_11025 0x40
+#define A2DP_AAC_SAMPLING_FREQ_12000 0x20
+#define A2DP_AAC_SAMPLING_FREQ_16000 0x10
+#define A2DP_AAC_SAMPLING_FREQ_22050 0x08
+#define A2DP_AAC_SAMPLING_FREQ_24000 0x04
+#define A2DP_AAC_SAMPLING_FREQ_32000 0x02
+#define A2DP_AAC_SAMPLING_FREQ_44100 0x01
+// [Octet 2], [Bits 4-7] Sampling Frequency - 48000 to 96000
+// NOTE: Bits offset for the higher-order octet 16-bit integer
+#define A2DP_AAC_SAMPLING_FREQ_MASK1 (0xF0 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_48000 (0x80 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_64000 (0x40 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_88200 (0x20 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_96000 (0x10 << 8)
+// [Octet 2], [Bits 2-3] Channel Mode
+#define A2DP_AAC_CHANNEL_MODE_MASK 0x0C
+#define A2DP_AAC_CHANNEL_MODE_MONO 0x08
+#define A2DP_AAC_CHANNEL_MODE_STEREO 0x04
+// [Octet 2], [Bits 0-1] RFA
+// [Octet 3], [Bit 7] Variable Bit Rate Supported
+#define A2DP_AAC_VARIABLE_BIT_RATE_MASK 0x80
+#define A2DP_AAC_VARIABLE_BIT_RATE_ENABLED 0x80
+#define A2DP_AAC_VARIABLE_BIT_RATE_DISABLED 0x00
+// [Octet 3], [Bits 0-6] Bit Rate - Bits 16-22 in the 23-bit UiMsbf
+#define A2DP_AAC_BIT_RATE_MASK0 (0x7F << 16)
+#define A2DP_AAC_BIT_RATE_MASK1 (0xFF << 8)
+#define A2DP_AAC_BIT_RATE_MASK2 0xFF
+// [Octet 4], [Bits 0-7] Bit Rate - Bits 8-15 in the 23-bit UiMsfb
+// [Octet 5], [Bits 0-7] Bit Rate - Bits 0-7 in the 23-bit UiMsfb
+
+#endif  // A2DP_AAC_CONSTANTS_H
diff --git a/stack/include/a2dp_aac_encoder.h b/stack/include/a2dp_aac_encoder.h
new file mode 100644
index 0000000..d07a9a5
--- /dev/null
+++ b/stack/include/a2dp_aac_encoder.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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 AAC Encoder
+//
+
+#ifndef A2DP_AAC_ENCODER_H
+#define A2DP_AAC_ENCODER_H
+
+#include "a2dp_codec_api.h"
+#include "osi/include/time.h"
+
+// Loads the A2DP AAC encoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadEncoderAac(void);
+
+// Unloads the A2DP AAC encoder.
+void A2DP_UnloadEncoderAac(void);
+
+// Initialize the A2DP AAC 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_aac_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 AAC encoder.
+void a2dp_aac_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP AAC encoder.
+void a2dp_aac_feeding_reset(void);
+
+// Flush the feeding for the A2DP AAC encoder.
+void a2dp_aac_feeding_flush(void);
+
+// Get the A2DP AAC encoder interval (in milliseconds).
+period_ms_t a2dp_aac_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP AAC encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_aac_send_frames(uint64_t timestamp_us);
+
+// Dump AAC codec-related statistics.
+// |fd| is the file descriptor to use to dump the statistics information
+// in user-friendly test format.
+void a2dp_aac_debug_codec_dump(int fd);
+
+#endif  // A2DP_AAC_ENCODER_H
diff --git a/stack/include/a2dp_api.h b/stack/include/a2dp_api.h
index 2a27de5..c4ab737 100644
--- a/stack/include/a2dp_api.h
+++ b/stack/include/a2dp_api.h
@@ -191,7 +191,7 @@
  *                  A2DP_SET_ZERO_BIT, if all bits clear
  *                  A2DP_SET_MULTL_BIT, if multiple bits are set
  *****************************************************************************/
-extern uint8_t A2DP_BitsSet(uint8_t num);
+extern uint8_t A2DP_BitsSet(uint64_t num);
 
 // Initializes the A2DP control block.
 void A2DP_Init(void);
diff --git a/stack/include/a2dp_constants.h b/stack/include/a2dp_constants.h
index f49a7a2..479d9e4 100644
--- a/stack/include/a2dp_constants.h
+++ b/stack/include/a2dp_constants.h
@@ -37,8 +37,8 @@
 #define A2DP_SUPF_AMP 0x0008
 
 /* AV Media Codec Types (Audio Codec ID) */
-/* SBC media codec type */
-#define A2DP_MEDIA_CT_SBC 0x00
+#define A2DP_MEDIA_CT_SBC 0x00 /* SBC media codec type */
+#define A2DP_MEDIA_CT_AAC 0x02 /* AAC media codec type */
 /* Non-A2DP media codec type (vendor-specific codec) */
 #define A2DP_MEDIA_CT_NON_A2DP 0xFF
 
diff --git a/stack/l2cap/l2c_main.cc b/stack/l2cap/l2c_main.cc
index 4d69eac..8a39383 100644
--- a/stack/l2cap/l2c_main.cc
+++ b/stack/l2cap/l2c_main.cc
@@ -876,8 +876,9 @@
 
   if (p_data->len > mtu) {
     L2CAP_TRACE_WARNING(
-        "L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size",
-        cid);
+        "L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size: "
+        "len=%u mtu=%u",
+        cid, p_data->len, mtu);
     osi_free(p_data);
     return (L2CAP_DW_FAILED);
   }
diff --git a/stack/test/stack_a2dp_test.cc b/stack/test/stack_a2dp_test.cc
index 8c3653e..305a240 100644
--- a/stack/test/stack_a2dp_test.cc
+++ b/stack/test/stack_a2dp_test.cc
@@ -22,6 +22,7 @@
 
 #include <gtest/gtest.h>
 
+#include "stack/include/a2dp_aac.h"
 #include "stack/include/a2dp_api.h"
 #include "stack/include/a2dp_codec_api.h"
 #include "stack/include/a2dp_sbc.h"
@@ -73,6 +74,71 @@
     9                 // Dummy
 };
 
+const uint8_t codec_info_aac[AVDT_CODEC_SIZE] = {
+    8,           // Length (A2DP_AAC_INFO_LEN)
+    0,           // Media Type: AVDT_MEDIA_TYPE_AUDIO
+    2,           // Media Codec Type: A2DP_MEDIA_CT_AAC
+    0x80,        // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
+    0x01,        // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
+    0x04,        // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
+    0x00 | 0x4,  // Variable Bit Rate:
+                 // A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
+                 // Bit Rate: 320000 = 0x4e200
+    0xe2,        // Bit Rate: 320000 = 0x4e200
+    0x00,        // Bit Rate: 320000 = 0x4e200
+    7,           // Dummy
+    8,           // Dummy
+    9            // Dummy
+};
+
+const uint8_t codec_info_aac_capability[AVDT_CODEC_SIZE] = {
+    8,     // Length (A2DP_AAC_INFO_LEN)
+    0,     // Media Type: AVDT_MEDIA_TYPE_AUDIO
+    2,     // Media Codec Type: A2DP_MEDIA_CT_AAC
+    0x80,  // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
+    0x01,  // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
+    0x80 | 0x20 | 0x10 | 0x04,  // Sampling Frequency:
+                                // A2DP_AAC_SAMPLING_FREQ_48000 |
+                                // A2DP_AAC_SAMPLING_FREQ_88200 |
+                                // A2DP_AAC_SAMPLING_FREQ_96000 |
+                                // Channels:
+                                // A2DP_AAC_CHANNEL_MODE_STEREO
+    0x00 | 0x4,                 // Variable Bit Rate:
+                                // A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
+                                // Bit Rate: 320000 = 0x4e200
+    0xe2,                       // Bit Rate: 320000 = 0x4e200
+    0x00,                       // Bit Rate: 320000 = 0x4e200
+    7,                          // Dummy
+    8,                          // Dummy
+    9                           // Dummy
+};
+
+const uint8_t codec_info_aac_sink_capability[AVDT_CODEC_SIZE] = {
+    8,                          // Length (A2DP_AAC_INFO_LEN)
+    0,                          // Media Type: AVDT_MEDIA_TYPE_AUDIO
+    2,                          // Media Codec Type: A2DP_MEDIA_CT_AAC
+    0x80 | 0x40 | 0x20 | 0x10,  // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC |
+                                // A2DP_AAC_OBJECT_TYPE_MPEG4_LC
+                                // A2DP_AAC_OBJECT_TYPE_MPEG4_LTP
+                                // A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE
+    0x01,  // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
+    0x80 | 0x20 | 0x10 | 0x08 | 0x04,  // Sampling Frequency:
+                                       // A2DP_AAC_SAMPLING_FREQ_48000 |
+                                       // A2DP_AAC_SAMPLING_FREQ_88200 |
+                                       // A2DP_AAC_SAMPLING_FREQ_96000 |
+                                       // Channels:
+                                       // A2DP_AAC_CHANNEL_MODE_MONO |
+                                       // A2DP_AAC_CHANNEL_MODE_STEREO
+    0x80 | 0x4,                        // Variable Bit Rate:
+                                       // A2DP_AAC_VARIABLE_BIT_RATE_ENABLED
+                                       // Bit Rate: 320000 = 0x4e200
+    0xe2,                              // Bit Rate: 320000 = 0x4e200
+    0x00,                              // Bit Rate: 320000 = 0x4e200
+    7,                                 // Dummy
+    8,                                 // Dummy
+    9                                  // Dummy
+};
+
 const uint8_t codec_info_non_a2dp[AVDT_CODEC_SIZE] = {
     8,              // Length
     0,              // Media Type: AVDT_MEDIA_TYPE_AUDIO
@@ -120,6 +186,9 @@
         case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
           supported = true;
           break;
+        case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+          supported = true;
+          break;
         case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
           // Codec aptX is supported only if the device has the corresponding
           // shared library installed.
@@ -168,10 +237,27 @@
   EXPECT_TRUE(A2DP_BitsSet(0x7f) == A2DP_SET_MULTL_BIT);
   EXPECT_TRUE(A2DP_BitsSet(0x80) == A2DP_SET_ONE_BIT);
   EXPECT_TRUE(A2DP_BitsSet(0x81) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xc0) == A2DP_SET_MULTL_BIT);
   EXPECT_TRUE(A2DP_BitsSet(0xff) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x8000) == A2DP_SET_ONE_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x8001) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xc000) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xffff) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x80000) == A2DP_SET_ONE_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x80001) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xc0000) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xfffff) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x80000000) == A2DP_SET_ONE_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x80000001) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xc0000000) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xffffffff) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x8000000000000000) == A2DP_SET_ONE_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0x8000000000000001) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xc000000000000000) == A2DP_SET_MULTL_BIT);
+  EXPECT_TRUE(A2DP_BitsSet(0xffffffffffffffff) == A2DP_SET_MULTL_BIT);
 }
 
-TEST_F(StackA2dpTest, test_a2dp_is_codec_valid) {
+TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_sbc) {
   EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc));
   EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc));
 
@@ -206,10 +292,35 @@
   EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
 }
 
+TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
+  EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
+  EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_capability));
+  EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
+
+  // Test with invalid AAC codecs
+  uint8_t codec_info_aac_invalid[AVDT_CODEC_SIZE];
+  memset(codec_info_aac_invalid, 0, sizeof(codec_info_aac_invalid));
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
+
+  memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
+  codec_info_aac_invalid[0] = 0;  // Corrupt the Length field
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
+
+  memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
+  codec_info_aac_invalid[1] = 0xff;  // Corrupt the Media Type field
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_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);
 
+  codec_type = A2DP_GetCodecType(codec_info_aac);
+  EXPECT_EQ(codec_type, A2DP_MEDIA_CT_AAC);
+
   codec_type = A2DP_GetCodecType(codec_info_non_a2dp);
   EXPECT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
 }
@@ -217,12 +328,22 @@
 TEST_F(StackA2dpTest, test_a2dp_is_sink_codec_supported) {
   EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_sbc));
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_sink_capability));
+
+  EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac));
+  EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
+  EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_sink_capability));
+
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
 }
 
 TEST_F(StackA2dpTest, test_a2dp_is_peer_source_codec_supported) {
   EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc));
   EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_sink_capability));
+
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
+
   EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
 }
 
@@ -249,7 +370,7 @@
     EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
   }
 
-  // Include extra (less preferred) capabilities and test again
+  // Include extra (less preferred) capabilities and test again - SBC
   uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
   memcpy(codec_info_sbc_test1, codec_info_sbc, sizeof(codec_info_sbc));
   codec_info_sbc_test1[3] |= (A2DP_SBC_IE_CH_MD_STEREO |
@@ -266,6 +387,10 @@
     EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
   }
 
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  EXPECT_NE(A2DP_BuildSrc2SinkConfig(codec_info_aac, codec_info_result),
+            A2DP_SUCCESS);
+
   // Test invalid codec info
   memset(codec_info_result, 0, sizeof(codec_info_result));
   memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
@@ -276,6 +401,10 @@
 TEST_F(StackA2dpTest, test_a2dp_uses_rtp_header) {
   EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_sbc));
   EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_sbc));
+
+  EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_aac));
+  EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_aac));
+
   EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_non_a2dp));
   EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_non_a2dp));
 }
@@ -284,6 +413,7 @@
   uint8_t codec_info_test[AVDT_CODEC_SIZE];
 
   EXPECT_EQ(A2DP_GetMediaType(codec_info_sbc), AVDT_MEDIA_TYPE_AUDIO);
+  EXPECT_EQ(A2DP_GetMediaType(codec_info_aac), AVDT_MEDIA_TYPE_AUDIO);
   EXPECT_EQ(A2DP_GetMediaType(codec_info_non_a2dp), AVDT_MEDIA_TYPE_AUDIO);
 
   // Prepare dummy codec info for video and for multimedia
@@ -301,11 +431,14 @@
   // Explicit tests for known codecs
   EXPECT_STREQ(A2DP_CodecName(codec_info_sbc), "SBC");
   EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_sink_capability), "SBC");
+  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");
   EXPECT_STREQ(A2DP_CodecName(codec_info_non_a2dp), "UNKNOWN VENDOR CODEC");
 
   // Test all unknown codecs
   memcpy(codec_info_test, codec_info_sbc, sizeof(codec_info_sbc));
-  for (uint8_t codec_type = A2DP_MEDIA_CT_SBC + 1;
+  for (uint8_t codec_type = A2DP_MEDIA_CT_AAC + 1;
        codec_type < A2DP_MEDIA_CT_NON_A2DP; codec_type++) {
     codec_info_test[2] = codec_type;  // Unknown codec type
     EXPECT_STREQ(A2DP_CodecName(codec_info_test), "UNKNOWN CODEC");
@@ -323,13 +456,19 @@
 TEST_F(StackA2dpTest, test_a2dp_codec_type_equals) {
   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));
   EXPECT_TRUE(
       A2DP_CodecTypeEquals(codec_info_non_a2dp, codec_info_non_a2dp_dummy));
   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));
 }
 
 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_non_a2dp_test[AVDT_CODEC_SIZE];
 
   // Test two identical SBC codecs
@@ -337,6 +476,11 @@
   memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
   EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
 
+  // Test two identical AAC codecs
+  memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+  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 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,
@@ -345,6 +489,7 @@
 
   // 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));
 
   // Test two SBC codecs that are slightly different
   memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
@@ -355,76 +500,128 @@
   codec_info_sbc_test[6] = codec_info_sbc[6] + 1;
   EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
 
+  // Test two AAC codecs that are slightly different
+  memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+  memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+  codec_info_aac_test[7] = codec_info_aac[7] + 1;
+  EXPECT_FALSE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
+  codec_info_aac_test[7] = codec_info_aac[7];
+  codec_info_aac_test[8] = codec_info_aac[8] + 1;
+  EXPECT_FALSE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
+
   // Test two SBC codecs that are identical, but with different dummy
   // trailer data.
   memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
   memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
   codec_info_sbc_test[7] = codec_info_sbc[7] + 1;
   EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+
+  // Test two AAC codecs that are identical, but with different dummy
+  // trailer data.
+  memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+  memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+  codec_info_aac_test[9] = codec_info_aac[9] + 1;
+  EXPECT_TRUE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
 }
 
 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);
   EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_track_bits_per_sample) {
   EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_sbc), 16);
+  EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_aac), 16);
   EXPECT_EQ(A2DP_GetTrackBitsPerSample(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);
   EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_number_of_subbands_sbc) {
   EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_sbc), 8);
+  EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_number_of_blocks_sbc) {
   EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_sbc), 16);
+  EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_allocation_method_code_sbc) {
   EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_sbc), 0);
+  EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_channel_mode_code_sbc) {
   EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_sbc), 3);
+  EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_sampling_frequency_code_sbc) {
   EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_sbc), 2);
+  EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_min_bitpool_sbc) {
   EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc), 2);
   EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc_sink_capability), 2);
+  EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_max_bitpool_sbc) {
   EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc), 53);
   EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc_sink_capability), 53);
+  EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_non_a2dp), -1);
 }
 
 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), -1);
   EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
 }
 
 TEST_F(StackA2dpTest, test_a2dp_get_sink_frames_count_to_process) {
   EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_sbc), 7);
+  EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_aac), -1);
   EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_non_a2dp), -1);
 }
 
+TEST_F(StackA2dpTest, test_a2dp_get_object_type_code_aac) {
+  EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_sbc), -1);
+  EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_aac), 0x80);
+  EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_channel_mode_code_aac) {
+  EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_sbc), -1);
+  EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_aac), 0x04);
+  EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_variable_bit_rate_support_aac) {
+  EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_sbc), -1);
+  EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_aac), 0);
+  EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_bit_rate_aac) {
+  EXPECT_EQ(A2DP_GetBitRateAac(codec_info_sbc), -1);
+  EXPECT_EQ(A2DP_GetBitRateAac(codec_info_aac), 320000);
+  EXPECT_EQ(A2DP_GetBitRateAac(codec_info_non_a2dp), -1);
+}
+
 TEST_F(StackA2dpTest, test_a2dp_get_packet_timestamp) {
   uint8_t a2dp_data[1000];
   uint32_t timestamp;
@@ -439,6 +636,12 @@
   memset(a2dp_data, 0xAB, sizeof(a2dp_data));
   *p_ts = 0x12345678;
   timestamp = 0xFFFFFFFF;
+  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;
   EXPECT_FALSE(
       A2DP_GetPacketTimestamp(codec_info_non_a2dp, a2dp_data, &timestamp));
 }
@@ -465,12 +668,18 @@
   memset(a2dp_data, 0xAB, sizeof(a2dp_data));
   p_buf->len = BT_HDR_LEN;
   p_buf->offset = BT_HDR_OFFSET;
+  EXPECT_TRUE(A2DP_BuildCodecHeader(codec_info_aac, p_buf, FRAMES_PER_PACKET));
+
+  memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+  p_buf->len = BT_HDR_LEN;
+  p_buf->offset = BT_HDR_OFFSET;
   EXPECT_FALSE(
       A2DP_BuildCodecHeader(codec_info_non_a2dp, p_buf, FRAMES_PER_PACKET));
 }
 
 TEST_F(StackA2dpTest, test_a2dp_adjust_codec) {
   uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
+  uint8_t codec_info_aac_test[AVDT_CODEC_SIZE];
   uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
 
   // Test updating a valid SBC codec that doesn't need adjustment
@@ -494,6 +703,13 @@
   codec_info_sbc_test[6] = 255;  // Invalid MAX_BITPOOL
   EXPECT_FALSE(A2DP_AdjustCodec(codec_info_sbc_test));
 
+  // Test updating a valid AAC codec that doesn't need adjustment
+  memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+  memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+  EXPECT_TRUE(A2DP_AdjustCodec(codec_info_aac_test));
+  EXPECT_TRUE(
+      memcmp(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac)) == 0);
+
   // Test updating a non-A2DP codec that is 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,
@@ -507,6 +723,12 @@
             BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
   EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_sink_capability),
             BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+  EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac),
+            BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+  EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_capability),
+            BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+  EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_sink_capability),
+            BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
   EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_non_a2dp),
             BTAV_A2DP_CODEC_INDEX_MAX);
 }
@@ -515,6 +737,7 @@
   // Explicit tests for known codecs
   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");
 
   // Test that the unknown codec string has not changed
   EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_MAX),
@@ -558,6 +781,24 @@
   for (size_t i = 0; i < codec_info_sbc_sink_capability[0] + 1; i++) {
     EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_sink_capability[i]);
   }
+
+  //
+  // Test for AAC Source
+  //
+  memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+  EXPECT_TRUE(
+      A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, &avdt_cfg));
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_aac_capability[0] + 1; i++) {
+    EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_aac_capability[i]);
+  }
+// Test for content protection
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  EXPECT_EQ(avdt_cfg.protect_info[0], AVDT_CP_LOSC);
+  EXPECT_EQ(avdt_cfg.protect_info[1], (AVDT_CP_SCMS_T_ID & 0xFF));
+  EXPECT_EQ(avdt_cfg.protect_info[2], ((AVDT_CP_SCMS_T_ID >> 8) & 0xFF));
+  EXPECT_EQ(avdt_cfg.num_protect, 1);
+#endif
 }
 
 TEST_F(A2dpCodecConfigTest, createCodec) {
@@ -587,7 +828,7 @@
 
   EXPECT_TRUE(a2dp_codecs->init());
 
-  // Create the codec capability
+  // Create the codec capability - SBC
   memset(codec_info_result, 0, sizeof(codec_info_result));
   peer_codec_index = A2DP_SourceCodecIndex(codec_info_sbc_sink_capability);
   EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
@@ -602,7 +843,22 @@
     EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
   }
 
-  // Create the codec config
+  // Create the codec capability - AAC
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac_sink_capability);
+  EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+  codec_config =
+      a2dp_codecs->findSourceCodecConfig(codec_info_aac_sink_capability);
+  EXPECT_NE(codec_config, nullptr);
+  EXPECT_TRUE(a2dp_codecs->setCodecConfig(codec_info_aac_sink_capability, true,
+                                          codec_info_result));
+  EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
+  }
+
+  // Create the codec config - SBC
   memset(codec_info_result, 0, sizeof(codec_info_result));
   peer_codec_index = A2DP_SourceCodecIndex(codec_info_sbc);
   EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
@@ -616,6 +872,20 @@
     EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
   }
 
+  // Create the codec config - AAC
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac);
+  EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+  codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_aac);
+  EXPECT_NE(codec_config, nullptr);
+  EXPECT_TRUE(
+      a2dp_codecs->setCodecConfig(codec_info_aac, false, codec_info_result));
+  EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
+  }
+
   // Test invalid codec info
   uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
   memset(codec_info_result, 0, sizeof(codec_info_result));