Uprev to AVDTP 1.3 and Implement AVDTP delay reports

Implement receiving the delay report message which requires AVDTP 1.3.
Also start keeping track of total number of audio bytes sent over the
air. We now will report both of these values to the audio HAL so that
they can adjust audio playback using these values.

Bug: 32755225
Test: Manual test with a device that supports delay reporting
      Testtracker: 145280
Change-Id: I22c1c6401e4912efab06fa56fb582faae4b38eaf
diff --git a/system/audio_a2dp_hw/Android.bp b/system/audio_a2dp_hw/Android.bp
index 474a6dd..281dbe3 100644
--- a/system/audio_a2dp_hw/Android.bp
+++ b/system/audio_a2dp_hw/Android.bp
@@ -20,6 +20,7 @@
     ],
     shared_libs: [
         "liblog",
+        "libcutils",
     ],
     static_libs: ["libosi"],
 }
diff --git a/system/audio_a2dp_hw/include/audio_a2dp_hw.h b/system/audio_a2dp_hw/include/audio_a2dp_hw.h
index ab7574b..0116e18 100644
--- a/system/audio_a2dp_hw/include/audio_a2dp_hw.h
+++ b/system/audio_a2dp_hw/include/audio_a2dp_hw.h
@@ -85,6 +85,7 @@
   A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG,
   A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG,
   A2DP_CTRL_CMD_OFFLOAD_START,
+  A2DP_CTRL_GET_PRESENTATION_POSITION,
 } tA2DP_CTRL_CMD;
 
 typedef enum {
@@ -140,12 +141,15 @@
 //
 // Returns the computed buffer size. If any of the input parameters is
 // invalid, the return value is the default |AUDIO_STREAM_OUTPUT_BUFFER_SZ|.
-extern size_t audio_a2dp_hw_stream_compute_buffer_size(
+size_t audio_a2dp_hw_stream_compute_buffer_size(
     btav_a2dp_codec_sample_rate_t codec_sample_rate,
     btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
     btav_a2dp_codec_channel_mode_t codec_channel_mode);
 
+// Returns whether the delay reporting property is set.
+bool delay_reporting_enabled();
+
 // Returns a string representation of |event|.
-extern const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);
+const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);
 
 #endif /* A2DP_AUDIO_HW_H */
diff --git a/system/audio_a2dp_hw/src/audio_a2dp_hw.cc b/system/audio_a2dp_hw/src/audio_a2dp_hw.cc
index 87e9736..d8c39b8 100644
--- a/system/audio_a2dp_hw/src/audio_a2dp_hw.cc
+++ b/system/audio_a2dp_hw/src/audio_a2dp_hw.cc
@@ -58,6 +58,13 @@
 #define USEC_PER_SEC 1000000L
 #define SOCK_SEND_TIMEOUT_MS 2000 /* Timeout for sending */
 #define SOCK_RECV_TIMEOUT_MS 5000 /* Timeout for receiving */
+#define SEC_TO_MS 1000
+#define SEC_TO_NS 1000000000
+#define MS_TO_NS 1000000
+#define DELAY_TO_NS 100000
+
+#define MIN_DELAY_MS 100
+#define MAX_DELAY_MS 1000
 
 // set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking
 // sockets
@@ -145,11 +152,14 @@
  *  Static variables
  *****************************************************************************/
 
+static bool enable_delay_reporting = false;
+
 /*****************************************************************************
  *  Static functions
  *****************************************************************************/
 
 static size_t out_get_buffer_size(const struct audio_stream* stream);
