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

Commit 60137822 authored by Andy Hung's avatar Andy Hung Committed by android-build-merger
Browse files

audio_a2dp_hw: add device lock

am: 24012515

Change-Id: Ia27886aed87b2e7076d92f68b303d34cfd22df66
parents 682020ca 24012515
Loading
Loading
Loading
Loading
+49 −18
Original line number Diff line number Diff line
@@ -95,7 +95,10 @@ struct a2dp_stream_in;
struct a2dp_stream_out;

struct a2dp_audio_device {
  // Important: device must be first as an audio_hw_device* may be cast to
  // a2dp_audio_device* when the type is implicitly known.
  struct audio_hw_device device;
  std::recursive_mutex* mutex;  // See note below on mutex acquisition order.
  struct a2dp_stream_in* input;
  struct a2dp_stream_out* output;
};
@@ -109,7 +112,7 @@ struct a2dp_config {
/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */

struct a2dp_stream_common {
  std::recursive_mutex* mutex;
  std::recursive_mutex* mutex;  // See note below on mutex acquisition order.
  int ctrl_fd;
  int audio_fd;
  size_t buffer_sz;
@@ -129,6 +132,15 @@ struct a2dp_stream_in {
  struct a2dp_stream_common common;
};

/*
 * Mutex acquisition order:
 *
 * The a2dp_audio_device (adev) mutex must be acquired before
 * the a2dp_stream_common (out or in) mutex.
 *
 * This may differ from other audio HALs.
 */

/*****************************************************************************
 *  Static variables
 *****************************************************************************/
@@ -1354,7 +1366,8 @@ static int adev_open_output_stream(struct audio_hw_device* dev,
  int ret = 0;

  INFO("opening output");

  // protect against adev->output and stream_out from being inconsistent
  std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
  out = (struct a2dp_stream_out*)calloc(1, sizeof(struct a2dp_stream_out));

  if (!out) return -ENOMEM;
@@ -1454,17 +1467,21 @@ static void adev_close_output_stream(struct audio_hw_device* dev,
  struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
  struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;

  INFO("closing output (state %d)", out->common.state);

  std::unique_lock<std::recursive_mutex> lock(*out->common.mutex);
  if ((out->common.state == AUDIO_A2DP_STATE_STARTED) ||
      (out->common.state == AUDIO_A2DP_STATE_STOPPING)) {
  // prevent interference with adev_set_parameters.
  std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
  {
    std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
    const a2dp_state_t state = out->common.state;
    INFO("closing output (state %d)", (int)state);
    if ((state == AUDIO_A2DP_STATE_STARTED) ||
        (state == AUDIO_A2DP_STATE_STOPPING)) {
      stop_audio_datapath(&out->common);
    }

    skt_disconnect(out->common.ctrl_fd);
    out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
  lock.unlock();
  }

  a2dp_stream_common_destroy(&out->common);
  free(stream);
  a2dp_dev->output = NULL;
@@ -1475,9 +1492,12 @@ static void adev_close_output_stream(struct audio_hw_device* dev,
static int adev_set_parameters(struct audio_hw_device* dev,
                               const char* kvpairs) {
  struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
  struct a2dp_stream_out* out = a2dp_dev->output;
  int retval = 0;

  // prevent interference with adev_close_output_stream
  std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
  struct a2dp_stream_out* out = a2dp_dev->output;

  if (out == NULL) return retval;

  INFO("state %d", out->common.state);
@@ -1562,6 +1582,8 @@ static int adev_open_input_stream(struct audio_hw_device* dev,

  FNLOG();

  // protect against adev->input and stream_in from being inconsistent
  std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
  in = (struct a2dp_stream_in*)calloc(1, sizeof(struct a2dp_stream_in));

  if (!in) return -ENOMEM;
@@ -1617,9 +1639,12 @@ static void adev_close_input_stream(struct audio_hw_device* dev,
                                    struct audio_stream_in* stream) {
  struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
  struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
  a2dp_state_t state = in->common.state;

  INFO("closing input (state %d)", state);
  std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
  {
    std::lock_guard<std::recursive_mutex> lock(*in->common.mutex);
    const a2dp_state_t state = in->common.state;
    INFO("closing input (state %d)", (int)state);

    if ((state == AUDIO_A2DP_STATE_STARTED) ||
        (state == AUDIO_A2DP_STATE_STOPPING))
@@ -1627,6 +1652,7 @@ static void adev_close_input_stream(struct audio_hw_device* dev,

    skt_disconnect(in->common.ctrl_fd);
    in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
  }
  a2dp_stream_common_destroy(&in->common);
  free(stream);
  a2dp_dev->input = NULL;
@@ -1642,8 +1668,11 @@ static int adev_dump(UNUSED_ATTR const audio_hw_device_t* device,
}

static int adev_close(hw_device_t* device) {
  struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)device;
  FNLOG();

  delete a2dp_dev->mutex;
  a2dp_dev->mutex = nullptr;
  free(device);
  return 0;
}
@@ -1664,6 +1693,8 @@ static int adev_open(const hw_module_t* module, const char* name,

  if (!adev) return -ENOMEM;

  adev->mutex = new std::recursive_mutex;

  adev->device.common.tag = HARDWARE_DEVICE_TAG;
  adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
  adev->device.common.module = (struct hw_module_t*)module;