OSDN Git Service

Add explicit init/cleanup steps for A2DP Source and Sink
authorPavlin Radoslavov <pavlin@google.com>
Fri, 23 Feb 2018 17:04:57 +0000 (09:04 -0800)
committerPavlin Radoslavov <pavlin@google.com>
Sat, 24 Feb 2018 02:27:32 +0000 (18:27 -0800)
The startup/shutdown steps for A2DP Source and Sink
are done when setting/resetting the Active device, and this
implies the device has been connected.

The operations that must be done before the remote device
is connected are moved to init (and cleanup for the reverse operations)

Bug: 73832547
Test: Manual - Connect/disconnect/play A2DP to Headset
Change-Id: Iaa55c2d27443646111f07a53d2c5163bca9e256d

btif/include/btif_a2dp_sink.h
btif/include/btif_a2dp_source.h
btif/src/btif_a2dp_sink.cc
btif/src/btif_a2dp_source.cc
btif/src/btif_av.cc

index b4bfbbb..3e64503 100644 (file)
@@ -38,16 +38,27 @@ typedef enum {
   BTIF_A2DP_SINK_FOCUS_GRANTED = 1
 } btif_a2dp_sink_focus_state_t;
 
-// Initialize and startup the A2DP Sink module.
+// Initialize the A2DP Sink module.
 // This function should be called by the BTIF state machine prior to using the
 // module.
+bool btif_a2dp_sink_init(void);
+
+// Startup the A2DP Sink module.
+// This function should be called by the BTIF state machine after
+// btif_a2dp_sink_init() to prepare for receiving and processing audio
+// streaming.
 bool btif_a2dp_sink_startup(void);
 
-// Shutdown and cleanup the A2DP Sink module.
-// This function should be called by the BTIF state machine during
-// graceful shutdown and cleanup.
+// Shutdown the A2DP Sink module.
+// This function should be called by the BTIF state machine before
+// btif_a2dp_sink_cleanup() to shutdown the processing of the audio streaming.
 void btif_a2dp_sink_shutdown(void);
 
+// Cleanup the A2DP Sink module.
+// This function should be called by the BTIF state machine during graceful
+// cleanup.
+void btif_a2dp_sink_cleanup(void);
+
 // Get the audio sample rate for the A2DP Sink module.
 tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void);
 
index 024b5e5..193e4b2 100644 (file)
 
 #include "bta_av_api.h"
 
-// Initialize and startup the A2DP Source module.
+// Initialize the A2DP Source module.
 // This function should be called by the BTIF state machine prior to using the
 // module.
+bool btif_a2dp_source_init(void);
+
+// Startup the A2DP Source module.
+// This function should be called by the BTIF state machine after
+// btif_a2dp_source_init() to prepare to start streaming.
 bool btif_a2dp_source_startup(void);
 
-// Shutdown and cleanup the A2DP Source module.
-// This function should be called by the BTIF state machine during
-// graceful shutdown and cleanup.
+// Shutdown the A2DP Source module.
+// This function should be called by the BTIF state machine to stop streaming.
 void btif_a2dp_source_shutdown(void);
 
+// Cleanup the A2DP Source module.
+// This function should be called by the BTIF state machine during graceful
+// cleanup.
+void btif_a2dp_source_cleanup(void);
+
 // Check whether the A2DP Source media task is running.
 // Returns true if the A2DP Source media task is running, otherwise false.
 bool btif_a2dp_source_media_task_is_running(void);
index 0a64f43..489a5bb 100644 (file)
@@ -93,8 +93,10 @@ static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
 
 static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};
 
+static void btif_a2dp_sink_init_delayed(void* context);
 static void btif_a2dp_sink_startup_delayed(void* context);
 static void btif_a2dp_sink_shutdown_delayed(void* context);
+static void btif_a2dp_sink_cleanup_delayed(void* context);
 static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
 static void btif_a2dp_sink_audio_handle_stop_decoding(void);
 static void btif_decode_alarm_cb(void* context);
@@ -123,7 +125,7 @@ UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
   return "UNKNOWN A2DP SINK EVENT";
 }
 