+static uint32_t out_get_latency(const struct audio_stream_out* stream);
 
 /*****************************************************************************
  *  Externs
@@ -729,6 +739,36 @@
   return 0;
 }
 
+static int a2dp_get_presentation_position_cmd(struct a2dp_stream_common* common,
+                                              uint64_t* bytes, uint16_t* delay,
+                                              struct timespec* timestamp) {
+  if (a2dp_command(common, A2DP_CTRL_GET_PRESENTATION_POSITION) < 0) {
+    return -1;
+  }
+
+  if (a2dp_ctrl_receive(common, bytes, sizeof(*bytes)) < 0) {
+    return -1;
+  }
+
+  if (a2dp_ctrl_receive(common, delay, sizeof(*delay)) < 0) {
+    return -1;
+  }
+
+  uint32_t seconds;
+  if (a2dp_ctrl_receive(common, &seconds, sizeof(seconds)) < 0) {
+    return -1;
+  }
+
+  uint32_t nsec;
+  if (a2dp_ctrl_receive(common, &nsec, sizeof(nsec)) < 0) {
+    return -1;
+  }
+
+  timestamp->tv_sec = seconds;
+  timestamp->tv_nsec = nsec;
+  return 0;
+}
+
 static void a2dp_open_ctrl_path(struct a2dp_stream_common* common) {
   int i;
 
@@ -803,6 +843,10 @@
     }
   }
   common->state = (a2dp_state_t)AUDIO_A2DP_STATE_STARTED;
+
+  /* check to see if delay reporting is enabled */
+  enable_delay_reporting = delay_reporting_enabled();
+
   return 0;
 
 error:
@@ -1286,17 +1330,44 @@
   FNLOG();
   if (stream == NULL || frames == NULL || timestamp == NULL) return -EINVAL;
 
-  int ret = -EWOULDBLOCK;
   std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+
+  // bytes is the total number of bytes sent by the Bluetooth stack to a
+  // remote headset
+  uint64_t bytes = 0;
+
+  // delay_report is the audio delay from the remote headset receiving data to
+  // the headset playing sound in units of 1/10ms
+  uint16_t delay_report = 0;
+
+  // If for some reason getting a delay fails or delay reports are disabled,
+  // default to old delay
+  if (enable_delay_reporting &&
+      a2dp_get_presentation_position_cmd(&out->common, &bytes, &delay_report,
+                                         timestamp) == 0) {
+    uint64_t delay_ns = delay_report * DELAY_TO_NS;
+    if (delay_ns > MIN_DELAY_MS * MS_TO_NS &&
+        delay_ns < MAX_DELAY_MS * MS_TO_NS) {
+      *frames = bytes / audio_stream_out_frame_size(stream);
+
+      timestamp->tv_nsec += delay_ns;
+      if (timestamp->tv_nsec > 1 * SEC_TO_NS) {
+        timestamp->tv_sec++;
+        timestamp->tv_nsec -= SEC_TO_NS;
+      }
+      return 0;
+    }
+  }
+
   uint64_t latency_frames =
       (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
   if (out->frames_presented >= latency_frames) {
+    clock_gettime(CLOCK_MONOTONIC, timestamp);
     *frames = out->frames_presented - latency_frames;
-    clock_gettime(CLOCK_MONOTONIC,
-                  timestamp);  // could also be associated with out_write().
-    ret = 0;
+    return 0;
   }
-  return ret;
+
+  return -EWOULDBLOCK;
 }
 
 static int out_get_render_position(const struct audio_stream_out* stream,
diff --git a/system/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc b/system/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
index 40a637d..5856191 100644
--- a/system/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
+++ b/system/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
@@ -17,6 +17,7 @@
  ******************************************************************************/
 
 #include "audio_a2dp_hw.h"
+#include "osi/include/properties.h"
 
 #define CASE_RETURN_STR(const) \
   case const:                  \
@@ -39,3 +40,7 @@
 
   return "UNKNOWN A2DP_CTRL_CMD";
 }
+
+bool delay_reporting_enabled() {
+  return osi_property_get_bool("persist.bluetooth.enabledelayreports", false);
+}
\ No newline at end of file
diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc
index c149ced..21842eb 100644
--- a/system/btif/co/bta_av_co.cc
+++ b/system/btif/co/bta_av_co.cc
@@ -1127,6 +1127,7 @@
                            const RawAddress& peer_address) {
   APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__,
                    peer_address.ToString().c_str(), bta_av_handle);
+  btif_av_reset_audio_delay();
 
   // Find the peer
   BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
@@ -1218,9 +1219,10 @@
 void BtaAvCo::ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle,
                                 const RawAddress& peer_address,
                                 uint16_t delay) {
-  APPL_TRACE_ERROR("%s: peer %s bta_av_handle: 0x%x delay:0x%x", __func__,
+  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x delay:0x%x", __func__,
                    peer_address.ToString().c_str(), bta_av_handle, delay);
-  // Nothing to do
+
+  btif_av_set_audio_delay(delay);
 }
 
 void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle,
