Merge "A2DP: Do AV suspend / stop at the stack main thread" am: 99d2649f78
am: 959b29d9e4

Change-Id: I3cdde8eb8277cf46978df0bc714ae25bc1509db4
diff --git a/audio_hal_interface/a2dp_encoding.cc b/audio_hal_interface/a2dp_encoding.cc
index fc61128..1b362e5 100644
--- a/audio_hal_interface/a2dp_encoding.cc
+++ b/audio_hal_interface/a2dp_encoding.cc
@@ -82,11 +82,10 @@
       return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
     }
 
-    if (btif_a2dp_source_is_streaming()) {
-      LOG(ERROR) << __func__ << ": source is busy streaming";
-      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
+    if (btif_av_stream_started_ready()) {
+      // Already started, ACK back immediately.
+      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
     }
-
     if (btif_av_stream_ready()) {
       /*
        * Post start event and wait for audio path to open.
@@ -102,11 +101,6 @@
       a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE;
       return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
     }
-
-    if (btif_av_stream_started_ready()) {
-      // Already started, ACK back immediately.
-      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
-    }
     LOG(ERROR) << __func__ << ": AV stream is not ready to start";
     return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
   }
@@ -137,7 +131,7 @@
 
   void StopRequest() override {
     if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
-        !btif_a2dp_source_is_streaming()) {
+        !btif_av_stream_started_ready()) {
       return;
     }
     LOG(INFO) << __func__ << ": handling";
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index 24e32ec..8ab336a 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -2861,6 +2861,27 @@
                                    BTIF_AV_START_STREAM_REQ_EVT);
 }
 
+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)
+    return;
+  auto src_do_stream_suspend = [](btif_av_sm_event_t event) {
+    bool is_idle = true;
+    for (auto it : btif_av_source.Peers()) {
+      const BtifAvPeer* peer = it.second;
+      if (peer->StateMachine().StateId() == BtifAvStateMachine::kStateStarted) {
+        btif_av_source_dispatch_sm_event(peer->PeerAddress(), event);
+        is_idle = false;
+      }
+    }
+    if (is_idle) {
+      btif_a2dp_on_stopped(nullptr);
+    }
+  };
+  // switch to main thread to prevent a race condition of accessing peers
+  do_in_main_thread(FROM_HERE, base::Bind(src_do_stream_suspend, event));
+}
+
 void btif_av_stream_stop(const RawAddress& peer_address) {
   LOG_INFO(LOG_TAG, "%s peer %s", __func__, peer_address.ToString().c_str());
 
@@ -2870,23 +2891,15 @@
   }
 
   // The active peer might have changed and we might be in the process
-  // of reconfiguring the stream. We need to stop the appopriate peer(s).
-  for (auto it : btif_av_source.Peers()) {
-    const BtifAvPeer* peer = it.second;
-    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
-                                     BTIF_AV_STOP_STREAM_REQ_EVT);
-  }
+  // of reconfiguring the stream. We need to stop the appropriate peer(s).
+  src_do_suspend_in_main_thread(BTIF_AV_STOP_STREAM_REQ_EVT);
 }
 
 void btif_av_stream_suspend(void) {
   LOG_INFO(LOG_TAG, "%s", __func__);
   // The active peer might have changed and we might be in the process
   // of reconfiguring the stream. We need to suspend the appropriate peer(s).
-  for (auto it : btif_av_source.Peers()) {
-    const BtifAvPeer* peer = it.second;
-    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
-                                     BTIF_AV_SUSPEND_STREAM_REQ_EVT);
-  }
+  src_do_suspend_in_main_thread(BTIF_AV_SUSPEND_STREAM_REQ_EVT);
 }
 
 void btif_av_stream_start_offload(void) {