Merge "test_vendor: Extract DeviceProperties"
diff --git a/btcore/src/device_class.cc b/btcore/src/device_class.cc
index 1538ef6..911eeee 100644
--- a/btcore/src/device_class.cc
+++ b/btcore/src/device_class.cc
@@ -21,7 +21,6 @@
 #include <string.h>
 
 #include "btcore/include/device_class.h"
-#include "osi/include/osi.h"
 
 typedef struct _bt_device_class_t {
   uint32_t unused : 2;  // LSBs
@@ -35,7 +34,9 @@
 
 // Ensure the internal device class implementation and public one
 // have equal size.
-COMPILE_ASSERT(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t));
+static_assert(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t),
+              "Internal and external device class implementation should have "
+              "the same size");
 
 // [Major Service Classes]
 // (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 1f1d7da..2b86bea 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -1051,6 +1051,19 @@
   return encoder_interface;
 }
 
+const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) {
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_lock();
+
+  const tA2DP_DECODER_INTERFACE* decoder_interface =
+      A2DP_GetDecoderInterface(bta_av_co_cb.codec_config);
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_unlock();
+
+  return decoder_interface;
+}
+
 bool bta_av_co_set_codec_user_config(
     const btav_a2dp_codec_config_t& codec_user_config) {
   uint8_t result_codec_config[AVDT_CODEC_SIZE];
diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h
index caa90e9..00fd5b9 100644
--- a/btif/include/btif_av_co.h
+++ b/btif/include/btif_av_co.h
@@ -37,6 +37,12 @@
 // otherwise NULL.
 const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);
 
+// Gets the current A2DP decoder interface that can be used to decode received
+// A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// Returns the A2DP decoder interface if the current codec is setup, otherwise
+// NULL.
+const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void);
+
 // Sets the user preferred codec configuration.
 // |codec_user_config| contains the preferred codec configuration.
 // Returns true on success, otherwise false.
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index 6e0c577..0a64f43 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -19,7 +19,9 @@
 
 #define LOG_TAG "bt_btif_a2dp_sink"
 
-#include <string.h>
+#include <atomic>
+#include <cstring>
+#include <mutex>
 
 #include "bt_common.h"
 #include "btif_a2dp.h"
@@ -33,8 +35,7 @@
 #include "osi/include/osi.h"
 #include "osi/include/thread.h"
 
-#include "oi_codec_sbc.h"
-#include "oi_status.h"
+using LockGuard = std::lock_guard<std::mutex>;
 
 /**
  * The receiving queue buffer size.
@@ -71,13 +72,6 @@
   btif_a2dp_sink_focus_state_t focus_state;
 } tBTIF_MEDIA_SINK_FOCUS_UPDATE;
 
-typedef struct {
-  uint16_t num_frames_to_be_processed;
-  uint16_t len;
-  uint16_t offset;
-  uint16_t layer_specific;
-} tBT_SBC_HDR;
-
 /* BTIF A2DP Sink control block */
 typedef struct {
   thread_t* worker_thread;
@@ -85,22 +79,19 @@
   fixed_queue_t* rx_audio_queue;
   bool rx_flush; /* discards any incoming data when true */
   alarm_t* decode_alarm;
-  uint8_t frames_to_process;
   tA2DP_SAMPLE_RATE sample_rate;
   tA2DP_CHANNEL_COUNT channel_count;
   btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
   void* audio_track;
+  const tA2DP_DECODER_INTERFACE* decoder_interface;
 } tBTIF_A2DP_SINK_CB;
 
+// Mutex for below data structures.
+static std::mutex g_mutex;
+
 static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
 
-static int btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
-
-static OI_CODEC_SBC_DECODER_CONTEXT btif_a2dp_sink_context;
-static uint32_t btif_a2dp_sink_context_data[CODEC_DATA_WORDS(
-    2, SBC_CODEC_FAST_FILTER_BUFFERS)];
-static int16_t
-    btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};
 
 static void btif_a2dp_sink_startup_delayed(void* context);
 static void btif_a2dp_sink_shutdown_delayed(void* context);
@@ -111,7 +102,7 @@
 static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
 static void btif_a2dp_sink_audio_rx_flush_req(void);
 /* Handle incoming media packets A2DP SINK streaming */
-static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg);
+static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg);
 static void btif_a2dp_sink_decoder_update_event(
     tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
 static void btif_a2dp_sink_clear_track_event(void);
@@ -133,6 +124,8 @@
 }
 
 bool btif_a2dp_sink_startup(void) {
+  LockGuard lock(g_mutex);
+
   if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
     APPL_TRACE_ERROR("%s: A2DP Sink media task already running", __func__);
     return false;
@@ -176,30 +169,41 @@
 }
 
 void btif_a2dp_sink_shutdown(void) {
-  if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
-      (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
-    return;
+  alarm_t* decode_alarm;
+  fixed_queue_t* cmd_msg_queue;
+  thread_t* worker_thread;
+  {
+    LockGuard lock(g_mutex);
+    if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
+        (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
+      return;
+    }
+    /* Make sure no channels are restarted while shutting down */
+    btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
+
+    APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
+
+    decode_alarm = btif_a2dp_sink_cb.decode_alarm;
+    btif_a2dp_sink_cb.decode_alarm = NULL;
+
+    cmd_msg_queue = btif_a2dp_sink_cb.cmd_msg_queue;
+    btif_a2dp_sink_cb.cmd_msg_queue = NULL;
+
+    worker_thread = btif_a2dp_sink_cb.worker_thread;
+    btif_a2dp_sink_cb.worker_thread = NULL;
   }
 
-  /* Make sure no channels are restarted while shutting down */
-  btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
-
-  APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
-
   // Stop the timer
-  alarm_free(btif_a2dp_sink_cb.decode_alarm);
-  btif_a2dp_sink_cb.decode_alarm = NULL;
+  alarm_free(decode_alarm);
 
   // Exit the thread
-  fixed_queue_free(btif_a2dp_sink_cb.cmd_msg_queue, NULL);
-  btif_a2dp_sink_cb.cmd_msg_queue = NULL;
-  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
-              NULL);
-  thread_free(btif_a2dp_sink_cb.worker_thread);
-  btif_a2dp_sink_cb.worker_thread = NULL;
+  fixed_queue_free(cmd_msg_queue, NULL);
+  thread_post(worker_thread, btif_a2dp_sink_shutdown_delayed, NULL);
+  thread_free(worker_thread);
 }
 
 static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+  LockGuard lock(g_mutex);
   fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL);
   btif_a2dp_sink_cb.rx_audio_queue = NULL;
 
@@ -207,10 +211,12 @@
 }
 
 tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void) {
+  LockGuard lock(g_mutex);
   return btif_a2dp_sink_cb.sample_rate;
 }
 
 tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void) {
+  LockGuard lock(g_mutex);
   return btif_a2dp_sink_cb.channel_count;
 }
 
