OSDN Git Service

Replace BT_HDR => BT_HDR_RIGID
[android-x86/system-bt.git] / btif / src / btif_a2dp_sink.cc
index aa75d21..fa02a86 100644 (file)
 
 #define LOG_TAG "bt_btif_a2dp_sink"
 
+#include <base/bind.h>
 #include <atomic>
-#include <cstdio>
-#include <cstring>
 #include <mutex>
 #include <string>
 
-#include <base/bind.h>
+#include "bt_target.h"  // Must be first to define build configuration
 
-#include "bt_common.h"
-#include "btif_a2dp.h"
-#include "btif_a2dp_sink.h"
-#include "btif_av.h"
-#include "btif_av_co.h"
-#include "btif_avrcp_audio_track.h"
-#include "btif_util.h"
+#include "btif/include/btif_a2dp_sink.h"
+#include "btif/include/btif_av.h"
+#include "btif/include/btif_av_co.h"
+#include "btif/include/btif_avrcp_audio_track.h"
+#include "btif/include/btif_util.h"  // CASE_RETURN_STR
 #include "common/message_loop_thread.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
-#include "osi/include/osi.h"
+#include "osi/include/osi.h"  // UNUSED_ATTR
+#include "stack/include/bt_types.h"
 
 using bluetooth::common::MessageLoopThread;
 using LockGuard = std::lock_guard<std::mutex>;
@@ -64,16 +64,18 @@ enum {
   BTIF_MEDIA_SINK_DECODER_UPDATE = 1,
   BTIF_MEDIA_SINK_CLEAR_TRACK,
   BTIF_MEDIA_SINK_SET_FOCUS_STATE,
-  BTIF_MEDIA_SINK_AUDIO_RX_FLUSH
+  BTIF_MEDIA_SINK_AUDIO_RX_FLUSH,
+  BTIF_MEDIA_SINK_START,
+  BTIF_MEDIA_SINK_SUSPEND
 };
 
 typedef struct {
-  BT_HDR hdr;
+  BT_HDR_RIGID hdr;
   uint8_t codec_info[AVDT_CODEC_SIZE];
 } tBTIF_MEDIA_SINK_DECODER_UPDATE;
 
 typedef struct {
-  BT_HDR hdr;
+  BT_HDR_RIGID hdr;
   btif_a2dp_sink_focus_state_t focus_state;
 } tBTIF_MEDIA_SINK_FOCUS_UPDATE;
 
@@ -134,7 +136,7 @@ static void btif_a2dp_sink_start_session_delayed(
 static void btif_a2dp_sink_end_session_delayed();
 static void btif_a2dp_sink_shutdown_delayed();
 static void btif_a2dp_sink_cleanup_delayed();
-static void btif_a2dp_sink_command_ready(BT_HDR* p_msg);
+static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg);
 static void btif_a2dp_sink_audio_handle_stop_decoding();
 static void btif_decode_alarm_cb(void* context);
 static void btif_a2dp_sink_audio_handle_start_decoding();
@@ -149,6 +151,8 @@ static void btif_a2dp_sink_set_focus_state_event(
     btif_a2dp_sink_focus_state_t state);
 static void btif_a2dp_sink_audio_rx_flush_event();
 static void btif_a2dp_sink_clear_track_event_req();
+static void btif_a2dp_sink_on_start_event();
+static void btif_a2dp_sink_on_suspend_event();
 
 UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
   switch (event) {
@@ -156,6 +160,8 @@ UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
     CASE_RETURN_STR(BTIF_MEDIA_SINK_CLEAR_TRACK)
     CASE_RETURN_STR(BTIF_MEDIA_SINK_SET_FOCUS_STATE)
     CASE_RETURN_STR(BTIF_MEDIA_SINK_AUDIO_RX_FLUSH)
+    CASE_RETURN_STR(BTIF_MEDIA_SINK_START)
+    CASE_RETURN_STR(BTIF_MEDIA_SINK_SUSPEND)
     default:
       break;
   }
@@ -163,11 +169,11 @@ UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
 }
 
 bool btif_a2dp_sink_init() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
 
   if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
-    LOG_ERROR(LOG_TAG, "%s: A2DP Sink media task already running", __func__);
+    LOG_ERROR("%s: A2DP Sink media task already running", __func__);
     return false;
   }
 
