Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5107d68a authored by Pavlin Radoslavov's avatar Pavlin Radoslavov
Browse files

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
parent 82fc8edc
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -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);

+13 −4
Original line number Diff line number Diff line
@@ -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);
+34 −6
Original line number Diff line number Diff line
@@ -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;
+36 −10
Original line number Diff line number Diff line
@@ -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);
}
+6 −6
Original line number Diff line number Diff line
@@ -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();