@@ -283,17 +289,31 @@
 }
 
 static void btif_a2dp_sink_audio_handle_stop_decoding(void) {
-  btif_a2dp_sink_cb.rx_flush = true;
-  btif_a2dp_sink_audio_rx_flush_req();
+  alarm_t* old_alarm;
+  {
+    LockGuard lock(g_mutex);
+    btif_a2dp_sink_cb.rx_flush = true;
+    btif_a2dp_sink_audio_rx_flush_req();
+    old_alarm = btif_a2dp_sink_cb.decode_alarm;
+    btif_a2dp_sink_cb.decode_alarm = NULL;
+  }
 
-  alarm_free(btif_a2dp_sink_cb.decode_alarm);
-  btif_a2dp_sink_cb.decode_alarm = NULL;
+  // Drop the lock here, btif_decode_alarm_cb may in the process of being called
+  // while we alarm free leading to deadlock.
+  //
+  // alarm_free waits for btif_decode_alarm_cb which is waiting for g_mutex.
+  alarm_free(old_alarm);
+
+  {
+    LockGuard lock(g_mutex);
 #ifndef OS_GENERIC
-  BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
+    BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
 #endif
+  }
 }
 
 static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
+  LockGuard lock(g_mutex);
   if (btif_a2dp_sink_cb.worker_thread != NULL) {
     thread_post(btif_a2dp_sink_cb.worker_thread,
                 btif_a2dp_sink_avk_handle_timer, NULL);
@@ -301,6 +321,7 @@
 }
 
 static void btif_a2dp_sink_clear_track_event(void) {
+  LockGuard lock(g_mutex);
   APPL_TRACE_DEBUG("%s", __func__);
 
 #ifndef OS_GENERIC
@@ -310,6 +331,7 @@
   btif_a2dp_sink_cb.audio_track = NULL;
 }
 
+// Must be called while locked.
 static void btif_a2dp_sink_audio_handle_start_decoding(void) {
   if (btif_a2dp_sink_cb.decode_alarm != NULL)
     return;  // Already started decoding
@@ -327,54 +349,31 @@
             btif_decode_alarm_cb, NULL);
 }
 
-static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
-  uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
-  int count;
-  uint32_t pcmBytes, availPcmBytes;
-  int16_t* pcmDataPointer =
-      btif_a2dp_sink_pcm_data; /* Will be overwritten on next packet receipt */
-  OI_STATUS status;
-  int num_sbc_frames = p_msg->num_frames_to_be_processed;
-  uint32_t sbc_frame_len = p_msg->len - 1;
-  availPcmBytes = sizeof(btif_a2dp_sink_pcm_data);
+static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) {
+#ifndef OS_GENERIC
+  BtifAvrcpAudioTrackWriteData(btif_a2dp_sink_cb.audio_track,
+                               reinterpret_cast<void*>(data), len);
+#endif
+}
 
+// Must be called while locked.
+static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg) {
   if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
       (btif_a2dp_sink_cb.rx_flush)) {
     APPL_TRACE_DEBUG("State Changed happened in this tick");
     return;
   }
 
-  APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
-                   num_sbc_frames, sbc_frame_len);
-
-  for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count++) {
-    pcmBytes = availPcmBytes;
-    status = OI_CODEC_SBC_DecodeFrame(
-        &btif_a2dp_sink_context, (const OI_BYTE**)&sbc_start_frame,
-        (uint32_t*)&sbc_frame_len, (int16_t*)pcmDataPointer,
-        (uint32_t*)&pcmBytes);
-    if (!OI_SUCCESS(status)) {
-      APPL_TRACE_ERROR("%s: Decoding failure: %d", __func__, status);
-      break;
-    }
-    availPcmBytes -= pcmBytes;
-    pcmDataPointer += pcmBytes / 2;
-    p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
-    p_msg->len = sbc_frame_len + 1;
+  CHECK(btif_a2dp_sink_cb.decoder_interface);
+  if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
+    APPL_TRACE_ERROR("%s Decoding failed!", __func__);
   }
-
-#ifndef OS_GENERIC
-  BtifAvrcpAudioTrackWriteData(
-      btif_a2dp_sink_cb.audio_track, (void*)btif_a2dp_sink_pcm_data,
-      (sizeof(btif_a2dp_sink_pcm_data) - availPcmBytes));
-#endif
 }
 
 static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
-  tBT_SBC_HDR* p_msg;
-  int num_sbc_frames;
-  int num_frames_to_process;
+  LockGuard lock(g_mutex);
 
+  BT_HDR* p_msg;
   if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
     APPL_TRACE_DEBUG("%s: empty queue", __func__);
     return;
@@ -392,42 +391,20 @@
     return;
   }
 
-  num_frames_to_process = btif_a2dp_sink_cb.frames_to_process;
   APPL_TRACE_DEBUG(" Process Frames + ");
 
-  do {
-    p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
-        btif_a2dp_sink_cb.rx_audio_queue);
-    if (p_msg == NULL) return;
-    /* Number of frames in queue packets */
-    num_sbc_frames = p_msg->num_frames_to_be_processed;
-    APPL_TRACE_DEBUG("Frames left in topmost packet %d", num_sbc_frames);
-    APPL_TRACE_DEBUG("Remaining frames to process in tick %d",
-                     num_frames_to_process);
+  while (true) {
+    p_msg = (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
+    if (p_msg == NULL) {
+      break;
+    }
     APPL_TRACE_DEBUG("Number of packets in queue %d",
                      fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));
 
-    if (num_sbc_frames > num_frames_to_process) {
-      /* Queue packet has more frames */
-      p_msg->num_frames_to_be_processed = num_frames_to_process;
-      btif_a2dp_sink_handle_inc_media(p_msg);
-      p_msg->num_frames_to_be_processed =
-          num_sbc_frames - num_frames_to_process;
-      num_frames_to_process = 0;
-      break;
-    }
     /* Queue packet has less frames */
     btif_a2dp_sink_handle_inc_media(p_msg);
-    p_msg =
-        (tBT_SBC_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
-    if (p_msg == NULL) {
-      APPL_TRACE_ERROR("Insufficient data in queue");
-      break;
-    }
-    num_frames_to_process =
-        num_frames_to_process - p_msg->num_frames_to_be_processed;
     osi_free(p_msg);
-  } while (num_frames_to_process > 0);
+  }
 
   APPL_TRACE_DEBUG("Process Frames - ");
 }
@@ -435,11 +412,14 @@
 /* when true media task discards any rx frames */
 void btif_a2dp_sink_set_rx_flush(bool enable) {
   APPL_TRACE_EVENT("## DROP RX %d ##", enable);
+  LockGuard lock(g_mutex);
+
   btif_a2dp_sink_cb.rx_flush = enable;
 }
 
 static void btif_a2dp_sink_audio_rx_flush_event(void) {
-  /* Flush all received SBC buffers (encoded) */
+  LockGuard lock(g_mutex);
+  /* Flush all received encoded audio buffers */
   APPL_TRACE_DEBUG("%s", __func__);
 
   fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
@@ -447,8 +427,7 @@
 
 static void btif_a2dp_sink_decoder_update_event(
     tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
-  OI_STATUS status;
-
+  LockGuard lock(g_mutex);
   APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
                    p_buf->codec_info[1], p_buf->codec_info[2],
                    p_buf->codec_info[3], p_buf->codec_info[4],
@@ -474,15 +453,21 @@
 
   btif_a2dp_sink_cb.rx_flush = false;
   APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
-  status = OI_CODEC_SBC_DecoderReset(
-      &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
-      sizeof(btif_a2dp_sink_context_data), 2, 2, false);
-  if (!OI_SUCCESS(status)) {
-    APPL_TRACE_ERROR("%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
-                     __func__, status);
+
+  btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
+  if (btif_a2dp_sink_cb.decoder_interface == NULL) {
+    APPL_TRACE_ERROR("%s: Cannot stream audio: no source decoder interface",
+                     __func__);
+    return;
   }
 
-  APPL_TRACE_DEBUG("%s: A2dpSink: SBC create track", __func__);
+  if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
+          btif_a2dp_sink_on_decode_complete)) {
+    APPL_TRACE_ERROR("%s: A2dpSink: Failed to initialize decoder", __func__);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("%s: A2dpSink: create audio track", __func__);
   btif_a2dp_sink_cb.audio_track =
 #ifndef OS_GENERIC
       BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
@@ -493,18 +478,10 @@
     APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
     return;
   }
-
-  btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
-      BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
-  APPL_TRACE_DEBUG("%s: Frames to be processed in 20 ms %d", __func__,
-                   btif_a2dp_sink_cb.frames_to_process);
-  if (btif_a2dp_sink_cb.frames_to_process == 0) {
-    APPL_TRACE_ERROR("%s: Cannot compute the number of frames to process",
-                     __func__);
-  }
 }
 
 uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
