Support setting BT controller Low Latency mode(1/2)

Handle audio api StartRequest and SetLatencyMode in a2dp to send stream latency
through btif_av to bta event.

Bug: 240637363
Bug: 223126227
Tag: #feature
Ignore-AOSP-First: TM QPR1 feature
Test: test on sink device support dynamic spatial audio
Change-Id: I9ad4a23a58eeca6128a9f04a530ae6c90c773da5
diff --git a/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc b/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc
index faa735a..1ea3b3c 100644
--- a/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc
+++ b/system/audio_hal_interface/aidl/a2dp_encoding_aidl.cc
@@ -90,7 +90,7 @@
      * procedure is completed, othewise send it now.
      */
     a2dp_pending_cmd_ = A2DP_CTRL_CMD_START;
-    btif_av_stream_start();
+    btif_av_stream_start_with_latency(is_low_latency);
     if (btif_av_get_peer_sep() != AVDT_TSEP_SRC) {
       LOG(INFO) << __func__ << ": accepted";
       return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_PENDING);
@@ -138,6 +138,10 @@
   btif_av_stream_stop(RawAddress::kEmpty);
 }
 
+void A2dpTransport::SetLowLatency(bool is_low_latency) {
+  btif_av_set_low_latency(is_low_latency);
+}
+
 bool A2dpTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                             uint64_t* total_bytes_read,
                                             timespec* data_position) {
@@ -569,4 +573,4 @@
 }  // namespace a2dp
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/audio_hal_interface/aidl/a2dp_transport.h b/system/audio_hal_interface/aidl/a2dp_transport.h
index 5732754..1b53da0 100644
--- a/system/audio_hal_interface/aidl/a2dp_transport.h
+++ b/system/audio_hal_interface/aidl/a2dp_transport.h
@@ -39,6 +39,8 @@
 
   void StopRequest() override;
 
+  void SetLowLatency(bool is_low_latency) override;
+
   bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                uint64_t* total_bytes_read,
                                timespec* data_position) override;
@@ -69,4 +71,4 @@
 }  // namespace a2dp
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc b/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc
index d9ce929..813648a 100644
--- a/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc
+++ b/system/audio_hal_interface/aidl/bluetooth_audio_port_impl.cc
@@ -137,6 +137,7 @@
     LatencyMode latency_mode) {
   bool is_low_latency = latency_mode == LatencyMode::LOW_LATENCY ? true : false;
   invoke_switch_buffer_size_cb(is_low_latency);
+  transport_instance_->SetLowLatency(is_low_latency);
   return ndk::ScopedAStatus::ok();
 }
 
@@ -148,4 +149,4 @@
 
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc
index 91b4dca..1cab476 100644
--- a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc
+++ b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc
@@ -74,6 +74,8 @@
     }
   }
 
+  void SetLowLatency(bool is_low_latency) override {}
+
   bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                uint64_t* total_bytes_read,
                                timespec* data_position) override {
@@ -267,4 +269,4 @@
 }  // namespace hearing_aid
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc
index 80aed9e..ffc213f 100644
--- a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc
+++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc
@@ -93,6 +93,8 @@
   }
 }
 