@@ -177,7 +183,7 @@ bool btif_a2dp_sink_init() {
   /* Start A2DP Sink media task */
   btif_a2dp_sink_cb.worker_thread.StartUp();
   if (!btif_a2dp_sink_cb.worker_thread.IsRunning()) {
-    LOG_ERROR(LOG_TAG, "%s: unable to start up media thread", __func__);
+    LOG_ERROR("%s: unable to start up media thread", __func__);
     btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
     return false;
   }
@@ -195,19 +201,19 @@ bool btif_a2dp_sink_init() {
 }
 
 static void btif_a2dp_sink_init_delayed() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
 }
 
 bool btif_a2dp_sink_startup() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   btif_a2dp_sink_cb.worker_thread.DoInThread(
       FROM_HERE, base::BindOnce(btif_a2dp_sink_startup_delayed));
   return true;
 }
 
 static void btif_a2dp_sink_startup_delayed() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
   // Nothing to do
 }
@@ -264,33 +270,32 @@ bool btif_a2dp_sink_restart_session(const RawAddress& old_peer_address,
 }
 
 bool btif_a2dp_sink_end_session(const RawAddress& peer_address) {
-  LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
-           peer_address.ToString().c_str());
+  LOG_INFO("%s: peer_address=%s", __func__, peer_address.ToString().c_str());
   btif_a2dp_sink_cb.worker_thread.DoInThread(
       FROM_HERE, base::BindOnce(btif_a2dp_sink_end_session_delayed));
   return true;
 }
 
 static void btif_a2dp_sink_end_session_delayed() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
   // Nothing to do
 }
 
 void btif_a2dp_sink_shutdown() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   btif_a2dp_sink_cb.worker_thread.DoInThread(
       FROM_HERE, base::BindOnce(btif_a2dp_sink_shutdown_delayed));
 }
 
 static void btif_a2dp_sink_shutdown_delayed() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
   // Nothing to do
 }
 
 void btif_a2dp_sink_cleanup() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
 
   alarm_t* decode_alarm;
 
@@ -320,7 +325,7 @@ void btif_a2dp_sink_cleanup() {
 }
 
 static void btif_a2dp_sink_cleanup_delayed() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
 
   fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, nullptr);
@@ -343,8 +348,8 @@ tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count() {
   return btif_a2dp_sink_cb.channel_count;
 }
 
-static void btif_a2dp_sink_command_ready(BT_HDR* p_msg) {
-  LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
+static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg) {
+  LOG_VERBOSE("%s: event %d %s", __func__, p_msg->event,
               dump_media_event(p_msg->event));
 
   switch (p_msg->event) {
@@ -364,17 +369,23 @@ static void btif_a2dp_sink_command_ready(BT_HDR* p_msg) {
     case BTIF_MEDIA_SINK_AUDIO_RX_FLUSH:
       btif_a2dp_sink_audio_rx_flush_event();
       break;
+    case BTIF_MEDIA_SINK_START:
+      btif_a2dp_sink_on_start_event();
+      break;
+    case BTIF_MEDIA_SINK_SUSPEND:
+      btif_a2dp_sink_on_suspend_event();
+      break;
     default:
-      LOG_ERROR(LOG_TAG, "%s: unknown event %d", __func__, p_msg->event);
+      LOG_ERROR("%s: unknown event %d", __func__, p_msg->event);
       break;
   }
 
   osi_free(p_msg);
-  LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+  LOG_VERBOSE("%s: %s DONE", __func__, dump_media_event(p_msg->event));
 }
 
 void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf =
       reinterpret_cast<tBTIF_MEDIA_SINK_DECODER_UPDATE*>(
           osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE)));
@@ -387,30 +398,61 @@ void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
   p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;
 
   btif_a2dp_sink_cb.worker_thread.DoInThread(
-      FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
+      FROM_HERE,
+      base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
 }
 
 void btif_a2dp_sink_on_idle() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
+  BT_HDR_RIGID* p_buf =
+      reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+  p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
+  btif_a2dp_sink_cb.worker_thread.DoInThread(
+      FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
   if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
   btif_a2dp_sink_audio_handle_stop_decoding();
   btif_a2dp_sink_clear_track_event_req();
 }
 
 void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
+  BT_HDR_RIGID* p_buf =
+      reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+  p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
+  btif_a2dp_sink_cb.worker_thread.DoInThread(
+      FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
   if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
   btif_a2dp_sink_audio_handle_stop_decoding();
 }
 
 void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