+  LockGuard lock(g_mutex);
   if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */
     return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
 
@@ -517,17 +494,11 @@
 
   BTIF_TRACE_VERBOSE("%s +", __func__);
   /* Allocate and queue this buffer */
-  tBT_SBC_HDR* p_msg = reinterpret_cast<tBT_SBC_HDR*>(
-      osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len));
-  memcpy((uint8_t*)(p_msg + 1), (uint8_t*)(p_pkt + 1) + p_pkt->offset,
-         p_pkt->len);
-  p_msg->num_frames_to_be_processed =
-      (*((uint8_t*)(p_pkt + 1) + p_pkt->offset)) & 0x0f;
-  p_msg->len = p_pkt->len;
+  BT_HDR* p_msg =
+      reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(*p_msg) + p_pkt->len));
+  memcpy(p_msg, p_pkt, sizeof(*p_msg));
   p_msg->offset = 0;
-  p_msg->layer_specific = p_pkt->layer_specific;
-  BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__,
-                     p_msg->num_frames_to_be_processed, p_msg->len);
+  memcpy(p_msg->data, p_pkt->data + p_pkt->offset, p_pkt->len);
   fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
   if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
       MAX_A2DP_DELAYED_START_FRAME_COUNT) {
@@ -567,6 +538,7 @@
 
 static void btif_a2dp_sink_set_focus_state_event(
     btif_a2dp_sink_focus_state_t state) {
+  LockGuard lock(g_mutex);
   if (!btif_av_is_connected()) return;
   APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
   btif_a2dp_sink_cb.rx_focus_state = state;
@@ -580,6 +552,7 @@
 
 void btif_a2dp_sink_set_audio_track_gain(float gain) {
   APPL_TRACE_DEBUG("%s set gain to %f", __func__, gain);
+  LockGuard lock(g_mutex);
 #ifndef OS_GENERIC
   BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain);
 #endif
diff --git a/build/Android.bp b/build/Android.bp
index 79fbccc..53d461d 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -46,7 +46,6 @@
 fluoride_defaults {
     name: "fluoride_defaults",
     defaults: ["fluoride_types_defaults"],
-    compile_multilib: "first",
     header_libs: ["libbluetooth_headers"],
     static_libs: [
         "libbluetooth-types",
diff --git a/hci/src/btsnoop.cc b/hci/src/btsnoop.cc
index f44713e..9812b61 100644
--- a/hci/src/btsnoop.cc
+++ b/hci/src/btsnoop.cc
@@ -200,7 +200,7 @@
   get_btsnoop_log_path(log_path);
   get_btsnoop_last_log_path(last_log_path, log_path);
 
-  if (!rename(log_path, last_log_path) && errno != ENOENT)
+  if (rename(log_path, last_log_path) != 0 && errno != ENOENT)
     LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
               log_path, last_log_path, strerror(errno));
 
diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h
index fac1aa4..7326c10 100644
--- a/include/hardware/bt_av.h
+++ b/include/hardware/bt_av.h
@@ -61,6 +61,7 @@
 
   // Add an entry for each sink codec here
   BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
+  BTAV_A2DP_CODEC_INDEX_SINK_AAC,
 
   BTAV_A2DP_CODEC_INDEX_SINK_MAX,
 
diff --git a/osi/include/osi.h b/osi/include/osi.h
index 3c5b5fb..a39d56c 100644
--- a/osi/include/osi.h
+++ b/osi/include/osi.h
@@ -35,15 +35,6 @@
 #define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c)
 #define DUMMY_PTR DUMMY_COUNTER(__COUNTER__)
 
-// base/macros.h defines a COMPILE_ASSERT macro to the C++11 keyword
-// "static_assert" (it undef's COMPILE_ASSERT before redefining it).
-// C++ code that includes base and osi/include/osi.h can thus easily default to
-// the definition from libbase but we should check here to avoid compile errors.
-#ifndef COMPILE_ASSERT
-#define COMPILE_ASSERT(COND) \
-  typedef int failed_compile_assert[(COND) ? 1 : -1] __attribute__((unused))
-#endif  // COMPILE_ASSERT
-
 // Macros for safe integer to pointer conversion. In the C language, data is
 // commonly cast to opaque pointer containers and back for generic parameter
 // passing in callbacks. These macros should be used sparingly in new code
diff --git a/stack/Android.bp b/stack/Android.bp
index 11b2e19..213da1c 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -24,6 +24,7 @@
     ],
     include_dirs: [
         "external/aac/libAACenc/include",
+        "external/aac/libAACdec/include",
         "external/aac/libSYS/include",
         "external/libldac/inc",
         "external/libldac/abr/inc",
@@ -41,10 +42,12 @@
     ],
     srcs: [
         "a2dp/a2dp_aac.cc",
+        "a2dp/a2dp_aac_decoder.cc",
         "a2dp/a2dp_aac_encoder.cc",
         "a2dp/a2dp_api.cc",
         "a2dp/a2dp_codec_config.cc",
         "a2dp/a2dp_sbc.cc",
+        "a2dp/a2dp_sbc_decoder.cc",
         "a2dp/a2dp_sbc_encoder.cc",
         "a2dp/a2dp_sbc_up_sample.cc",
         "a2dp/a2dp_vendor.cc",
@@ -201,6 +204,7 @@
     ],
     static_libs: [
         "libbt-stack",
+        "libbt-sbc-decoder",
         "libbt-sbc-encoder",
         "libFraunhoferAAC",
         "libosi",
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 68ae811..6f3c55a 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -17,10 +17,12 @@
 static_library("stack") {
   sources = [
     "a2dp/a2dp_aac.cc",
+    "a2dp/a2dp_aac_decoder.cc",
     "a2dp/a2dp_aac_encoder.cc",
     "a2dp/a2dp_api.cc",
     "a2dp/a2dp_codec_config.cc",
     "a2dp/a2dp_sbc.cc",
+    "a2dp/a2dp_sbc_decoder.cc",
     "a2dp/a2dp_sbc_encoder.cc",
     "a2dp/a2dp_sbc_up_sample.cc",
     "a2dp/a2dp_vendor.cc",
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
index 65badeb..9bb67ea 100644
--- a/stack/a2dp/a2dp_aac.cc
+++ b/stack/a2dp/a2dp_aac.cc
@@ -30,6 +30,7 @@
 #include <string.h>
 
 #include <base/logging.h>
+#include "a2dp_aac_decoder.h"
 #include "a2dp_aac_encoder.h"
 #include "bt_utils.h"
 #include "osi/include/log.h"
@@ -65,6 +66,21 @@
     // bits_per_sample
     BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
 
+/* AAC Sink codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_sink_caps = {
+    // objectType
+    A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+    // sampleRate
+    A2DP_AAC_SAMPLING_FREQ_44100 | A2DP_AAC_SAMPLING_FREQ_48000,
+    // channelMode
+    A2DP_AAC_CHANNEL_MODE_MONO | A2DP_AAC_CHANNEL_MODE_STEREO,
+    // variableBitRateSupport
+    A2DP_AAC_VARIABLE_BIT_RATE_ENABLED,
+    // 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
@@ -85,9 +101,14 @@
     nullptr  // set_transmit_queue_length
 };
 
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_aac = {
+    a2dp_aac_decoder_init, a2dp_aac_decoder_cleanup,
+    a2dp_aac_decoder_decode_packet,
+};
+
 UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
     const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
-    bool is_peer_codec_info);
+    bool is_capability);
 
 // Builds the AAC Media Codec Capabilities byte sequence beginning from the
 // LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
@@ -191,11 +212,19 @@
 }
 
 bool A2DP_IsSinkCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
+  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_IsPeerSourceCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
+  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_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info) {
@@ -206,13 +235,14 @@
          (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_IsSinkCodecSupportedAac(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+                                            false) == A2DP_SUCCESS;
 }
 
-bool A2DP_IsPeerSourceCodecSupportedAac(
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  return false;
+bool A2DP_IsPeerSourceCodecSupportedAac(const uint8_t* p_codec_info) {
+  return A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+                                            true) == A2DP_SUCCESS;
 }
 
 tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(UNUSED_ATTR const uint8_t* p_src_cap,
@@ -222,11 +252,8 @@
 
 // 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.
+// the device's codec capabilities. |is_capability| is true if
+// |p_codec_info| contains A2DP codec capability.
 // Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
 // otherwise the corresponding A2DP error status code.
 static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
@@ -390,13 +417,24 @@
   return -1;
 }
 
-int A2DP_GetSinkTrackChannelTypeAac(UNUSED_ATTR const uint8_t* p_codec_info) {
-  return -1;
-}
+int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info) {
+  tA2DP_AAC_CIE aac_cie;
 
-int A2DP_GetSinkFramesCountToProcessAac(
-    UNUSED_ATTR uint64_t time_interval_ms,
-    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // 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 3;
+  }
+
   return -1;
 }
 
@@ -616,6 +654,13 @@
   return &a2dp_encoder_interface_aac;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceAac(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsSinkCodecValidAac(p_codec_info)) return NULL;
+
+  return &a2dp_decoder_interface_aac;
+}
+
 bool A2DP_AdjustCodecAac(uint8_t* p_codec_info) {
   tA2DP_AAC_CIE cfg_cie;
 
@@ -633,6 +678,8 @@
 
 const char* A2DP_CodecIndexStrAac(void) { return "AAC"; }
 
+const char* A2DP_CodecIndexStrAacSink(void) { return "AAC SINK"; }
+
 bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg) {
   if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_caps,
                         p_cfg->codec_info) != A2DP_SUCCESS) {
@@ -650,6 +697,11 @@
   return true;
 }
 
+bool A2DP_InitCodecConfigAacSink(tAVDT_CFG* p_cfg) {
+  return A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_sink_caps,
+                           p_cfg->codec_info) == A2DP_SUCCESS;
+}
+
 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)
@@ -672,7 +724,8 @@
 
 A2dpCodecConfigAac::A2dpCodecConfigAac(
     btav_a2dp_codec_priority_t codec_priority)
-    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC", codec_priority) {
+    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, A2DP_CodecIndexStrAac(),
+                      codec_priority) {
   // Compute the local capability
   if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
     codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1263,3 +1316,48 @@
          sizeof(ota_codec_peer_config_));
   return false;
 }
+
+A2dpCodecConfigAacSink::A2dpCodecConfigAacSink(
+    btav_a2dp_codec_priority_t codec_priority)
+    : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_AAC,
+                      A2DP_CodecIndexStrAacSink(), codec_priority) {}
+
+A2dpCodecConfigAacSink::~A2dpCodecConfigAacSink() {}
+
+bool A2dpCodecConfigAacSink::init() {
+  if (!isValid()) return false;
+
+  // Load the decoder
+  if (!A2DP_LoadDecoderAac()) {
+    LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+    return false;
+  }
+
+  return true;
+}
+
+period_ms_t A2dpCodecConfigAacSink::encoderIntervalMs() const {
+  // TODO: This method applies only to Source codecs
+  return 0;
+}
+
+bool A2dpCodecConfigAacSink::setCodecConfig(
+    UNUSED_ATTR const uint8_t* p_peer_codec_info,
+    UNUSED_ATTR bool is_capability,
+    UNUSED_ATTR uint8_t* p_result_codec_config) {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
+
+bool A2dpCodecConfigAacSink::useRtpHeaderMarkerBit() const {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
+
+bool A2dpCodecConfigAacSink::updateEncoderUserConfig(
+    UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+    UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+    UNUSED_ATTR bool* p_config_updated) {
+  // TODO: This method applies only to Source codecs
+  return false;
+}
diff --git a/stack/a2dp/a2dp_aac_decoder.cc b/stack/a2dp/a2dp_aac_decoder.cc
new file mode 100644
index 0000000..d9cd85d
--- /dev/null
+++ b/stack/a2dp/a2dp_aac_decoder.cc
@@ -0,0 +1,107 @@
+/*
+ * 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_decoder"
+
+#include "a2dp_aac_decoder.h"
+
+#include <aacdecoder_lib.h>
+#include <base/logging.h>
+
+#include "a2dp_aac.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+#define DECODE_BUF_LEN (8 * 2 * 1024)
+
+typedef struct {
+  HANDLE_AACDECODER aac_handle;
+  bool has_aac_handle;  // True if aac_handle is valid
+  INT_PCM* decode_buf;
+  decoded_data_callback_t decode_callback;
+} tA2DP_AAC_DECODER_CB;
+
+static tA2DP_AAC_DECODER_CB a2dp_aac_decoder_cb;
+
+bool A2DP_LoadDecoderAac(void) {
+  // Nothing to do - the library is statically linked
+  return true;
+}
+
+void A2DP_UnloadDecoderAac(void) { a2dp_aac_decoder_cleanup(); }
+
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback) {
+  a2dp_aac_decoder_cleanup();
+
+  a2dp_aac_decoder_cb.aac_handle =
+      aacDecoder_Open(TT_MP4_LATM_MCP1, 1 /* nrOfLayers */);
+  a2dp_aac_decoder_cb.has_aac_handle = true;
+  a2dp_aac_decoder_cb.decode_buf = static_cast<INT_PCM*>(
+      osi_malloc(sizeof(a2dp_aac_decoder_cb.decode_buf[0]) * DECODE_BUF_LEN));
+  a2dp_aac_decoder_cb.decode_callback = decode_callback;
+  return true;
+}
+
+void a2dp_aac_decoder_cleanup(void) {
+  if (a2dp_aac_decoder_cb.has_aac_handle)
+    aacDecoder_Close(a2dp_aac_decoder_cb.aac_handle);
+  free(a2dp_aac_decoder_cb.decode_buf);
+  memset(&a2dp_aac_decoder_cb, 0, sizeof(a2dp_aac_decoder_cb));
+}
+
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf) {
+  auto* pBuffer = reinterpret_cast<UCHAR*>(p_buf->data + p_buf->offset);
+  UINT bufferSize = p_buf->len;
+  UINT bytesValid = p_buf->len;
+  while (bytesValid > 0) {
+    AAC_DECODER_ERROR err = aacDecoder_Fill(a2dp_aac_decoder_cb.aac_handle,
+                                            &pBuffer, &bufferSize, &bytesValid);
+    if (err != AAC_DEC_OK) {
+      LOG_ERROR(LOG_TAG, "%s: aacDecoder_Fill failed: 0x%x", __func__,
+                static_cast<unsigned>(err));
+      return false;
+    }
+
+    while (true) {
+      err = aacDecoder_DecodeFrame(a2dp_aac_decoder_cb.aac_handle,
+                                   a2dp_aac_decoder_cb.decode_buf,
+                                   DECODE_BUF_LEN, 0 /* flags */);
+      if (err == AAC_DEC_NOT_ENOUGH_BITS) {
+        break;
+      }
+      if (err != AAC_DEC_OK) {
+        LOG_ERROR(LOG_TAG, "%s: aacDecoder_DecodeFrame failed: 0x%x", __func__,
+                  static_cast<int>(err));
+        break;
+      }
+
+      CStreamInfo* info =
+          aacDecoder_GetStreamInfo(a2dp_aac_decoder_cb.aac_handle);
+      if (!info || info->sampleRate <= 0) {
+        LOG_ERROR(LOG_TAG, "%s: Invalid stream info", __func__);
+        break;
+      }
+
+      size_t frame_len = info->frameSize * info->numChannels *
+                         sizeof(a2dp_aac_decoder_cb.decode_buf[0]);
+      a2dp_aac_decoder_cb.decode_callback(
+          reinterpret_cast<uint8_t*>(a2dp_aac_decoder_cb.decode_buf),
+          frame_len);
+    }
+  }
+
+  return true;
+}
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 60dd7e0..b01c623 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -111,6 +111,9 @@
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
       codec_config = new A2dpCodecConfigAac(codec_priority);
       break;
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+      codec_config = new A2dpCodecConfigAacSink(codec_priority);
+      break;
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       codec_config = new A2dpCodecConfigAptx(codec_priority);
       break;
@@ -1093,30 +1096,6 @@
   return -1;
 }
 
-int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
-                                     const uint8_t* p_codec_info) {
-  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
-
-  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
-
-  switch (codec_type) {
-    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);
-    default:
-      break;
-  }
-
-  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
-  return -1;
-}
-
 bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
                              uint32_t* p_timestamp) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