+void LeAudioTransport::SetLowLatency(bool is_low_latency) {}
+
 bool LeAudioTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                                uint64_t* total_bytes_processed,
                                                timespec* data_position) {
@@ -244,6 +246,10 @@
 
 void LeAudioSinkTransport::StopRequest() { transport_->StopRequest(); }
 
+void LeAudioSinkTransport::SetLowLatency(bool is_low_latency) {
+  transport_->SetLowLatency(is_low_latency);
+}
+
 bool LeAudioSinkTransport::GetPresentationPosition(
     uint64_t* remote_delay_report_ns, uint64_t* total_bytes_read,
     timespec* data_position) {
@@ -327,6 +333,10 @@
 
 void LeAudioSourceTransport::StopRequest() { transport_->StopRequest(); }
 
+void LeAudioSourceTransport::SetLowLatency(bool is_low_latency) {
+  transport_->SetLowLatency(is_low_latency);
+}
+
 bool LeAudioSourceTransport::GetPresentationPosition(
     uint64_t* remote_delay_report_ns, uint64_t* total_bytes_written,
     timespec* data_position) {
@@ -538,4 +548,4 @@
 }  // namespace le_audio
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/audio_hal_interface/aidl/le_audio_software_aidl.h b/system/audio_hal_interface/aidl/le_audio_software_aidl.h
index 2958d26..1b54c84 100644
--- a/system/audio_hal_interface/aidl/le_audio_software_aidl.h
+++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.h
@@ -76,6 +76,8 @@
 
   void StopRequest();
 
+  void SetLowLatency(bool is_low_latency);
+
   bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                uint64_t* total_bytes_processed,
                                timespec* data_position);
@@ -129,6 +131,8 @@
 
   void StopRequest() override;
 
+  void SetLowLatency(bool is_low_latency) override;
+
   bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                uint64_t* total_bytes_read,
                                timespec* data_position) override;
@@ -181,6 +185,8 @@
 
   void StopRequest() override;
 
+  void SetLowLatency(bool is_low_latency) override;
+
   bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                uint64_t* total_bytes_written,
                                timespec* data_position) override;
@@ -214,4 +220,4 @@
 }  // namespace le_audio
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/audio_hal_interface/aidl/transport_instance.h b/system/audio_hal_interface/aidl/transport_instance.h
index 11b9a21..e7967ab 100644
--- a/system/audio_hal_interface/aidl/transport_instance.h
+++ b/system/audio_hal_interface/aidl/transport_instance.h
@@ -71,6 +71,8 @@
 
   virtual void StopRequest() = 0;
 
+  virtual void SetLowLatency(bool is_low_latency) = 0;
+
   virtual bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                                        uint64_t* total_bytes_readed,
                                        timespec* data_position) = 0;
@@ -122,4 +124,4 @@
 
 }  // namespace aidl
 }  // namespace audio
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index 9e48782..92a8af7 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -1824,6 +1824,7 @@
     if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
       notify_start_failed(p_scb);
     } else {
+      bta_av_set_use_latency_mode(p_scb, p_data->do_start.use_latency_mode);
       bta_av_start_ok(p_scb, NULL);
     }
     return;
@@ -1858,6 +1859,8 @@
     LOG_ERROR("%s: AVDT_StartReq failed for peer %s result:%d", __func__,
               p_scb->PeerAddress().ToString().c_str(), result);
     bta_av_start_failed(p_scb, p_data);
+  } else {
+    bta_av_set_use_latency_mode(p_scb, p_data->do_start.use_latency_mode);
   }
   LOG_INFO(
       "%s: peer %s start requested: sco_occupied:%s role:0x%x "
diff --git a/system/bta/av/bta_av_act.cc b/system/bta/av/bta_av_act.cc
index 177377c..9d3c90d 100644
--- a/system/bta/av/bta_av_act.cc
+++ b/system/bta/av/bta_av_act.cc
@@ -1339,6 +1339,19 @@
   alarm_cancel(p_scb->link_signalling_timer);
 }
 