+  BT_HDR_RIGID* p_buf =
+      reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+  p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
+  btif_a2dp_sink_cb.worker_thread.DoInThread(
+      FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
   if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
   btif_a2dp_sink_audio_handle_stop_decoding();
 }
 
+bool btif_a2dp_sink_on_start() {
+  LOG_INFO("%s", __func__);
+
+  BT_HDR_RIGID* p_buf =
+      reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+  p_buf->event = BTIF_MEDIA_SINK_START;
+  btif_a2dp_sink_cb.worker_thread.DoInThread(
+      FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
+  return true;
+}
+
 static void btif_a2dp_sink_audio_handle_stop_decoding() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   alarm_t* old_alarm;
   {
     LockGuard lock(g_mutex);
@@ -441,7 +483,7 @@ static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
 }
 
 static void btif_a2dp_sink_clear_track_event() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
 
 #ifndef OS_GENERIC
@@ -453,7 +495,7 @@ static void btif_a2dp_sink_clear_track_event() {
 
 // Must be called while locked.
 static void btif_a2dp_sink_audio_handle_start_decoding() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   if (btif_a2dp_sink_cb.decode_alarm != nullptr)
     return;  // Already started decoding
 
@@ -463,7 +505,7 @@ static void btif_a2dp_sink_audio_handle_start_decoding() {
 
   btif_a2dp_sink_cb.decode_alarm = alarm_new_periodic("btif.a2dp_sink_decode");
   if (btif_a2dp_sink_cb.decode_alarm == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s: unable to allocate decode alarm", __func__);
+    LOG_ERROR("%s: unable to allocate decode alarm", __func__);
     return;
   }
   alarm_set(btif_a2dp_sink_cb.decode_alarm, BTIF_SINK_MEDIA_TIME_TICK_MS,
@@ -487,7 +529,7 @@ static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg) {
 
   CHECK(btif_a2dp_sink_cb.decoder_interface != nullptr);
   if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
-    LOG_ERROR(LOG_TAG, "%s: decoding failed", __func__);
+    LOG_ERROR("%s: decoding failed", __func__);
   }
 }
 
@@ -530,14 +572,14 @@ static void btif_a2dp_sink_avk_handle_timer() {
 
 /* when true media task discards any rx frames */
 void btif_a2dp_sink_set_rx_flush(bool enable) {
-  LOG_INFO(LOG_TAG, "%s: enable=%s", __func__, (enable) ? "true" : "false");
+  LOG_INFO("%s: enable=%s", __func__, (enable) ? "true" : "false");
   LockGuard lock(g_mutex);
 
   btif_a2dp_sink_cb.rx_flush = enable;
 }
 
 static void btif_a2dp_sink_audio_rx_flush_event() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   LockGuard lock(g_mutex);
   // Flush all received encoded audio buffers
   fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
@@ -545,7 +587,7 @@ static void btif_a2dp_sink_audio_rx_flush_event() {
 
 static void btif_a2dp_sink_decoder_update_event(
     tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   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],
@@ -554,22 +596,22 @@ static void btif_a2dp_sink_decoder_update_event(
 
   int sample_rate = A2DP_GetTrackSampleRate(p_buf->codec_info);
   if (sample_rate == -1) {
-    LOG_ERROR(LOG_TAG, "%s: cannot get the track frequency", __func__);
+    LOG_ERROR("%s: cannot get the track frequency", __func__);
     return;
   }
   int bits_per_sample = A2DP_GetTrackBitsPerSample(p_buf->codec_info);
   if (bits_per_sample == -1) {
-    LOG_ERROR(LOG_TAG, "%s: cannot get the bits per sample", __func__);
+    LOG_ERROR("%s: cannot get the bits per sample", __func__);
     return;
   }
   int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
   if (channel_count == -1) {
-    LOG_ERROR(LOG_TAG, "%s: cannot get the channel count", __func__);
+    LOG_ERROR("%s: cannot get the channel count", __func__);
     return;
   }
   int channel_type = A2DP_GetSinkTrackChannelType(p_buf->codec_info);
   if (channel_type == -1) {
-    LOG_ERROR(LOG_TAG, "%s: cannot get the Sink channel type", __func__);
+    LOG_ERROR("%s: cannot get the Sink channel type", __func__);
     return;
   }
   btif_a2dp_sink_cb.sample_rate = sample_rate;
@@ -581,26 +623,29 @@ static void btif_a2dp_sink_decoder_update_event(
 
   btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
   if (btif_a2dp_sink_cb.decoder_interface == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s: cannot stream audio: no source decoder interface",
-              __func__);
+    LOG_ERROR("%s: cannot stream audio: no source decoder interface", __func__);
     return;
   }
 
   if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
           btif_a2dp_sink_on_decode_complete)) {
-    LOG_ERROR(LOG_TAG, "%s: failed to initialize decoder", __func__);
+    LOG_ERROR("%s: failed to initialize decoder", __func__);
     return;
   }
 
+  if (btif_a2dp_sink_cb.decoder_interface->decoder_configure != nullptr) {
+    btif_a2dp_sink_cb.decoder_interface->decoder_configure(p_buf->codec_info);
+  }
+
   APPL_TRACE_DEBUG("%s: create audio track", __func__);
   btif_a2dp_sink_cb.audio_track =
 #ifndef OS_GENERIC
-      BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_type);
+      BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_count);
 #else
       NULL;
 #endif
   if (btif_a2dp_sink_cb.audio_track == nullptr) {
-    LOG_ERROR(LOG_TAG, "%s: track creation failed", __func__);
+    LOG_ERROR("%s: track creation failed", __func__);
     return;
   }
 }