diff --git a/system/btif/include/btif_a2dp_control.h b/system/btif/include/btif_a2dp_control.h
index e1ac22c..37a0f1b 100644
--- a/system/btif/include/btif_a2dp_control.h
+++ b/system/btif/include/btif_a2dp_control.h
@@ -34,4 +34,17 @@
 // |status| is the acknowledement status - see |tA2DP_CTRL_ACK|.
 void btif_a2dp_command_ack(tA2DP_CTRL_ACK status);
 
+// Increment the total number audio data bytes that have been encoded since
+// last encoding attempt.
+// |bytes_read| is the number of bytes to increment by.
+void btif_a2dp_control_log_bytes_read(uint32_t bytes_read);
+
+// Set the audio delay reported to the audio HAL in uints of 1/10ms.
+// |delay| is the audio delay to set.
+void btif_a2dp_control_set_audio_delay(uint16_t delay);
+
+// Reset the remote audio device's delay value and reset the counter that keeps
+// track of the number of audio bytes sent
+void btif_a2dp_control_reset_audio_delay(void);
+
 #endif /* BTIF_A2DP_CONTROL_H */
diff --git a/system/btif/include/btif_av.h b/system/btif/include/btif_av.h
index 1f07cd6..3ab4903 100644
--- a/system/btif/include/btif_av.h
+++ b/system/btif/include/btif_av.h
@@ -179,4 +179,16 @@
  */
 void btif_debug_av_dump(int fd);
 
+/**
+ * Set the audio delay for the stream.
+ *
+ * @param delay the delay to set in units of 1/10ms
+ */
+void btif_av_set_audio_delay(uint16_t delay);
+
+/**
+ * Reset the audio delay and count of audio bytes sent to zero.
+ */
+void btif_av_reset_audio_delay(void);
+
 #endif /* BTIF_AV_H */
diff --git a/system/btif/src/btif_a2dp_control.cc b/system/btif/src/btif_a2dp_control.cc
index b9bd4d9..d2a804f 100644
--- a/system/btif/src/btif_a2dp_control.cc
+++ b/system/btif/src/btif_a2dp_control.cc
@@ -37,6 +37,12 @@
 
 #define A2DP_DATA_READ_POLL_MS 10
 
+struct {
+  uint64_t total_bytes_read = 0;
+  uint16_t audio_delay = 0;
+  struct timespec timestamp = {};
+} delay_report_stats;
+
 static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
 static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
 
@@ -261,6 +267,22 @@
       btif_av_stream_start_offload();
       break;
 
+    case A2DP_CTRL_GET_PRESENTATION_POSITION: {
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+
+      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+                (uint8_t*)&(delay_report_stats.total_bytes_read),
+                sizeof(uint64_t));
+      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+                (uint8_t*)&(delay_report_stats.audio_delay), sizeof(uint16_t));
+
+      uint32_t seconds = delay_report_stats.timestamp.tv_sec;
+      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, (uint8_t*)&seconds, sizeof(seconds));
+
+      uint32_t nsec = delay_report_stats.timestamp.tv_nsec;
+      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, (uint8_t*)&nsec, sizeof(nsec));
+      break;
+    }
     default:
       APPL_TRACE_ERROR("%s: UNSUPPORTED CMD (%d)", __func__, cmd);
       btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
@@ -358,3 +380,20 @@
   /* Acknowledge start request */
   UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
 }
+
+void btif_a2dp_control_log_bytes_read(uint32_t bytes_read) {
+  delay_report_stats.total_bytes_read += bytes_read;
+  clock_gettime(CLOCK_MONOTONIC, &delay_report_stats.timestamp);
+}
+
+void btif_a2dp_control_set_audio_delay(uint16_t delay) {
+  APPL_TRACE_DEBUG("%s: DELAY: %.1f ms", __func__, (float)delay / 10);
+  delay_report_stats.audio_delay = delay;
+}
+
+void btif_a2dp_control_reset_audio_delay(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  delay_report_stats.audio_delay = 0;
+  delay_report_stats.total_bytes_read = 0;
+  delay_report_stats.timestamp = {};
+}
diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc
index e047a5e..9469d1c 100644
--- a/system/btif/src/btif_a2dp_source.cc
+++ b/system/btif/src/btif_a2dp_source.cc
@@ -313,7 +313,8 @@
 static void btif_a2dp_source_alarm_cb(void* context);
 static void btif_a2dp_source_audio_handle_timer(void);
 static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len);