+/*******************************************************************************
+ *
+ * Function         bta_av_set_use_latency_mode
+ *
+ * Description      Sets stream use latency mode.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_set_use_latency_mode(tBTA_AV_SCB* p_scb, bool use_latency_mode) {
+  L2CA_UseLatencyMode(p_scb->PeerAddress(), use_latency_mode);
+}
+
 /**
  * Find the index for the free LCB entry to use.
  *
diff --git a/system/bta/av/bta_av_api.cc b/system/bta/av/bta_av_api.cc
index 9a8ccfd..defaea1 100644
--- a/system/bta/av/bta_av_api.cc
+++ b/system/bta/av/bta_av_api.cc
@@ -215,13 +215,17 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AvStart(tBTA_AV_HNDL handle) {
-  LOG_INFO("Starting audio/video stream data transfer bta_handle:%hhu", handle);
+void BTA_AvStart(tBTA_AV_HNDL handle, bool use_latency_mode) {
+  LOG_INFO(
+      "Starting audio/video stream data transfer bta_handle:%hhu, "
+      "use_latency_mode:%s",
+      handle, use_latency_mode ? "true" : "false");
 
-  BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
-
-  p_buf->event = BTA_AV_API_START_EVT;
-  p_buf->layer_specific = handle;
+  tBTA_AV_DO_START* p_buf =
+      (tBTA_AV_DO_START*)osi_malloc(sizeof(tBTA_AV_DO_START));
+  p_buf->hdr.event = BTA_AV_API_START_EVT;
+  p_buf->hdr.layer_specific = handle;
+  p_buf->use_latency_mode = use_latency_mode;
 
   bta_sys_sendmsg(p_buf);
 }
@@ -613,3 +617,26 @@
 
   bta_sys_sendmsg(p_buf);
 }
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvSetLatency
+ *
+ * Description      Set audio/video stream latency.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvSetLatency(tBTA_AV_HNDL handle, bool is_low_latency) {
+  LOG_INFO(
+      "Set audio/video stream low latency bta_handle:%hhu, is_low_latency:%s",
+      handle, is_low_latency ? "true" : "false");
+
+  tBTA_AV_API_SET_LATENCY* p_buf =
+      (tBTA_AV_API_SET_LATENCY*)osi_malloc(sizeof(tBTA_AV_API_SET_LATENCY));
+  p_buf->hdr.event = BTA_AV_API_SET_LATENCY_EVT;
+  p_buf->hdr.layer_specific = handle;
+  p_buf->is_low_latency = is_low_latency;
+
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/system/bta/av/bta_av_int.h b/system/bta/av/bta_av_int.h
index 0b3e914..49b3ce4 100644
--- a/system/bta/av/bta_av_int.h
+++ b/system/bta/av/bta_av_int.h
@@ -114,7 +114,8 @@
   BTA_AV_AVDT_RPT_CONN_EVT,
   BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as
                            the *AP_*EVT */
-  BTA_AV_API_STOP_EVT
+  BTA_AV_API_STOP_EVT,
+  BTA_AV_API_SET_LATENCY_EVT,
 };
 
 /* events for AV control block state machine */
@@ -264,6 +265,18 @@
   uint16_t uuid; /* uuid of initiator */
 } tBTA_AV_API_OPEN;
 