@@ -1177,6 +1156,27 @@
   return NULL;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
+    const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetDecoderInterfaceSbc(p_codec_info);
+    case A2DP_MEDIA_CT_AAC:
+      return A2DP_GetDecoderInterfaceAac(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetDecoderInterface(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return NULL;
+}
+
 bool A2DP_AdjustCodec(uint8_t* p_codec_info) {
   tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
 
@@ -1223,6 +1223,8 @@
       return A2DP_CodecIndexStrSbcSink();
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
       return A2DP_CodecIndexStrAac();
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+      return A2DP_CodecIndexStrAacSink();
     default:
       break;
   }
@@ -1249,6 +1251,8 @@
       return A2DP_InitCodecConfigSbcSink(p_cfg);
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
       return A2DP_InitCodecConfigAac(p_cfg);
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+      return A2DP_InitCodecConfigAacSink(p_cfg);
     default:
       break;
   }
diff --git a/stack/a2dp/a2dp_sbc.cc b/stack/a2dp/a2dp_sbc.cc
index 18760c7..38e1b3b 100644
--- a/stack/a2dp/a2dp_sbc.cc
+++ b/stack/a2dp/a2dp_sbc.cc
@@ -32,6 +32,7 @@
 #include <string.h>
 
 #include <base/logging.h>