@@ -635,13 +680,14 @@ uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
 }
 
 void btif_a2dp_sink_audio_rx_flush_req() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
     /* Queue is already empty */
     return;
   }
 
-  BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+  BT_HDR_RIGID* p_buf =
+      reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
   p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH;
   btif_a2dp_sink_cb.worker_thread.DoInThread(
       FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
@@ -652,19 +698,20 @@ void btif_a2dp_sink_debug_dump(UNUSED_ATTR int fd) {
 }
 
 void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+  LOG_INFO("%s", __func__);
   tBTIF_MEDIA_SINK_FOCUS_UPDATE* p_buf =
       reinterpret_cast<tBTIF_MEDIA_SINK_FOCUS_UPDATE*>(
           osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));
   p_buf->focus_state = state;
   p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
   btif_a2dp_sink_cb.worker_thread.DoInThread(
-      FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
+      FROM_HERE,
+      base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
 }
 
 static void btif_a2dp_sink_set_focus_state_event(
     btif_a2dp_sink_focus_state_t state) {
-  LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
+  LOG_INFO("%s: state=%d", __func__, state);
   LockGuard lock(g_mutex);
 
   APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
@@ -678,7 +725,7 @@ static void btif_a2dp_sink_set_focus_state_event(
 }
 
 void btif_a2dp_sink_set_audio_track_gain(float gain) {
-  LOG_INFO(LOG_TAG, "%s: set gain to %f", __func__, gain);
+  LOG_INFO("%s: set gain to %f", __func__, gain);
   LockGuard lock(g_mutex);
 
 #ifndef OS_GENERIC
@@ -687,10 +734,33 @@ void btif_a2dp_sink_set_audio_track_gain(float gain) {
 }
 
 static void btif_a2dp_sink_clear_track_event_req() {
-  LOG_INFO(LOG_TAG, "%s", __func__);
-  BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+  LOG_INFO("%s", __func__);
+  BT_HDR_RIGID* p_buf =
+      reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
 
   p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
   btif_a2dp_sink_cb.worker_thread.DoInThread(
       FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
 }
+
+static void btif_a2dp_sink_on_start_event() {
+  LOG_INFO("%s", __func__);
+
+  if ((btif_a2dp_sink_cb.decoder_interface != nullptr) &&
+      (btif_a2dp_sink_cb.decoder_interface->decoder_start != nullptr)) {
+    btif_a2dp_sink_cb.decoder_interface->decoder_start();
+  }
+
+  return;
+}
+
+static void btif_a2dp_sink_on_suspend_event() {
+  LOG_INFO("%s", __func__);
+
+  if ((btif_a2dp_sink_cb.decoder_interface != nullptr) &&
+      (btif_a2dp_sink_cb.decoder_interface->decoder_suspend != nullptr)) {
+    btif_a2dp_sink_cb.decoder_interface->decoder_suspend();
+  }
+
+  return;
+}