+/* data type for BTA_AV_API_SET_LATENCY_EVT */
+typedef struct {
+  BT_HDR_RIGID hdr;
+  bool is_low_latency;
+} tBTA_AV_API_SET_LATENCY;
+
+/* data type for BTA_AV_API_START_EVT and bta_av_do_start */
+typedef struct {
+  BT_HDR_RIGID hdr;
+  bool use_latency_mode;
+} tBTA_AV_DO_START;
+
 /* data type for BTA_AV_API_STOP_EVT */
 typedef struct {
   BT_HDR_RIGID hdr;
@@ -429,6 +442,8 @@
   tBTA_AV_API_ENABLE api_enable;
   tBTA_AV_API_REG api_reg;
   tBTA_AV_API_OPEN api_open;
+  tBTA_AV_API_SET_LATENCY api_set_latency;
+  tBTA_AV_DO_START do_start;
   tBTA_AV_API_STOP api_stop;
   tBTA_AV_API_DISCNT api_discnt;
   tBTA_AV_API_PROTECT_REQ api_protect_req;
@@ -724,6 +739,8 @@
 
 /* nsm action functions */
 extern void bta_av_api_disconnect(tBTA_AV_DATA* p_data);
+extern void bta_av_set_use_latency_mode(tBTA_AV_SCB* p_scb,
+                                        bool use_latency_mode);
 extern void bta_av_sig_chg(tBTA_AV_DATA* p_data);
 extern void bta_av_signalling_timer(tBTA_AV_DATA* p_data);
 extern void bta_av_rc_disc_done(tBTA_AV_DATA* p_data);
diff --git a/system/bta/include/bta_av_api.h b/system/bta/include/bta_av_api.h
index fd1dd00..9112a32 100644
--- a/system/bta/include/bta_av_api.h
+++ b/system/bta/include/bta_av_api.h
@@ -500,7 +500,7 @@
  * Returns          void
  *
  ******************************************************************************/
-void BTA_AvStart(tBTA_AV_HNDL handle);
+void BTA_AvStart(tBTA_AV_HNDL handle, bool use_latency_mode);
 
 /*******************************************************************************
  *
@@ -676,6 +676,17 @@
 
 /*******************************************************************************
  *
+ * Function         BTA_AvSetLatency
+ *
+ * Description      Set audio/video stream latency.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvSetLatency(tBTA_AV_HNDL handle, bool is_low_latency);
+
+/*******************************************************************************
+ *
  * Function         BTA_AvOffloadStart
  *
  * Description      Request Starting of A2DP Offload.
diff --git a/system/btif/include/btif_av.h b/system/btif/include/btif_av.h
index 0a3095e..09c0e27 100644
--- a/system/btif/include/btif_av.h
+++ b/system/btif/include/btif_av.h
@@ -52,6 +52,11 @@
 void btif_av_stream_start(void);
 
 /**
+ * Start streaming with latency setting.
+ */
+void btif_av_stream_start_with_latency(bool use_latency_mode);
+
+/**
  * Stop streaming.
  *
  * @param peer_address the peer address or RawAddress::kEmpty to stop all peers
@@ -228,4 +233,11 @@
  */
 void btif_av_set_dynamic_audio_buffer_size(uint8_t dynamic_audio_buffer_size);
 
+/**
+ * Enable/disable the low latency
+ *
+ * @param is_low_latency to set
+ */
+void btif_av_set_low_latency(bool is_low_latency);
+
 #endif /* BTIF_AV_H */
diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc
index 8ae8db8..7f613b8 100644
--- a/system/btif/src/btif_av.cc
+++ b/system/btif/src/btif_av.cc
@@ -80,6 +80,14 @@
   RawAddress peer_address;
 } btif_av_sink_config_req_t;
 
+typedef struct {
+  bool use_latency_mode;
+} btif_av_start_stream_req_t;
+
+typedef struct {
+  bool is_low_latency;
+} btif_av_set_latency_req_t;
+
 /**
  * BTIF AV events
  */
@@ -96,6 +104,7 @@
   BTIF_AV_AVRCP_OPEN_EVT,
   BTIF_AV_AVRCP_CLOSE_EVT,
   BTIF_AV_AVRCP_REMOTE_PLAY_EVT,
+  BTIF_AV_SET_LATENCY_REQ_EVT,
 } btif_av_sm_event_t;
 
 class BtifAvEvent {
@@ -340,6 +349,11 @@
   bool SelfInitiatedConnection() const { return self_initiated_connection_; }
   void SetSelfInitiatedConnection(bool v) { self_initiated_connection_ = v; }
 
+  bool UseLatencyMode() const { return use_latency_mode_; }
+  void SetUseLatencyMode(bool use_latency_mode) {
+    use_latency_mode_ = use_latency_mode;
+  }
+
  private:
   const RawAddress peer_address_;
   const uint8_t peer_sep_;  // SEP type of peer device
@@ -353,6 +367,7 @@
   bool is_silenced_;
   uint16_t delay_report_;
   bool mandatory_codec_preferred_ = false;
+  bool use_latency_mode_ = false;
 };
 
 class BtifAvSource {
@@ -769,6 +784,7 @@
     CASE_RETURN_STR(BTIF_AV_AVRCP_OPEN_EVT)
     CASE_RETURN_STR(BTIF_AV_AVRCP_CLOSE_EVT)
     CASE_RETURN_STR(BTIF_AV_AVRCP_REMOTE_PLAY_EVT)
+    CASE_RETURN_STR(BTIF_AV_SET_LATENCY_REQ_EVT)
     default:
       return "UNKNOWN_EVENT";
   }