+#include "a2dp_sbc_decoder.h"
 #include "a2dp_sbc_encoder.h"
 #include "bt_utils.h"
 #include "embdrv/sbc/encoder/include/sbc_encoder.h"
@@ -101,6 +102,11 @@
     nullptr  // set_transmit_queue_length
 };
 
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_sbc = {
+    a2dp_sbc_decoder_init, a2dp_sbc_decoder_cleanup,
+    a2dp_sbc_decoder_decode_packet,
+};
+
 static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
     const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
     bool is_capability);
@@ -716,138 +722,6 @@
   return -1;
 }
 
-int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
-                                        const uint8_t* p_codec_info) {
-  tA2DP_SBC_CIE sbc_cie;
-  uint32_t freq_multiple;
-  uint32_t num_blocks;
-  uint32_t num_subbands;
-  int frames_to_process;
-
-  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_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;
-  }
-
-  // Check the sample frequency
-  switch (sbc_cie.samp_freq) {
-    case A2DP_SBC_IE_SAMP_FREQ_16:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (16000)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = 16 * time_interval_ms;
-      break;
-    case A2DP_SBC_IE_SAMP_FREQ_32:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (32000)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = 32 * time_interval_ms;
-      break;
-    case A2DP_SBC_IE_SAMP_FREQ_44:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (44100)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = (441 * time_interval_ms) / 10;
-      break;
-    case A2DP_SBC_IE_SAMP_FREQ_48:
-      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (48000)", __func__,
-                  sbc_cie.samp_freq);
-      freq_multiple = 48 * time_interval_ms;
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown frequency: %d", __func__,
-                sbc_cie.samp_freq);
-      return -1;
-  }
-
-  // Check the channel mode
-  switch (sbc_cie.ch_mode) {
-    case A2DP_SBC_IE_CH_MD_MONO:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, sbc_cie.ch_mode);
-      break;
-    case A2DP_SBC_IE_CH_MD_DUAL:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, sbc_cie.ch_mode);
-      break;
-    case A2DP_SBC_IE_CH_MD_STEREO:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__,
-                  sbc_cie.ch_mode);
-      break;
-    case A2DP_SBC_IE_CH_MD_JOINT:
-      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, sbc_cie.ch_mode);
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown channel mode: %d", __func__,
-                sbc_cie.ch_mode);
-      return -1;
-  }
-
-  // Check the block length
-  switch (sbc_cie.block_len) {
-    case A2DP_SBC_IE_BLOCKS_4:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (4)", __func__, sbc_cie.block_len);
-      num_blocks = 4;
-      break;
-    case A2DP_SBC_IE_BLOCKS_8:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (8)", __func__, sbc_cie.block_len);
-      num_blocks = 8;
-      break;
-    case A2DP_SBC_IE_BLOCKS_12:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (12)", __func__,
-                  sbc_cie.block_len);
-      num_blocks = 12;
-      break;
-    case A2DP_SBC_IE_BLOCKS_16:
-      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (16)", __func__,
-                  sbc_cie.block_len);
-      num_blocks = 16;
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown block length: %d", __func__,
-                sbc_cie.block_len);
-      return -1;
-  }
-
-  // Check the number of sub-bands
-  switch (sbc_cie.num_subbands) {
-    case A2DP_SBC_IE_SUBBAND_4:
-      LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (4)", __func__,
-                  sbc_cie.num_subbands);
-      num_subbands = 4;
-      break;
-    case A2DP_SBC_IE_SUBBAND_8:
-      LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (8)", __func__,
-                  sbc_cie.num_subbands);
-      num_subbands = 8;
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown number of subbands: %d", __func__,
-                sbc_cie.num_subbands);
-      return -1;
-  }
-
-  // Check the allocation method
-  switch (sbc_cie.alloc_method) {
-    case A2DP_SBC_IE_ALLOC_MD_S:
-      LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__,
-                  sbc_cie.alloc_method);
-      break;
-    case A2DP_SBC_IE_ALLOC_MD_L:
-      LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__,
-                  sbc_cie.alloc_method);
-      break;
-    default:
-      LOG_ERROR(LOG_TAG, "%s: unknown allocation method: %d", __func__,
-                sbc_cie.alloc_method);
-      return -1;
-  }
-
-  LOG_VERBOSE(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__,
-              sbc_cie.min_bitpool, sbc_cie.max_bitpool);
-
-  frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
-
-  return frames_to_process;
-}
-
 bool A2DP_GetPacketTimestampSbc(UNUSED_ATTR const uint8_t* p_codec_info,
                                 const uint8_t* p_data, uint32_t* p_timestamp) {
   *p_timestamp = *(const uint32_t*)p_data;
@@ -950,6 +824,13 @@
   return &a2dp_encoder_interface_sbc;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceSbc(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsSinkCodecValidSbc(p_codec_info)) return NULL;
+
+  return &a2dp_decoder_interface_sbc;
+}
+
 bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info) {
   tA2DP_SBC_CIE cfg_cie;
 
@@ -1622,6 +1503,12 @@
 bool A2dpCodecConfigSbcSink::init() {
   if (!isValid()) return false;
 
+  // Load the decoder
+  if (!A2DP_LoadDecoderSbc()) {
+    LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+    return false;
+  }
+
   return true;
 }
 
diff --git a/stack/a2dp/a2dp_sbc_decoder.cc b/stack/a2dp/a2dp_sbc_decoder.cc
new file mode 100644
index 0000000..bc64513
--- /dev/null
+++ b/stack/a2dp/a2dp_sbc_decoder.cc
@@ -0,0 +1,97 @@
+/*
+ * 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_sbc_decoder"
+
+#include "a2dp_sbc_decoder.h"
+
+#include <base/logging.h>
+
+#include "embdrv/sbc/decoder/include/oi_codec_sbc.h"
+#include "embdrv/sbc/decoder/include/oi_status.h"
+#include "osi/include/log.h"
+
+typedef struct {
+  OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
+  uint32_t context_data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+  int16_t decode_buf[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+  decoded_data_callback_t decode_callback;
+} tA2DP_SBC_DECODER_CB;
+
+static tA2DP_SBC_DECODER_CB a2dp_sbc_decoder_cb;
+
+bool A2DP_LoadDecoderSbc(void) {
+  // Nothing to do - the library is statically linked
+  return true;
+}
+
+void A2DP_UnloadDecoderSbc(void) { a2dp_sbc_decoder_cleanup(); }
+
+bool a2dp_sbc_decoder_init(decoded_data_callback_t decode_callback) {
+  OI_STATUS status = OI_CODEC_SBC_DecoderReset(
+      &a2dp_sbc_decoder_cb.decoder_context, a2dp_sbc_decoder_cb.context_data,
+      sizeof(a2dp_sbc_decoder_cb.context_data), 2, 2, false);
+  if (!OI_SUCCESS(status)) {
+    LOG_ERROR(LOG_TAG,
+              "%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
+              __func__, status);
+    return false;
+  }
+
+  a2dp_sbc_decoder_cb.decode_callback = decode_callback;
+  return true;
+}
+
+void a2dp_sbc_decoder_cleanup(void) {
+  // Do nothing.
+}
+
+bool a2dp_sbc_decoder_decode_packet(BT_HDR* p_buf) {
+  uint8_t* data = p_buf->data + p_buf->offset;
+  size_t data_size = p_buf->len;
+
+  if (data_size == 0) {
+    LOG_ERROR(LOG_TAG, "%s: Empty packet", __func__);
+    return false;
+  }
+  size_t num_frames = data[0] & 0xf;
+  data += 1;
+  data_size -= 1;
+
+  const OI_BYTE* oi_data = data;
+  uint32_t oi_size = data_size;
+  size_t out_avail = sizeof(a2dp_sbc_decoder_cb.decode_buf);
+  int16_t* out_ptr = a2dp_sbc_decoder_cb.decode_buf;
+
+  for (size_t i = 0; i < num_frames; ++i) {
+    uint32_t out_size = out_avail;
+    OI_STATUS status =
+        OI_CODEC_SBC_DecodeFrame(&a2dp_sbc_decoder_cb.decoder_context, &oi_data,
+                                 &oi_size, out_ptr, &out_size);
+    if (!OI_SUCCESS(status)) {
+      LOG_ERROR(LOG_TAG, "%s: Decoding failure: %d", __func__, status);
+      return false;
+    }
+    out_avail -= out_size;
+    out_ptr += out_size / sizeof(*out_ptr);
+  }
+
+  size_t out_used =
+      (out_ptr - a2dp_sbc_decoder_cb.decode_buf) * sizeof(*out_ptr);
+  a2dp_sbc_decoder_cb.decode_callback(
+      reinterpret_cast<uint8_t*>(a2dp_sbc_decoder_cb.decode_buf), out_used);
+  return true;
+}
diff --git a/stack/a2dp/a2dp_vendor.cc b/stack/a2dp/a2dp_vendor.cc
index 724bf51..2b874e3 100644
--- a/stack/a2dp/a2dp_vendor.cc
+++ b/stack/a2dp/a2dp_vendor.cc
@@ -350,18 +350,6 @@
   return -1;
 }
 
-int A2DP_VendorGetSinkFramesCountToProcess(
-    UNUSED_ATTR uint64_t time_interval_ms,
-    UNUSED_ATTR const uint8_t* p_codec_info) {
-  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
-  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
-
-  // Add checks based on <vendor_id, codec_id>
-  // NOTE: Should be done only for local Sink codecs.
-
-  return -1;
-}
-
 bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
                                    const uint8_t* p_data,
                                    uint32_t* p_timestamp) {
@@ -448,6 +436,12 @@
   return NULL;
 }
 
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
+    const uint8_t* p_codec_info) {
+  // We do not support vendor codecs for decoding right now.
+  return NULL;
+}
+
 bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info) {
   uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
   uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -507,6 +501,7 @@
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
       break;  // These are not vendor-specific codecs
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       return A2DP_VendorCodecIndexStrAptx();
@@ -529,6 +524,7 @@
     case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
     case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
     case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+    case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
       break;  // These are not vendor-specific codecs
     case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
       return A2DP_VendorInitCodecConfigAptx(p_cfg);
diff --git a/stack/avrc/avrc_sdp.cc b/stack/avrc/avrc_sdp.cc
index 9ce38f5..eba96cc 100644
--- a/stack/avrc/avrc_sdp.cc
+++ b/stack/avrc/avrc_sdp.cc
@@ -209,7 +209,17 @@
   }
   result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
 
-  /* add protocol descriptor list   */
+  uint16_t protocol_reported_version;
+  /* AVRCP versions 1.3 to 1.5 report (version - 1) in the protocol
+     descriptor list. Oh, and 1.6 and 1.6.1 report version 1.4.
+     /because-we-smart */
+  if (profile_version < AVRC_REV_1_6) {
+    protocol_reported_version = profile_version - 1;
+  } else {
+    protocol_reported_version = AVCT_REV_1_4;
+  }
+
+  /* add protocol descriptor list */
   tSDP_PROTOCOL_ELEM avrc_proto_desc_list[AVRC_NUM_PROTO_ELEMS];
   avrc_proto_desc_list[0].num_params = 1;
   avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
@@ -218,13 +228,13 @@
   for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++) {
     avrc_proto_desc_list[index].num_params = 1;
     avrc_proto_desc_list[index].protocol_uuid = UUID_PROTOCOL_AVCTP;
-    avrc_proto_desc_list[index].params[0] = AVCT_REV_1_4;
+    avrc_proto_desc_list[index].params[0] = protocol_reported_version;
     avrc_proto_desc_list[index].params[1] = 0;
   }
   result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS,
                                 &avrc_proto_desc_list[0]);
 
