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);
#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);
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);
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) {
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) ||
// 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;
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);
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__);
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));
/* 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) {
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);
}
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;
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();
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;
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();