@@ -1908,14 +1924,22 @@
     case BTIF_AV_ACL_DISCONNECTED:
       break;  // Ignore
 
-    case BTIF_AV_START_STREAM_REQ_EVT:
+    case BTIF_AV_START_STREAM_REQ_EVT: {
       LOG_INFO("%s: Peer %s : event=%s flags=%s", __PRETTY_FUNCTION__,
                peer_.PeerAddress().ToString().c_str(),
                BtifAvEvent::EventName(event).c_str(),
                peer_.FlagsToString().c_str());
-      BTA_AvStart(peer_.BtaHandle());
+      if (p_data) {
+        const btif_av_start_stream_req_t* p_start_steam_req =
+            static_cast<const btif_av_start_stream_req_t*>(p_data);
+        LOG_INFO("Stream use_latency_mode=%s",
+                 p_start_steam_req->use_latency_mode ? "true" : "false");
+        peer_.SetUseLatencyMode(p_start_steam_req->use_latency_mode);
+      }
+
+      BTA_AvStart(peer_.BtaHandle(), peer_.UseLatencyMode());
       peer_.SetFlags(BtifAvPeer::kFlagPendingStart);
-      break;
+    } break;
 
     case BTA_AV_START_EVT: {
       LOG_INFO(
@@ -2039,7 +2063,7 @@
         LOG(INFO) << __PRETTY_FUNCTION__ << " : Peer " << peer_.PeerAddress()
                   << " : Reconfig done - calling BTA_AvStart("
                   << loghex(peer_.BtaHandle()) << ")";
-        BTA_AvStart(peer_.BtaHandle());
+        BTA_AvStart(peer_.BtaHandle(), peer_.UseLatencyMode());
       }
       break;
 
@@ -2070,6 +2094,18 @@
 
       CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
 
+    case BTIF_AV_SET_LATENCY_REQ_EVT: {
+      const btif_av_set_latency_req_t* p_set_latency_req =
+          static_cast<const btif_av_set_latency_req_t*>(p_data);
+      LOG_INFO("Peer %s : event=%s flags=%s is_low_latency=%s",
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str(),
+               p_set_latency_req->is_low_latency ? "true" : "false");
+
+      BTA_AvSetLatency(peer_.BtaHandle(), p_set_latency_req->is_low_latency);
+    } break;
+
     default:
       BTIF_TRACE_WARNING("%s: Peer %s : Unhandled event=%s",
                          __PRETTY_FUNCTION__,
@@ -2273,6 +2309,18 @@
       btif_a2dp_on_offload_started(peer_.PeerAddress(), p_av->status);
       break;
 
+    case BTIF_AV_SET_LATENCY_REQ_EVT: {
+      const btif_av_set_latency_req_t* p_set_latency_req =
+          static_cast<const btif_av_set_latency_req_t*>(p_data);
+      LOG_INFO("Peer %s : event=%s flags=%s is_low_latency=%s",
+               peer_.PeerAddress().ToString().c_str(),
+               BtifAvEvent::EventName(event).c_str(),
+               peer_.FlagsToString().c_str(),
+               p_set_latency_req->is_low_latency ? "true" : "false");
+
+      BTA_AvSetLatency(peer_.BtaHandle(), p_set_latency_req->is_low_latency);
+    } break;
+
       CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
 
     default:
@@ -3117,6 +3165,24 @@
                                    BTIF_AV_START_STREAM_REQ_EVT);
 }
 