-  /* additional protocal descriptor, required only for version > 1.3    */
+  /* additional protocal descriptor, required only for version > 1.3 */
   if ((profile_version > AVRC_REV_1_3) && (browse_supported)) {
     tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list;
     avrc_add_proto_desc_list.num_elems = 2;
@@ -234,7 +244,7 @@
     avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
     avrc_add_proto_desc_list.list_elem[1].num_params = 1;
     avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
-    avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
+    avrc_add_proto_desc_list.list_elem[1].params[0] = protocol_reported_version;
     avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
 
     result &=
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index a3d9caa..d63187b 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -1841,10 +1841,10 @@
   }
 }
 
-void btm_ble_process_adv_addr(RawAddress& bda, uint8_t addr_type) {
+void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) {
 #if (BLE_PRIVACY_SPT == TRUE)
   /* map address to security record */
-  bool match = btm_identity_addr_to_random_pseudo(&bda, &addr_type, false);
+  bool match = btm_identity_addr_to_random_pseudo(&bda, addr_type, false);
 
   VLOG(1) << __func__ << ": bda=" << bda;
   /* always do RRA resolution on host */
@@ -1915,7 +1915,7 @@
                       pkt_data_len, rssi);
     }
 
-    btm_ble_process_adv_addr(bda, addr_type);
+    btm_ble_process_adv_addr(bda, &addr_type);
     btm_ble_process_adv_pkt_cont(event_type, addr_type, bda, primary_phy,
                                  secondary_phy, advertising_sid, tx_power, rssi,
                                  periodic_adv_int, pkt_data_len, pkt_data);
