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

Commit 187e7be2 authored by Henri Chataing's avatar Henri Chataing Committed by Gerrit Code Review
Browse files

Merge "btif_a2dp_source: Schedule internal calls to bt_main_thread" into main

parents 1922f13d 031daf24
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ enum class BluetoothAudioStatus {
/// Implements callbacks for the BT Audio HAL to start, suspend and configure
/// the audio stream. Completion of the requested operation is indicated
/// by the methods ack_stream_started, ack_stream_suspended.
///
/// The callbacks are always invoked from one of the binder threads.
class BluetoothAudioPort {
public:
  virtual ~BluetoothAudioPort() {}
+46 −30
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include "stack/include/bt_hdr.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/btm_status.h"
#include "stack/include/main_thread.h"
#include "types/raw_address.h"

using bluetooth::audio::a2dp::BluetoothAudioStatus;
@@ -227,9 +228,14 @@ private:
  BtifA2dpSource::RunState state_;
};

/// Source worker thread created to run the CPU heavy encoder calls.
/// Exactly three functions are executed on this thread:
///   - btif_a2dp_source_audio_handle_timer
///   - btif_a2dp_source_read_callback
///   - btif_a2dp_source_enqueue_callback
static bluetooth::common::MessageLoopThread btif_a2dp_source_thread("bt_a2dp_source_worker_thread");
static BtifA2dpSource btif_a2dp_source_cb;

static BtifA2dpSource btif_a2dp_source_cb;
static uint8_t btif_a2dp_source_dynamic_audio_buffer_size = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ;

static void btif_a2dp_source_init_delayed(void);
@@ -313,12 +319,19 @@ static void btif_a2dp_source_accumulate_stats(BtifMediaStats* src, BtifMediaStat
  src->Reset();
}

/// Select the thread to run a2dp source actions on (a2dp encoder excluded).
static bluetooth::common::MessageLoopThread* local_thread() {
  return com::android::bluetooth::flags::a2dp_source_threading_fix() ? get_main_thread()
                                                                     : &btif_a2dp_source_thread;
}

bool btif_a2dp_source_init(void) {
  log::info("");

  // Start A2DP Source media task
  btif_a2dp_source_thread.StartUp();
  btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed));

  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed));
  return true;
}

@@ -384,8 +397,7 @@ static void btif_a2dp_source_init_delayed(void) {
  // the provider needs to be initialized earlier in order to ensure
  // get_a2dp_configuration and parse_a2dp_configuration can be
  // invoked before the stream is started.
  bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port,
                               btif_av_is_a2dp_offload_enabled());
  bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled());
}

static bool btif_a2dp_source_startup(void) {
@@ -401,7 +413,7 @@ static bool btif_a2dp_source_startup(void) {
  btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX);

  // Schedule the rest of the operations
  btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed));

  return true;
}
@@ -413,7 +425,7 @@ static void btif_a2dp_source_startup_delayed() {
    log::fatal("unable to enable real time scheduling");
#endif
  }
  if (!bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port,
  if (!bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port,
                                    btif_av_is_a2dp_offload_enabled())) {
    log::warn("Failed to setup the bluetooth audio HAL");
  }
@@ -426,7 +438,7 @@ bool btif_a2dp_source_start_session(const RawAddress& peer_address,

  btif_a2dp_source_audio_tx_flush_req();

  if (btif_a2dp_source_thread.DoInThread(
  if (local_thread()->DoInThread(
              FROM_HERE, base::BindOnce(&btif_a2dp_source_start_session_delayed, peer_address,
                                        std::move(peer_ready_promise)))) {
    return true;
@@ -491,8 +503,8 @@ bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address,

bool btif_a2dp_source_end_session(const RawAddress& peer_address) {
  log::info("peer_address={} state={}", peer_address, btif_a2dp_source_cb.StateStr());
  btif_a2dp_source_thread.DoInThread(
          FROM_HERE, base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address));
  local_thread()->DoInThread(FROM_HERE,
                             base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address));
  btif_a2dp_source_cleanup_codec();
  return true;
}
@@ -518,7 +530,7 @@ static void btif_a2dp_source_end_session_delayed(const RawAddress& peer_address)
void btif_a2dp_source_allow_low_latency_audio(bool allowed) {
  log::info("allowed={}", allowed);

  btif_a2dp_source_thread.DoInThread(
  local_thread()->DoInThread(
          FROM_HERE,
          base::BindOnce(bluetooth::audio::a2dp::set_audio_low_latency_mode_allowed, allowed));
}
@@ -534,9 +546,8 @@ void btif_a2dp_source_shutdown(std::promise<void> shutdown_complete_promise) {
  /* Make sure no channels are restarted while shutting down */
  btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateShuttingDown);

  btif_a2dp_source_thread.DoInThread(
          FROM_HERE,
          base::BindOnce(&btif_a2dp_source_shutdown_delayed, std::move(shutdown_complete_promise)));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed,
                                                       std::move(shutdown_complete_promise)));
}