+void btif_av_stream_start_with_latency(bool use_latency_mode) {
+  LOG_INFO("%s", __func__);
+
+  btif_av_start_stream_req_t start_stream_req;
+  start_stream_req.use_latency_mode = use_latency_mode;
+  BtifAvEvent btif_av_event(BTIF_AV_START_STREAM_REQ_EVT, &start_stream_req,
+                            sizeof(start_stream_req));
+  LOG_INFO("peer_address=%s event=%s use_latency_mode=%s",
+           btif_av_source_active_peer().ToString().c_str(),
+           btif_av_event.ToString().c_str(),
+           use_latency_mode ? "true" : "false");
+
+  do_in_main_thread(FROM_HERE, base::Bind(&btif_av_handle_event,
+                                          AVDT_TSEP_SNK,  // peer_sep
+                                          btif_av_source_active_peer(),
+                                          kBtaHandleUnknown, btif_av_event));
+}
+
 void src_do_suspend_in_main_thread(btif_av_sm_event_t event) {
   if (event != BTIF_AV_SUSPEND_STREAM_REQ_EVT &&
       event != BTIF_AV_STOP_STREAM_REQ_EVT)
@@ -3534,3 +3600,19 @@
 void btif_av_set_dynamic_audio_buffer_size(uint8_t dynamic_audio_buffer_size) {
   btif_a2dp_source_set_dynamic_audio_buffer_size(dynamic_audio_buffer_size);
 }
+
+void btif_av_set_low_latency(bool is_low_latency) {
+  LOG_INFO("is_low_latency: %s", is_low_latency ? "true" : "false");
+
+  btif_av_set_latency_req_t set_latency_req;
+  set_latency_req.is_low_latency = is_low_latency;
+  BtifAvEvent btif_av_event(BTIF_AV_SET_LATENCY_REQ_EVT, &set_latency_req,
+                            sizeof(set_latency_req));
+  LOG_INFO("peer_address=%s event=%s",
+           btif_av_source_active_peer().ToString().c_str(),
+           btif_av_event.ToString().c_str());
+  do_in_main_thread(FROM_HERE, base::Bind(&btif_av_handle_event,
+                                          AVDT_TSEP_SNK,  // peer_sep
+                                          btif_av_source_active_peer(),
+                                          kBtaHandleUnknown, btif_av_event));
+}
diff --git a/system/stack/include/l2c_api.h b/system/stack/include/l2c_api.h
index 92cf17f..1a2bc40 100644
--- a/system/stack/include/l2c_api.h
+++ b/system/stack/include/l2c_api.h
@@ -636,6 +636,18 @@
 
 /*******************************************************************************
  *
+ * Function         L2CA_UseLatencyMode
+ *
+ * Description      Sets use latency mode for an ACL channel.
+ *
+ * Returns          true if a valid channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_UseLatencyMode(const RawAddress& bd_addr,
+                                bool use_latency_mode);
+
+/*******************************************************************************
+ *
  * Function         L2CA_SetAclPriority
  *
  * Description      Sets the transmission priority for an ACL channel.
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 6eedcbb..a7eaf6a 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -1029,6 +1029,29 @@
 
 /*******************************************************************************
  *
+ * Function         L2CA_UseLatencyMode
+ *
+ * Description      Sets acl use latency mode.
+ *
+ * Returns          true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_UseLatencyMode(const RawAddress& bd_addr, bool use_latency_mode) {
+  /* Find the link control block for the acl channel */
+  tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+  if (p_lcb == nullptr) {
+    LOG_WARN("L2CAP - no LCB for L2CA_SetUseLatencyMode, BDA: %s",
+             bd_addr.ToString().c_str());
+    return false;
+  }
+  LOG_INFO("BDA: %s, use_latency_mode: %s", bd_addr.ToString().c_str(),
+           use_latency_mode ? "true" : "false");
+  p_lcb->use_latency_mode = use_latency_mode;
+  return true;
+}
+
+/*******************************************************************************
+ *
  * Function         L2CA_SetAclPriority
  *
  * Description      Sets the transmission priority for a channel.
diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h
index 39ba1ec..b6f70ae 100644
--- a/system/stack/l2cap/l2c_int.h
+++ b/system/stack/l2cap/l2c_int.h
@@ -497,6 +497,8 @@
     return false;
   }
 
+  bool use_latency_mode = false;
+
   tL2C_CCB* p_fixed_ccbs[L2CAP_NUM_FIXED_CHNLS];
 
  private:
diff --git a/system/test/mock/mock_bta_av_api.cc b/system/test/mock/mock_bta_av_api.cc
index 4c4e93d..6017d03 100644
--- a/system/test/mock/mock_bta_av_api.cc
+++ b/system/test/mock/mock_bta_av_api.cc
@@ -93,7 +93,9 @@
                                  uint8_t buf_len) {
   mock_function_count_map[__func__]++;
 }
-void BTA_AvStart(tBTA_AV_HNDL handle) { mock_function_count_map[__func__]++; }
+void BTA_AvStart(tBTA_AV_HNDL handle, bool use_latency_mode) {
+  mock_function_count_map[__func__]++;
+}
 void BTA_AvStop(tBTA_AV_HNDL handle, bool suspend) {
   mock_function_count_map[__func__]++;
 }
@@ -105,3 +107,6 @@
                      uint8_t* p_data, uint16_t len, uint32_t company_id) {
   mock_function_count_map[__func__]++;
 }
+void BTA_AvSetLatency(tBTA_AV_HNDL handle, bool is_low_latency) {
+  mock_function_count_map[__func__]++;
+}
diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc
index 96d4eef..81e71b0 100644
--- a/system/test/mock/mock_stack_l2cap_api.cc
+++ b/system/test/mock/mock_stack_l2cap_api.cc
@@ -83,6 +83,7 @@
 struct L2CA_GetRemoteCid L2CA_GetRemoteCid;
 struct L2CA_SetIdleTimeoutByBdAddr L2CA_SetIdleTimeoutByBdAddr;
 struct L2CA_SetTraceLevel L2CA_SetTraceLevel;
+struct L2CA_UseLatencyMode L2CA_UseLatencyMode;
 struct L2CA_SetAclPriority L2CA_SetAclPriority;
 struct L2CA_SetTxPriority L2CA_SetTxPriority;
 struct L2CA_GetPeerFeatures L2CA_GetPeerFeatures;
@@ -210,6 +211,11 @@
   mock_function_count_map[__func__]++;
   return test::mock::stack_l2cap_api::L2CA_SetTraceLevel(new_level);
 }
+bool L2CA_UseLatencyMode(const RawAddress& bd_addr, bool use_latency_mode) {
+  mock_function_count_map[__func__]++;
+  return test::mock::stack_l2cap_api::L2CA_UseLatencyMode(bd_addr,
+                                                          use_latency_mode);
+}
 bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) {
   mock_function_count_map[__func__]++;
   return test::mock::stack_l2cap_api::L2CA_SetAclPriority(bd_addr, priority);
diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h
index 6f682fc..b3e52b5 100644
--- a/system/test/mock/mock_stack_l2cap_api.h
+++ b/system/test/mock/mock_stack_l2cap_api.h
@@ -302,6 +302,17 @@
   uint8_t operator()(uint8_t new_level) { return body(new_level); };
 };
 extern struct L2CA_SetTraceLevel L2CA_SetTraceLevel;
+// Name: L2CA_UseLatencyMode
+// Params: const RawAddress& bd_addr, bool use_latency_mode
+// Returns: bool
+struct L2CA_UseLatencyMode {
+  std::function<bool(const RawAddress& bd_addr, bool use_latency_mode)> body{
+      [](const RawAddress& bd_addr, bool use_latency_mode) { return false; }};
+  bool operator()(const RawAddress& bd_addr, bool use_latency_mode) {
+    return body(bd_addr, use_latency_mode);
+  };
+};
+extern struct L2CA_UseLatencyMode L2CA_UseLatencyMode;
 // Name: L2CA_SetAclPriority
 // Params: const RawAddress& bd_addr, tL2CAP_PRIORITY priority
 // Returns: bool