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

Commit de2ba72b authored by Cheney Ni's avatar Cheney Ni
Browse files

A2DP: Do AV suspend / stop at the stack main thread

Because Bluetooth stack cleaned up peers at its main thread, there would
be a race condition if audio HAL asked to suspend / stop the stream at
the same time. These tasks were handled by the called-in thread like
HwBinder, and was segmentation fault since peers were cleaned. This CL
moves audio control tasks to the stack main thread to prevent it.

Besides, this CL also modified the check of audio HAL A2DP CMDs:
* A2DP_Start should be successful if streaming already, and is because
  we only have this HAL as our input. It did not make scense to have
  streaming without a provider.
* A2DP_Stop should not check whether the media tick was scheduled or not
  for a hardware offloading case.

Bug: 139646747
Bug: 144067743
Test: A2DP playback
Change-Id: I736b308628b0da75ceb91e57cfe1854c6767233d
parent 7d6b5ace
Loading
Loading
Loading
Loading
+4 −10
Original line number Diff line number Diff line
@@ -82,11 +82,10 @@ class A2dpTransport : public ::bluetooth::audio::IBluetoothTransportInstance {
      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
    }

    if (btif_a2dp_source_is_streaming()) {
      LOG(ERROR) << __func__ << ": source is busy streaming";
      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
    if (btif_av_stream_started_ready()) {
      // Already started, ACK back immediately.
      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
    }

    if (btif_av_stream_ready()) {
      /*
       * Post start event and wait for audio path to open.
@@ -102,11 +101,6 @@ class A2dpTransport : public ::bluetooth::audio::IBluetoothTransportInstance {
      a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE;
      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
    }

    if (btif_av_stream_started_ready()) {
      // Already started, ACK back immediately.
      return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
    }
    LOG(ERROR) << __func__ << ": AV stream is not ready to start";
    return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
  }
@@ -137,7 +131,7 @@ class A2dpTransport : public ::bluetooth::audio::IBluetoothTransportInstance {

  void StopRequest() override {
    if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
        !btif_a2dp_source_is_streaming()) {
        !btif_av_stream_started_ready()) {
      return;
    }
    LOG(INFO) << __func__ << ": handling";
+24 −11
Original line number Diff line number Diff line
@@ -2861,6 +2861,27 @@ void btif_av_stream_start(void) {
                                   BTIF_AV_START_STREAM_REQ_EVT);
}

void src_do_suspend_in_main_thread(btif_av_sm_event_t event) {
  if (event != BTIF_AV_SUSPEND_STREAM_REQ_EVT &&
      event != BTIF_AV_STOP_STREAM_REQ_EVT)
    return;
  auto src_do_stream_suspend = [](btif_av_sm_event_t event) {
    bool is_idle = true;
    for (auto it : btif_av_source.Peers()) {
      const BtifAvPeer* peer = it.second;
      if (peer->StateMachine().StateId() == BtifAvStateMachine::kStateStarted) {
        btif_av_source_dispatch_sm_event(peer->PeerAddress(), event);
        is_idle = false;
      }
    }
    if (is_idle) {
      btif_a2dp_on_stopped(nullptr);
    }
  };
  // switch to main thread to prevent a race condition of accessing peers
  do_in_main_thread(FROM_HERE, base::Bind(src_do_stream_suspend, event));
}

void btif_av_stream_stop(const RawAddress& peer_address) {
  LOG_INFO(LOG_TAG, "%s peer %s", __func__, peer_address.ToString().c_str());

@@ -2870,23 +2891,15 @@ void btif_av_stream_stop(const RawAddress& peer_address) {
  }

  // The active peer might have changed and we might be in the process
  // of reconfiguring the stream. We need to stop the appopriate peer(s).
  for (auto it : btif_av_source.Peers()) {
    const BtifAvPeer* peer = it.second;
    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
                                     BTIF_AV_STOP_STREAM_REQ_EVT);
  }
  // of reconfiguring the stream. We need to stop the appropriate peer(s).
  src_do_suspend_in_main_thread(BTIF_AV_STOP_STREAM_REQ_EVT);
}

void btif_av_stream_suspend(void) {
  LOG_INFO(LOG_TAG, "%s", __func__);
  // The active peer might have changed and we might be in the process
  // of reconfiguring the stream. We need to suspend the appropriate peer(s).
  for (auto it : btif_av_source.Peers()) {
    const BtifAvPeer* peer = it.second;
    btif_av_source_dispatch_sm_event(peer->PeerAddress(),
                                     BTIF_AV_SUSPEND_STREAM_REQ_EVT);
  }
  src_do_suspend_in_main_thread(BTIF_AV_SUSPEND_STREAM_REQ_EVT);
}

void btif_av_stream_start_offload(void) {