@@ -1962,7 +1962,7 @@
                       pkt_data_len, rssi);
     }
 
-    btm_ble_process_adv_addr(bda, addr_type);
+    btm_ble_process_adv_addr(bda, &addr_type);
 
     uint16_t event_type;
     if (legacy_evt_type == 0x00) {  // ADV_IND;
diff --git a/stack/include/a2dp_aac.h b/stack/include/a2dp_aac.h
index ac85975..f2d2553 100644
--- a/stack/include/a2dp_aac.h
+++ b/stack/include/a2dp_aac.h
@@ -44,6 +44,24 @@
   void debug_codec_dump(int fd) override;
 };
 
+class A2dpCodecConfigAacSink : public A2dpCodecConfig {
+ public:
+  A2dpCodecConfigAacSink(btav_a2dp_codec_priority_t codec_priority);
+  virtual ~A2dpCodecConfigAacSink();
+
+  bool init() override;
+  period_ms_t encoderIntervalMs() const override;
+  bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+                      uint8_t* p_result_codec_config) override;
+
+ private:
+  bool useRtpHeaderMarkerBit() const override;
+  bool updateEncoderUserConfig(
+      const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+      bool* p_restart_input, bool* p_restart_output,
+      bool* p_config_updated) override;
+};
+
 // Checks whether the codec capabilities contain a valid A2DP AAC Source
 // codec.
 // NOTE: only codecs that are implemented are considered valid.
@@ -135,14 +153,6 @@
 // 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.
@@ -208,6 +218,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
     const uint8_t* p_codec_info);
 
+// Gets the current A2DP AAC decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP AAC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceAac(
+    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.
@@ -222,8 +240,15 @@
 // Gets the A2DP AAC Source codec name.
 const char* A2DP_CodecIndexStrAac(void);
 
+// Gets the A2DP AAC Sink codec name.
+const char* A2DP_CodecIndexStrAacSink(void);
+
 // Initializes A2DP AAC Source codec information into |tAVDT_CFG|
 // configuration entry pointed by |p_cfg|.
 bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg);
 
+// Initializes A2DP AAC Sink codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigAacSink(tAVDT_CFG* p_cfg);
+
 #endif  // A2DP_AAC_H
diff --git a/stack/include/a2dp_aac_decoder.h b/stack/include/a2dp_aac_decoder.h
new file mode 100644
index 0000000..53ffc52
--- /dev/null
+++ b/stack/include/a2dp_aac_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * 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 Decoder
+//
+
+#ifndef A2DP_AAC_DECODER_H
+#define A2DP_AAC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP AAC decoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadDecoderAac(void);
+
+// Unloads the A2DP AAC decoder.
+void A2DP_UnloadDecoderAac(void);
+
+// Initialize the A2DP AAC decoder.
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP AAC decoder.
+void a2dp_aac_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into |a2dp_aac_decoder_init|
+// if decoded frames are available.
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif  // A2DP_AAC_DECODER_H
diff --git a/stack/include/a2dp_codec_api.h b/stack/include/a2dp_codec_api.h
index c10264a..ba62fbe 100644
--- a/stack/include/a2dp_codec_api.h
+++ b/stack/include/a2dp_codec_api.h
@@ -490,6 +490,27 @@
   void (*set_transmit_queue_length)(size_t transmit_queue_length);
 } tA2DP_ENCODER_INTERFACE;
 
+// Prototype for a callback to receive decoded audio data from a
+// tA2DP_DECODER_INTERFACE|.
+// |buf| is a pointer to the data.
+// |len| is the number of octets pointed to by |buf|.
+typedef void (*decoded_data_callback_t)(uint8_t* buf, uint32_t len);
+
+//
+// A2DP decoder callbacks interface.
+//
+typedef struct {
+  // Initialize the decoder. Can be called multiple times, will reinitalize.
+  bool (*decoder_init)(decoded_data_callback_t decode_callback);
+
+  // Cleanup the A2DP decoder.
+  void (*decoder_cleanup)();
+
+  // Decodes |p_buf| and calls |decode_callback| passed into init for the
+  // decoded data.
+  bool (*decode_packet)(BT_HDR* p_buf);
+} tA2DP_DECODER_INTERFACE;
+
 // Gets the A2DP codec type.
 // |p_codec_info| contains information about the codec capabilities.
 tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info);
@@ -592,14 +613,6 @@
 // contains invalid codec information.
 int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// 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_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
-                                     const uint8_t* p_codec_info);
-
 // Gets the A2DP audio data timestamp from an audio packet.
 // |p_codec_info| contains the codec information.
 // |p_data| contains the audio data.
@@ -624,6 +637,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
     const uint8_t* p_codec_info);
 