-static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n);
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
+                                              uint32_t bytes_read);
 static void log_tstamps_us(const char* comment, uint64_t timestamp_us);
 static void update_scheduling_stats(SchedulingStats* stats, uint64_t now_us,
                                     uint64_t expected_delta);
@@ -651,6 +652,13 @@
 
   const bool send_ack = btif_a2dp_source_is_streaming();
 
+  uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
+  uint16_t event;
+
+  // Keep track of audio data still left in the pipe
+  btif_a2dp_control_log_bytes_read(
+      UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, p_buf, sizeof(p_buf)));
+
   /* Stop the timer first */
   alarm_free(btif_a2dp_source_cb.media_alarm);
   btif_a2dp_source_cb.media_alarm = nullptr;
@@ -728,8 +736,10 @@
   return bytes_read;
 }
 
-static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n) {
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
+                                              uint32_t bytes_read) {
   uint64_t now_us = time_get_os_boottime_us();
+  btif_a2dp_control_log_bytes_read(bytes_read);
 
   /* Check if timer was stopped (media task stopped) */
   if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc
index d0c650e..e5bb996 100644
--- a/system/btif/src/btif_av.cc
+++ b/system/btif/src/btif_av.cc
@@ -2729,6 +2729,11 @@
     // while registering.
     tBTA_AV_FEAT features = BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA |
                             BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_NO_SCO_SSPD;
+
+    if (delay_reporting_enabled()) {
+      features |= BTA_AV_FEAT_DELAY_RPT;
+    }
+
 #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
     features |= BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_BROWSE;
 #endif
@@ -2981,3 +2986,9 @@
   btif_debug_av_source_dump(fd);
   btif_debug_av_sink_dump(fd);
 }
+
+void btif_av_set_audio_delay(uint16_t delay) {
+  btif_a2dp_control_set_audio_delay(delay);
+}
+
+void btif_av_reset_audio_delay(void) { btif_a2dp_control_reset_audio_delay(); }
\ No newline at end of file
diff --git a/system/internal_include/bt_target.h b/system/internal_include/bt_target.h
index 33571c3..4024e28 100644
--- a/system/internal_include/bt_target.h
+++ b/system/internal_include/bt_target.h
@@ -84,7 +84,7 @@
 #endif
 
 #ifndef AVDT_VERSION
-#define AVDT_VERSION 0x0102
+#define AVDT_VERSION 0x0103
 #endif
 
 #ifndef BTA_AG_AT_MAX_LEN
diff --git a/system/osi/include/properties.h b/system/osi/include/properties.h
index ee99e99..b186f4f 100644
--- a/system/osi/include/properties.h
+++ b/system/osi/include/properties.h
@@ -41,3 +41,10 @@
 // returns the value of |key| truncated and coerced into an
 // int32_t. If the property is not set, then the |default_value| is used.
 int32_t osi_property_get_int32(const char* key, int32_t default_value);
+
+// Adapter function for property_get_bool in
+// libcutils/include/cutils/properties.h
+//
+// returns the value of |key| coerced into a bool. If the property is not set,
+// then the |default_value| is used.
+bool osi_property_get_bool(const char* key, bool default_value);
\ No newline at end of file
diff --git a/system/osi/src/properties.cc b/system/osi/src/properties.cc
index d2bdd28..c20b39f 100644
--- a/system/osi/src/properties.cc
+++ b/system/osi/src/properties.cc
@@ -60,3 +60,11 @@
   return property_get_int32(key, default_value);
 #endif  // defined(OS_GENERIC)
 }
+
+bool osi_property_get_bool(const char* key, bool default_value) {
+#if defined(OS_GENERIC)
+  return default_value;
+#else
+  return property_get_bool(key, default_value);
+#endif  // defined(OS_GENERIC)
+}
\ No newline at end of file
diff --git a/system/osi/test/properties_test.cc b/system/osi/test/properties_test.cc
index d9ef800..499f6f3 100644
--- a/system/osi/test/properties_test.cc
+++ b/system/osi/test/properties_test.cc
@@ -53,4 +53,4 @@
 
   int32_t received = osi_property_get_int32("very.useful.set.test", 84);
   ASSERT_EQ(received, 42);