static void btif_a2dp_source_shutdown_delayed(std::promise<void> shutdown_complete_promise) {
@@ -614,8 +625,9 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
    log::error("Cannot stream audio: cannot set active peer to {}", peer_address);
    return;
  }
  btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface(peer_address);
  if (btif_a2dp_source_cb.encoder_interface == nullptr) {

  const tA2DP_ENCODER_INTERFACE* encoder_interface = bta_av_co_get_encoder_interface(peer_address);
  if (encoder_interface == nullptr) {
    log::error("Cannot stream audio: no source encoder interface");
    return;
  }
@@ -626,11 +638,11 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
    return;
  }

  btif_a2dp_source_cb.encoder_interface->encoder_init(&peer_params, a2dp_codec_config,
                                                      btif_a2dp_source_read_callback,
  encoder_interface->encoder_init(&peer_params, a2dp_codec_config, btif_a2dp_source_read_callback,
                                  btif_a2dp_source_enqueue_callback);

  // Save a local copy of the encoder_interval_ms
  btif_a2dp_source_cb.encoder_interface = encoder_interface;
  btif_a2dp_source_cb.encoder_interval_ms =
          btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms();

@@ -645,8 +657,7 @@ static void btif_a2dp_source_cleanup_codec() {
  log::info("state={}", btif_a2dp_source_cb.StateStr());
  // Must stop media task first before cleaning up the encoder
  btif_a2dp_source_stop_audio_req();
  btif_a2dp_source_thread.DoInThread(FROM_HERE,
                                     base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed));
}

static void btif_a2dp_source_cleanup_codec_delayed() {
@@ -660,15 +671,13 @@ static void btif_a2dp_source_cleanup_codec_delayed() {
void btif_a2dp_source_start_audio_req(void) {
  log::info("state={}", btif_a2dp_source_cb.StateStr());

  btif_a2dp_source_thread.DoInThread(FROM_HERE,
                                     base::BindOnce(&btif_a2dp_source_audio_tx_start_event));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_start_event));
}

void btif_a2dp_source_stop_audio_req(void) {
  log::info("state={}", btif_a2dp_source_cb.StateStr());

  btif_a2dp_source_thread.DoInThread(FROM_HERE,
                                     base::BindOnce(&btif_a2dp_source_audio_tx_stop_event));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_stop_event));
}

void btif_a2dp_source_encoder_user_config_update_req(
@@ -677,7 +686,8 @@ void btif_a2dp_source_encoder_user_config_update_req(
        std::promise<void> peer_ready_promise) {
  log::info("peer_address={} state={} {} codec_preference(s)", peer_address,
            btif_a2dp_source_cb.StateStr(), codec_user_preferences.size());
  if (!btif_a2dp_source_thread.DoInThread(

  if (!local_thread()->DoInThread(
              FROM_HERE,
              base::BindOnce(&btif_a2dp_source_encoder_user_config_update_event, peer_address,
                             codec_user_preferences, std::move(peer_ready_promise)))) {
@@ -723,9 +733,8 @@ static void btif_a2dp_source_encoder_user_config_update_event(

void btif_a2dp_source_feeding_update_req(const btav_a2dp_codec_config_t& codec_audio_config) {
  log::info("state={}", btif_a2dp_source_cb.StateStr());
  btif_a2dp_source_thread.DoInThread(
          FROM_HERE,
          base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, codec_audio_config));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_feeding_update_event,
                                                       codec_audio_config));
}

static void btif_a2dp_source_audio_feeding_update_event(
@@ -885,6 +894,12 @@ static void btif_a2dp_source_audio_tx_stop_event(void) {
  }
}

/// Periodic task responsible for encoding the audio stream and forwarding
/// to the remote device. It will read PCM samples from the HAL provided FMQ,
/// encode them into audio frames. Runs on the source worker thread.
///
/// The timer driving the periodic task is cancelled before any state cleanup
/// when the stream is ended.
static void btif_a2dp_source_audio_handle_timer(void) {
  uint64_t timestamp_us = bluetooth::common::time_get_audio_server_tick_us();
  uint64_t stats_timestamp_us = bluetooth::common::time_get_os_boottime_us();
@@ -911,6 +926,8 @@ static void btif_a2dp_source_audio_handle_timer(void) {
                          btif_a2dp_source_cb.encoder_interval_ms * 1000);
}

/// Callback invoked by the encoder for reading PCM audio data from the
/// Bluetooth Audio HAL. Runs on the source worker thread.
static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) {
  if (!btif_a2dp_source_cb.sw_audio_is_encoding) {
    return 0;
@@ -1030,8 +1047,7 @@ static void btif_a2dp_source_audio_tx_flush_event(void) {
static bool btif_a2dp_source_audio_tx_flush_req(void) {
  log::info("state={}", btif_a2dp_source_cb.StateStr());

  btif_a2dp_source_thread.DoInThread(FROM_HERE,
                                     base::BindOnce(&btif_a2dp_source_audio_tx_flush_event));
  local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_flush_event));
  return true;
}