+// Gets the A2DP decoder interface that can be used to decode received A2DP
+// packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP 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.
diff --git a/stack/include/a2dp_sbc.h b/stack/include/a2dp_sbc.h
index ee10858..51632ad 100644
--- a/stack/include/a2dp_sbc.h
+++ b/stack/include/a2dp_sbc.h
@@ -196,14 +196,6 @@
 // contains invalid codec information.
 int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// SBC 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_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
-                                        const uint8_t* p_codec_info);
-
 // Gets the A2DP SBC audio data timestamp from an audio packet.
 // |p_codec_info| contains the codec information.
 // |p_data| contains the audio data.
@@ -233,6 +225,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
     const uint8_t* p_codec_info);
 
+// Gets the A2DP SBC decoder interface that can be used to decode received A2DP
+// packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP SBC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceSbc(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP SBC codec, based on local support and Bluetooth
 // specification.
 // |p_codec_info| contains the codec information to adjust.
diff --git a/stack/include/a2dp_sbc_decoder.h b/stack/include/a2dp_sbc_decoder.h
new file mode 100644
index 0000000..f5ac99a
--- /dev/null
+++ b/stack/include/a2dp_sbc_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * 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 SBC Decoder
+//
+
+#ifndef A2DP_SBC_DECODER_H
+#define A2DP_SBC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP SBC decoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadDecoderSbc(void);
+
+// Unloads the A2DP SBC decoder.
+void A2DP_UnloadDecoderSbc(void);
+
+// Initialize the A2DP SBC decoder.
+bool a2dp_sbc_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP SBC decoder.
+void a2dp_sbc_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into |a2dp_sbc_decoder_init|
+// if decoded frames are available.
+bool a2dp_sbc_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif  // A2DP_SBC_DECODER_H
diff --git a/stack/include/a2dp_vendor.h b/stack/include/a2dp_vendor.h
index 97663fd..0547d46 100644
--- a/stack/include/a2dp_vendor.h
+++ b/stack/include/a2dp_vendor.h
@@ -139,15 +139,6 @@
 // contains invalid codec information.
 int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info);
 
-// Computes the number of frames to process in a time window for the A2DP
-// vendor-specific 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_VendorGetSinkFramesCountToProcess(uint64_t time_interval_ms,
-                                           const uint8_t* p_codec_info);
-
 // Gets the A2DP codec-specific audio data timestamp from an audio packet.
 // |p_codec_info| contains the codec information.
 // |p_data| contains the audio data.
@@ -173,6 +164,14 @@
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
     const uint8_t* p_codec_info);
 
+// Gets the current A2DP vendor decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP vendor decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
+    const uint8_t* p_codec_info);
+
 // Adjusts the A2DP vendor-specific codec, based on local support and Bluetooth
 // specification.
 // |p_codec_info| contains the codec information to adjust.
diff --git a/stack/test/stack_a2dp_test.cc b/stack/test/stack_a2dp_test.cc
index b6a33b3..91c1c83 100644
--- a/stack/test/stack_a2dp_test.cc
+++ b/stack/test/stack_a2dp_test.cc
@@ -220,6 +220,9 @@
         case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
           supported = true;
           break;
+        case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+          supported = true;
+          break;
         case BTAV_A2DP_CODEC_INDEX_MAX:
           // Needed to avoid using "default:" case so we can capture when
           // a new codec is added, and it can be included here.
@@ -310,10 +313,10 @@
 TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
   EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
   EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_capability));
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
-  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
 
-  EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
+  EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
   EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
 
   // Test with invalid AAC codecs
@@ -349,8 +352,11 @@
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_capability));
   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_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac));
+  // NOTE: The test below should be EXPECT_FALSE.
+  // However, codec_info_aac_capability is practically same as codec_info_aac,
+  // therefore we cannot differentiate it as a capability.
+  EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_sink_capability));
 
   EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
@@ -361,9 +367,9 @@
   EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_capability));
   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_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
 
   EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
 }
@@ -607,16 +613,10 @@
 
 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_aac), 3);
   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);
diff --git a/test/run_host_unit_tests.py b/test/run_host_unit_tests.py
index 536ad21..e5e392c 100755
--- a/test/run_host_unit_tests.py
+++ b/test/run_host_unit_tests.py
@@ -77,7 +77,7 @@
         current_path = parent_path
     if not value:
       print 'Cannot determine ANDROID_BUILD_TOP'
-      sys.exit(0)
+      sys.exit(1)
   check_dir_exists(value, '$ANDROID_BUILD_TOP')
   return value
 
@@ -93,7 +93,7 @@
                                      'HOST_OUT'))
     if not value:
       print 'Cannot determine ANDROID_HOST_OUT'
-      sys.exit(0)
+      sys.exit(1)
   check_dir_exists(value, '$ANDROID_HOST_OUT')
   return value
 
@@ -108,7 +108,7 @@
   if not os.path.isdir(value):
     if os.path.exists(value):
       print '%s is not a directory!' % (value)
-      sys.exit(0)
+      sys.exit(1)
     os.makedirs(value)
   return value
 
@@ -121,7 +121,7 @@
     if not os.path.isdir(test_root):
       print 'Neither nativetest64 nor nativetest directory exist,' \
             ' please compile first'
-      sys.exit(0)
+      sys.exit(1)
   return test_root
 
 
@@ -129,7 +129,7 @@
   test_path = os.path.join(os.path.join(test_root, test_name), test_name)
   if not os.path.isfile(test_path):
     print 'Cannot find: ' + test_path
-    return None
+    sys.exit(1)
   cmd = [test_path]
   if enable_xml:
     dist_dir = get_android_dist_dir_or_die()
@@ -149,9 +149,10 @@
     build_cmd.append('-j' + str(num_tasks))
   build_cmd.append(target)
   p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy())
-  if p.wait() != 0:
-    print 'BUILD FAILED'
-    sys.exit(0)
+  return_code = p.wait()
+  if return_code != 0:
+    print 'BUILD FAILED, return code: {0}'.format(str(return_code))
+    sys.exit(1)
   return
 
 
@@ -187,9 +188,6 @@
   test_results = []
   for test in HOST_TESTS:
     test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest)
-    if not test_cmd:
-      test_results.append(False)
-      continue
     if subprocess.call(test_cmd) != 0:
       test_results.append(False)
     else:
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index 4c390bf..8fe47f8 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -102,18 +102,11 @@
   adb+=( "-s" "${device}" )
 fi
 
-source ${ANDROID_BUILD_TOP}/build/envsetup.sh
-target_arch=$(gettargetarch)
-
 failed_tests=()
 for spec in "${tests[@]}"
 do
   name="${spec%%.*}"
-  if [[ $target_arch == *"64"* ]]; then
-    binary="/data/nativetest64/${name}/${name}"
-  else
-    binary="/data/nativetest/${name}/${name}"
-  fi
+  binary="/data/nativetest/${name}/${name}"
 
   push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" )
   test_command=( "${adb[@]}" shell "${binary}" )
diff --git a/types/Android.bp b/types/Android.bp
index ed5c613..5867d63 100644
--- a/types/Android.bp
+++ b/types/Android.bp
@@ -6,11 +6,10 @@
     host_supported: true,
 }
 
-cc_library {
+cc_library_static {
     name: "libbluetooth-types",
     vendor_available: true,
     defaults: ["fluoride_types_defaults"],
-    compile_multilib: "both",
     cflags: [
         /* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
         "-fvisibility=default",