-}
+}
\ No newline at end of file
diff --git a/system/stack/a2dp/a2dp_aac_encoder.cc b/system/stack/a2dp/a2dp_aac_encoder.cc
index c87f018..135595c 100644
--- a/system/stack/a2dp/a2dp_aac_encoder.cc
+++ b/system/stack/a2dp/a2dp_aac_encoder.cc
@@ -109,7 +109,7 @@
                                              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);
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read);
 
 bool A2DP_LoadEncoderAac(void) {
   // Nothing to do - the library is statically linked
@@ -587,6 +587,7 @@
       .numOutBytes = 0, .numInSamples = 0, .numAncBytes = 0};
 
   uint32_t count;
+  uint32_t total_bytes_read = 0;
   int written = 0;
 
   while (nb_frame) {
@@ -601,7 +602,8 @@
       //
       // Read the PCM data and encode it
       //
-      if (a2dp_aac_read_feeding(read_buffer)) {
+      uint32_t bytes_read = 0;
+      if (a2dp_aac_read_feeding(read_buffer, &bytes_read)) {
         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__);
@@ -636,6 +638,7 @@
         // no more pcm to read
         nb_frame = 0;
       }
+      total_bytes_read += bytes_read;
     } while ((written == 0) && nb_frame);
 
     // NOTE: We don't check whether the packet will fit in the MTU,
@@ -654,7 +657,9 @@
 
       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;
+      if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                total_bytes_read))
+        return;
     } else {
       a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++;
       osi_free(p_buf);
@@ -662,7 +667,7 @@
   }
 }
 
