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

Commit 0448438c authored by Philip Cuadra's avatar Philip Cuadra Committed by Andre Eisenbach
Browse files

Make Bluetooth audio threads use RT scheduling

Bluetooth threads that are used in audio have deadline
requirements for glitchless playback.  Those threads need to be
scheduled as RT tasks to ensure that they can meet the deadline even if
there is high system load.

Bug 37518404

Test:  play Bluetooth audio, check for RT with systrace
Change-Id: I4505fbce55e5a4fe18d00dbda23646a60e482efd
parent b68c126e
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -929,17 +929,9 @@ static bool btif_av_state_started_handler(btif_sm_event_t event, void* p_data) {
       * see update_audio_focus_state()
       */
      btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));

      /* increase the a2dp consumer task priority temporarily when start
      ** audio playing, to avoid overflow the audio packet queue. */
      adjust_priority_a2dp(true);

      break;

    case BTIF_SM_EXIT_EVT:
      /* restore the a2dp consumer task priority when stop audio playing. */
      adjust_priority_a2dp(false);

      break;

    case BTIF_AV_START_STREAM_REQ_EVT:
+6 −0
Original line number Diff line number Diff line
@@ -63,6 +63,9 @@ typedef struct {
#define DEFAULT_STARTUP_TIMEOUT_MS 8000
#define STRING_VALUE_OF(x) #x

// RT priority for HCI thread
static const int BT_HCI_RT_PRIORITY = 1;

// Abort if there is no response to an HCI command.
static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;

@@ -188,6 +191,9 @@ static future_t* hci_module_start_up(void) {
    LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
    goto error;
  }
  if (!thread_set_rt_priority(thread, BT_HCI_RT_PRIORITY)) {
    LOG_ERROR(LOG_TAG, "%s unable to make thread RT.", __func__);
  }

  commands_pending_response = list_new(NULL);
  if (!commands_pending_response) {
+7 −0
Original line number Diff line number Diff line
@@ -65,6 +65,13 @@ void thread_stop(thread_t* thread);
// Returns true on success.
bool thread_set_priority(thread_t* thread, int priority);

// Attempts to set |thread| to the real-time SCHED_FIFO |priority|.
// The |thread| has to be running for this call to succeed.
// Priority values are valid in the range sched_get_priority_max(SCHED_FIFO)
// to sched_get_priority_min(SCHED_FIFO).  Larger values are higher priority.
// Returns true on success.
bool thread_set_rt_priority(thread_t* thread, int priority);

// Returns true if the current thread is the same as the one represented by
// |thread|.
// |thread| may not be NULL.
+15 −9
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <malloc.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <time.h>
@@ -44,12 +45,9 @@
#include "osi/include/thread.h"
#include "osi/include/wakelock.h"

// Make callbacks run at high thread priority. Some callbacks are used for audio
// related timer tasks as well as re-transmissions etc. Since we at this point
// cannot differentiate what callback we are dealing with, assume high priority
// for now.
// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?)
static const int CALLBACK_THREAD_PRIORITY_HIGH = -19;
// Callback and timer threads should run at RT priority in order to ensure they
// meet audio deadlines.  Use this priority for all audio/timer related thread.
static const int THREAD_RT_PRIORITY = 1;

typedef struct {
  size_t count;
@@ -314,7 +312,7 @@ static bool lazy_initialize(void) {
              __func__);
    goto error;
  }
  thread_set_priority(default_callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
  thread_set_rt_priority(default_callback_thread, THREAD_RT_PRIORITY);
  default_callback_queue = fixed_queue_new(SIZE_MAX);
  if (default_callback_queue == NULL) {
    LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.",
@@ -330,8 +328,7 @@ static bool lazy_initialize(void) {
    LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
    goto error;
  }

  thread_set_priority(dispatcher_thread, CALLBACK_THREAD_PRIORITY_HIGH);
  thread_set_rt_priority(dispatcher_thread, THREAD_RT_PRIORITY);
  thread_post(dispatcher_thread, callback_dispatch, NULL);
  return true;

@@ -625,9 +622,18 @@ static bool timer_create_internal(const clockid_t clock_id, timer_t* timer) {
  CHECK(timer != NULL);

  struct sigevent sigevent;
  // create timer with RT priority thread
  pthread_attr_t thread_attr;
  pthread_attr_init(&thread_attr);
  pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);
  struct sched_param param;
  param.sched_priority = THREAD_RT_PRIORITY;
  pthread_attr_setschedparam(&thread_attr, &param);

  memset(&sigevent, 0, sizeof(sigevent));
  sigevent.sigev_notify = SIGEV_THREAD;
  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
  sigevent.sigev_notify_attributes = (void*)(&thread_attr);
  if (timer_create(clock_id, &sigevent, timer) == -1) {
    LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__,
              clock_id, strerror(errno));
+17 −0
Original line number Diff line number Diff line
@@ -159,6 +159,23 @@ bool thread_set_priority(thread_t* thread, int priority) {
  return true;
}

bool thread_set_rt_priority(thread_t* thread, int priority) {
  if (!thread) return false;

  struct sched_param rt_params;
  rt_params.sched_priority = priority;

  const int rc = sched_setscheduler(thread->tid, SCHED_FIFO, &rt_params);
  if (rc != 0) {
    LOG_ERROR(LOG_TAG,
              "%s unable to set SCHED_FIFO priority %d for tid %d, error %s",
              __func__, priority, thread->tid, strerror(errno));
    return false;
  }

  return true;
}

bool thread_is_self(const thread_t* thread) {
  CHECK(thread != NULL);
  return !!pthread_equal(pthread_self(), thread->pthread);
Loading