From ee164d2de5c9d0f68ba834dfc9d4d61c65ee6c55 Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Fri, 23 Feb 2018 09:04:57 -0800 Subject: [PATCH] Add explicit init/cleanup steps for A2DP Source and Sink 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 | 19 +++++++++++++---- btif/include/btif_a2dp_source.h | 17 +++++++++++---- btif/src/btif_a2dp_sink.cc | 40 +++++++++++++++++++++++++++++------ btif/src/btif_a2dp_source.cc | 46 ++++++++++++++++++++++++++++++++--------- btif/src/btif_av.cc | 12 +++++------ 5 files changed, 104 insertions(+), 30 deletions(-) diff --git a/btif/include/btif_a2dp_sink.h b/btif/include/btif_a2dp_sink.h index b4bfbbbcf..3e64503d1 100644 --- a/btif/include/btif_a2dp_sink.h +++ b/btif/include/btif_a2dp_sink.h @@ -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); diff --git a/btif/include/btif_a2dp_source.h b/btif/include/btif_a2dp_source.h index 024b5e5b7..193e4b240 100644 --- a/btif/include/btif_a2dp_source.h +++ b/btif/include/btif_a2dp_source.h @@ -24,16 +24,25 @@ #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); diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc index 0a64f434c..489a5bbe8 100644 --- a/btif/src/btif_a2dp_sink.cc +++ b/btif/src/btif_a2dp_sink.cc @@ -93,8 +93,10 @@ static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb; static std::atomic 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; diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc index 9469d1c94..285585739 100644 --- a/btif/src/btif_a2dp_source.cc +++ b/btif/src/btif_a2dp_source.cc @@ -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); } diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc index e5bb9962f..4f9744911 100644 --- a/btif/src/btif_av.cc +++ b/btif/src/btif_av.cc @@ -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(); -- 2.11.0