-bool btif_a2dp_sink_startup(void) {
+bool btif_a2dp_sink_init(void) {
   LockGuard lock(g_mutex);
 
   if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
@@ -156,22 +158,48 @@ bool btif_a2dp_sink_startup(void) {
 
   APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##");
 
-  /* Schedule the rest of the startup operations */
-  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
+  /* Schedule the rest of the operations */
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_init_delayed,
               NULL);
 
   return true;
 }
 
-static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_init_delayed(UNUSED_ATTR void* context) {
   raise_priority_a2dp(TASK_HIGH_MEDIA);
   btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
 }
 
+bool btif_a2dp_sink_startup(void) {
+  LockGuard lock(g_mutex);
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
+              NULL);
+  return true;
+}
+
+static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+  LockGuard lock(g_mutex);
+  // Nothing to do
+}
+
 void btif_a2dp_sink_shutdown(void) {
+  LockGuard lock(g_mutex);
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
+              NULL);
+}
+
+static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+  // Nothing to do
+}
+
+void btif_a2dp_sink_cleanup(void) {
   alarm_t* decode_alarm;
   fixed_queue_t* cmd_msg_queue;
   thread_t* worker_thread;
+
+  // Make sure the sink is shutdown
+  btif_a2dp_sink_shutdown();
+
   {
     LockGuard lock(g_mutex);
     if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
@@ -198,11 +226,11 @@ void btif_a2dp_sink_shutdown(void) {
 
   // Exit the thread
   fixed_queue_free(cmd_msg_queue, NULL);
-  thread_post(worker_thread, btif_a2dp_sink_shutdown_delayed, NULL);
+  thread_post(worker_thread, btif_a2dp_sink_cleanup_delayed, NULL);
   thread_free(worker_thread);
 }
 
-static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+static void btif_a2dp_sink_cleanup_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;
index 9469d1c..2855857 100644 (file)
@@ -296,8 +296,10 @@ class BtifA2dpSource {
 static BtWorkerThread btif_a2dp_source_thread("btif_a2dp_source_thread");
 static BtifA2dpSource btif_a2dp_source_cb;
 
+static void btif_a2dp_source_init_delayed(void);
 static void btif_a2dp_source_startup_delayed(void);
 static void btif_a2dp_source_shutdown_delayed(void);
+static void btif_a2dp_source_cleanup_delayed(void);
 static void btif_a2dp_source_audio_tx_start_event(void);
 static void btif_a2dp_source_audio_tx_stop_event(void);
 static void btif_a2dp_source_audio_tx_flush_event(void);
@@ -372,6 +374,21 @@ void btif_a2dp_source_accumulate_stats(BtifMediaStats* src,
   src->Reset();
 }
 
+bool btif_a2dp_source_init(void) {
+  // Start A2DP Source media task
+  APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
+  btif_a2dp_source_thread.StartUp();
+  APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##");
+
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_init_delayed));
+  return true;
+}
+
+static void btif_a2dp_source_init_delayed(void) {
+  // Nothing to do
+}
+
 bool btif_a2dp_source_startup(void) {
   if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateOff) {
     APPL_TRACE_ERROR("%s: A2DP Source media task already running", __func__);
@@ -382,13 +399,6 @@ bool btif_a2dp_source_startup(void) {
   btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateStartingUp);
   btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX);
 
-  APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
-
-  /* Start A2DP Source media task */
-  btif_a2dp_source_thread.StartUp();
-
-  APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##");
-
   /* Schedule the rest of the startup operations */
   btif_a2dp_source_thread.DoInThread(
       FROM_HERE, base::Bind(&btif_a2dp_source_startup_delayed));
@@ -413,12 +423,12 @@ void btif_a2dp_source_shutdown(void) {
   /* Make sure no channels are restarted while shutting down */
   btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateShuttingDown);
 
-  APPL_TRACE_EVENT("## A2DP SOURCE STOP MEDIA THREAD ##");
+  // Stop the timer
+  alarm_free(btif_a2dp_source_cb.media_alarm);
+  btif_a2dp_source_cb.media_alarm = nullptr;
 
-  // Exit the thread
   btif_a2dp_source_thread.DoInThread(
       FROM_HERE, base::Bind(&btif_a2dp_source_shutdown_delayed));
-  btif_a2dp_source_thread.ShutDown();
 }
 
 static void btif_a2dp_source_shutdown_delayed(void) {
@@ -435,6 +445,22 @@ static void btif_a2dp_source_shutdown_delayed(void) {
       system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
 }
 
+void btif_a2dp_source_cleanup(void) {
+  // Make sure the source is shutdown
+  btif_a2dp_source_shutdown();
+
+  btif_a2dp_source_thread.DoInThread(
+      FROM_HERE, base::Bind(&btif_a2dp_source_cleanup_delayed));
+
+  // Exit the thread
+  APPL_TRACE_EVENT("## A2DP SOURCE STOP MEDIA THREAD ##");
+  btif_a2dp_source_thread.ShutDown();
+}
+
+static void btif_a2dp_source_cleanup_delayed(void) {
+  // Nothing to do
+}
+
 bool btif_a2dp_source_media_task_is_running(void) {
   return (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateRunning);
 }
index e5bb996..4f97449 100644 (file)
@@ -822,8 +822,8 @@ bt_status_t BtifAvSource::Init(
   codec_priorities_ = codec_priorities;
   bta_av_co_init(codec_priorities_);
 
-  if (!btif_a2dp_source_startup()) {
-    return BT_STATUS_FAIL;  // Already running
+  if (!btif_a2dp_source_init()) {
+    return BT_STATUS_FAIL;
   }
   btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
   enabled_ = true;
@@ -834,7 +834,7 @@ void BtifAvSource::Cleanup() {
   if (!enabled_) return;
 
   btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE);
-  do_in_jni_thread(FROM_HERE, base::Bind(&btif_a2dp_source_shutdown));
+  do_in_jni_thread(FROM_HERE, base::Bind(&btif_a2dp_source_cleanup));
 
   btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
   CleanupAllPeers();
@@ -993,8 +993,8 @@ bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks) {
                              kDefaultMaxConnectedAudioDevices);
   callbacks_ = callbacks;
 
-  if (!btif_a2dp_sink_startup()) {
-    return BT_STATUS_FAIL;  // Already running
+  if (!btif_a2dp_sink_init()) {
+    return BT_STATUS_FAIL;
   }
   btif_enable_service(BTA_A2DP_SINK_SERVICE_ID);
   enabled_ = true;
@@ -1005,7 +1005,7 @@ void BtifAvSink::Cleanup() {
   if (!enabled_) return;
 
   btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK);
-  do_in_jni_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_shutdown));
+  do_in_jni_thread(FROM_HERE, base::Bind(&btif_a2dp_sink_cleanup));
 
   btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
   CleanupAllPeers();