-static bool a2dp_aac_read_feeding(uint8_t* read_buffer) {
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read) {
   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;
@@ -674,6 +679,7 @@
   uint32_t nb_byte_read =
       a2dp_aac_encoder_cb.read_callback(read_buffer, read_size);
   a2dp_aac_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;
+  *bytes_read = nb_byte_read;
 
   if (nb_byte_read < read_size) {
     if (nb_byte_read == 0) return false;
diff --git a/system/stack/a2dp/a2dp_sbc_encoder.cc b/system/stack/a2dp/a2dp_sbc_encoder.cc
index 46d0f47..158e696 100644
--- a/system/stack/a2dp/a2dp_sbc_encoder.cc
+++ b/system/stack/a2dp/a2dp_sbc_encoder.cc
@@ -118,7 +118,7 @@
                                     bool* p_restart_input,
                                     bool* p_restart_output,
                                     bool* p_config_updated);
-static bool a2dp_sbc_read_feeding(void);
+static bool a2dp_sbc_read_feeding(uint32_t* bytes);
 static void a2dp_sbc_encode_frames(uint8_t nb_frame);
 static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
                                              uint8_t* num_of_frames,
@@ -529,8 +529,11 @@
       p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
 
   uint8_t last_frame_len = 0;
+
   while (nb_frame) {
     BT_HDR* p_buf = (BT_HDR*)osi_malloc(A2DP_SBC_BUFFER_SIZE);
+    uint32_t bytes_read = 0;
+
     p_buf->offset = A2DP_SBC_OFFSET;
     p_buf->len = 0;
     p_buf->layer_specific = 0;
@@ -540,11 +543,11 @@
       /* Fill allocated buffer with 0 */
       memset(a2dp_sbc_encoder_cb.pcmBuffer, 0,
              blocm_x_subband * p_encoder_params->s16NumOfChannels);
-
       //
       // Read the PCM data and encode it. If necessary, upsample the data.
       //
-      if (a2dp_sbc_read_feeding()) {
+      uint32_t num_bytes = 0;
+      if (a2dp_sbc_read_feeding(&num_bytes)) {
         uint8_t* output = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
         int16_t* input = a2dp_sbc_encoder_cb.pcmBuffer;
         uint16_t output_len = SBC_Encode(p_encoder_params, input, output);
@@ -554,6 +557,8 @@
         p_buf->len += output_len;
         nb_frame--;
         p_buf->layer_specific++;
+
+        bytes_read += num_bytes;
       } else {
         LOG_WARN(LOG_TAG, "%s: underflow %d, %d", __func__, nb_frame,
                  a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue);
@@ -580,7 +585,9 @@
 
       uint8_t done_nb_frame = remain_nb_frame - nb_frame;
       remain_nb_frame = nb_frame;
-      if (!a2dp_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+      if (!a2dp_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                bytes_read))
+        return;
     } else {
       a2dp_sbc_encoder_cb.stats.media_read_total_dropped_packets++;
       osi_free(p_buf);
@@ -588,7 +595,7 @@
   }
 }
 
-static bool a2dp_sbc_read_feeding(void) {
+static bool a2dp_sbc_read_feeding(uint32_t* bytes_read) {
   SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
   uint16_t blocm_x_subband =
       p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
@@ -639,6 +646,7 @@
     a2dp_sbc_encoder_cb.stats.media_read_total_actual_read_bytes +=
         nb_byte_read;
 
+    *bytes_read = nb_byte_read;
     if (nb_byte_read != read_size) {
       a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue += nb_byte_read;
       return false;
diff --git a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc
index 8500382..ce52684 100644
--- a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc
+++ b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -395,6 +395,7 @@
               framing_params->pcm_reads, framing_params->pcm_bytes_per_read);
   size_t encoded_ptr_index = 0;
   size_t pcm_bytes_encoded = 0;
+  uint32_t bytes_read = 0;
   a2dp_aptx_encoder_cb.stats.media_read_total_expected_packets++;
   a2dp_aptx_encoder_cb.stats.media_read_total_expected_reads_count +=
       framing_params->pcm_reads;
@@ -404,6 +405,7 @@
     uint16_t read_buffer16[A2DP_APTX_MAX_PCM_BYTES_PER_READ / sizeof(uint16_t)];
     size_t pcm_bytes_read = a2dp_aptx_encoder_cb.read_callback(
         (uint8_t*)read_buffer16, framing_params->pcm_bytes_per_read);
+    bytes_read += pcm_bytes_read;
     a2dp_aptx_encoder_cb.stats.media_read_total_actual_read_bytes +=
         pcm_bytes_read;
     if (pcm_bytes_read < framing_params->pcm_bytes_per_read) {
@@ -435,7 +437,7 @@
   a2dp_aptx_encoder_cb.timestamp += rtp_timestamp;
 
   if (p_buf->len > 0) {
-    a2dp_aptx_encoder_cb.enqueue_callback(p_buf, 1);
+    a2dp_aptx_encoder_cb.enqueue_callback(p_buf, 1, bytes_read);
   } else {
     a2dp_aptx_encoder_cb.stats.media_read_total_dropped_packets++;
     osi_free(p_buf);
diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
index 1e2f571..a57ba8d 100644
--- a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
+++ b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -380,6 +380,7 @@
               framing_params->pcm_reads, framing_params->pcm_bytes_per_read);
   size_t encoded_ptr_index = 0;
   size_t pcm_bytes_encoded = 0;
+  uint32_t bytes_read = 0;
   a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_packets++;
   a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_reads_count +=
       framing_params->pcm_reads;
@@ -390,6 +391,7 @@
         read_buffer32[A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ / sizeof(uint32_t)];
     size_t pcm_bytes_read = a2dp_aptx_hd_encoder_cb.read_callback(
         (uint8_t*)read_buffer32, framing_params->pcm_bytes_per_read);
+    bytes_read += pcm_bytes_read;
     a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_read_bytes +=
         pcm_bytes_read;
     if (pcm_bytes_read < framing_params->pcm_bytes_per_read) {
@@ -422,7 +424,7 @@
   a2dp_aptx_hd_encoder_cb.timestamp += rtp_timestamp;
 
   if (p_buf->len > 0) {
-    a2dp_aptx_hd_encoder_cb.enqueue_callback(p_buf, 1);
+    a2dp_aptx_hd_encoder_cb.enqueue_callback(p_buf, 1, bytes_read);
   } else {
     a2dp_aptx_hd_encoder_cb.stats.media_read_total_dropped_packets++;
     osi_free(p_buf);
diff --git a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc
index da8e5aa..9da6afe 100644
--- a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc
+++ b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc
@@ -180,7 +180,7 @@
                                               uint8_t* num_of_frames,
                                               uint64_t timestamp_us);
 static void a2dp_ldac_encode_frames(uint8_t nb_frame);
-static bool a2dp_ldac_read_feeding(uint8_t* read_buffer);
+static bool a2dp_ldac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read);
 static std::string quality_mode_index_to_name(int quality_mode_index);
 
 static void* load_func(const char* func_name) {
@@ -627,6 +627,7 @@
   int32_t out_frames = 0;
   int written = 0;
 
+  uint32_t bytes_read = 0;
   while (nb_frame) {
     BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
     p_buf->offset = A2DP_LDAC_OFFSET;
@@ -639,7 +640,9 @@
       //
       // Read the PCM data and encode it
       //
-      if (a2dp_ldac_read_feeding(read_buffer)) {
+      uint32_t temp_bytes_read = 0;
+      if (a2dp_ldac_read_feeding(read_buffer, &temp_bytes_read)) {
+        bytes_read += temp_bytes_read;
         uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
         if (a2dp_ldac_encoder_cb.ldac_handle == NULL) {
           LOG_ERROR(LOG_TAG, "%s: invalid LDAC handle", __func__);
@@ -689,7 +692,9 @@
 
       uint8_t done_nb_frame = remain_nb_frame - nb_frame;
       remain_nb_frame = nb_frame;
-      if (!a2dp_ldac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+      if (!a2dp_ldac_encoder_cb.enqueue_callback(p_buf, done_nb_frame,
+                                                 bytes_read))
+        return;
     } else {
       // NOTE: Unlike the execution path for other codecs, it is normal for
       // LDAC to NOT write encoded data to the last buffer if there wasn't
@@ -701,7 +706,7 @@
   }
 }
 
-static bool a2dp_ldac_read_feeding(uint8_t* read_buffer) {
+static bool a2dp_ldac_read_feeding(uint8_t* read_buffer, uint32_t* bytes_read) {
   uint32_t read_size = LDACBT_ENC_LSU *
                        a2dp_ldac_encoder_cb.feeding_params.channel_count *
                        a2dp_ldac_encoder_cb.feeding_params.bits_per_sample / 8;
@@ -723,6 +728,7 @@
   }
   a2dp_ldac_encoder_cb.stats.media_read_total_actual_reads_count++;
 
+  *bytes_read = nb_byte_read;
   return true;
 }
 
diff --git a/system/stack/avdt/avdt_msg.cc b/system/stack/avdt/avdt_msg.cc
index 618424f..b930b06 100644
--- a/system/stack/avdt/avdt_msg.cc
+++ b/system/stack/avdt/avdt_msg.cc
@@ -469,8 +469,6 @@
 static void avdt_msg_bld_svccap(uint8_t** p, tAVDT_MSG* p_msg) {
   AvdtpSepConfig cfg = *p_msg->svccap.p_cfg;
 
-  /* make sure the delay report category is not reported */
-  cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
   avdt_msg_bld_cfg(p, &cfg);
 }
 
@@ -626,6 +624,8 @@
         break;
 
       case AVDT_CAT_DELAY_RPT:
+        AVDT_TRACE_DEBUG("%s: Remote device supports delay reporting",
+                         __func__);
         break;
 
       default:
diff --git a/system/stack/include/a2dp_codec_api.h b/system/stack/include/a2dp_codec_api.h
index 0db1f16..dbae736 100644
--- a/system/stack/include/a2dp_codec_api.h
+++ b/system/stack/include/a2dp_codec_api.h
@@ -453,8 +453,11 @@
 // responsible for freeing |p_buf|.
 // |frames_n| is the number of audio frames in |p_buf| - it is used for
 // statistics purpose.
+// |num_bytes| is the number of audio bytes in |p_buf| - it is used for
+// delay reporting.
 // Returns true if the packet was enqueued, otherwise false.
-typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n);
+typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n,
+                                               uint32_t num_bytes);
 
 //
 // A2DP encoder callbacks interface.
diff --git a/system/stack/include/avdt_api.h b/system/stack/include/avdt_api.h
index 8cbbb6c..5d2135b 100644
--- a/system/stack/include/avdt_api.h
+++ b/system/stack/include/avdt_api.h
@@ -32,7 +32,7 @@
  *  Constants
  ****************************************************************************/
 #ifndef AVDT_VERSION
-#define AVDT_VERSION 0x0102
+#define AVDT_VERSION 0x0103
 #endif
 #define AVDT_VERSION_1_3 0x0103