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

Commit 73ec92e9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "A2DP: Don't start or suspend the encoder for a non-active sink"

parents 09129959 ec0372c3
Loading
Loading
Loading
Loading
+32 −33
Original line number Original line Diff line number Diff line
@@ -434,12 +434,10 @@ bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address,
  }
  }


  // Start the session.
  // Start the session.
  // If audio was streaming before, start audio streaming as well.
  btif_a2dp_source_start_session(new_peer_address,
  btif_a2dp_source_start_session(new_peer_address,
                                 std::move(peer_ready_promise));
                                 std::move(peer_ready_promise));
  if (is_streaming) {
  // If audio was streaming before, DON'T start audio streaming, but leave the
    btif_a2dp_source_start_audio_req();
  // control to the audio HAL.
  }
  return true;
  return true;
}
}


@@ -707,35 +705,33 @@ void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {


  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;


  /* allow using this api for other than suspend */
  // allow using this API for other (acknowledgement and stopping media task)
  if (p_av_suspend != nullptr) {
  // than suspend
    if (p_av_suspend->status != BTA_AV_SUCCESS) {
  if (p_av_suspend != nullptr && p_av_suspend->status != BTA_AV_SUCCESS) {
      LOG_ERROR(LOG_TAG, "%s: A2DP stop request failed: status=%d", __func__,
    LOG_ERROR(LOG_TAG, "%s: A2DP stop failed: status=%d, initiator=%s",
                p_av_suspend->status);
              __func__, p_av_suspend->status,
              (p_av_suspend->initiator ? "true" : "false"));
    if (p_av_suspend->initiator) {
    if (p_av_suspend->initiator) {
        LOG_WARN(LOG_TAG, "%s: A2DP stop request failed: status=%d", __func__,
                 p_av_suspend->status);
      if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
      if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
        bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_FAILURE);
        bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_FAILURE);
      } else {
      } else {
        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
      }
      }
    }
    }
      return;
  } else if (btif_av_is_a2dp_offload_enabled()) {
    }
  }
  if (btif_av_is_a2dp_offload_enabled()) {
    bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
    bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
    return;
    return;
  }
  }
  /* ensure tx frames are immediately suspended */
  btif_a2dp_source_cb.tx_flush = true;


  /* request to stop media task */
  // ensure tx frames are immediately suspended
  btif_a2dp_source_cb.tx_flush = true;
  // ensure tx frames are immediately flushed
  btif_a2dp_source_audio_tx_flush_req();
  btif_a2dp_source_audio_tx_flush_req();

  // request to stop media task
  btif_a2dp_source_stop_audio_req();
  btif_a2dp_source_stop_audio_req();


  /* once stream is fully stopped we will ack back */
  // once software stream is fully stopped we will ack back
}
}


void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
@@ -744,29 +740,32 @@ void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {


  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
  if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;


  /* check for status failures */
  CHECK(p_av_suspend != nullptr) << "Suspend result could not be nullptr";

  // check for status failures
  if (p_av_suspend->status != BTA_AV_SUCCESS) {
  if (p_av_suspend->status != BTA_AV_SUCCESS) {
    LOG_WARN(LOG_TAG, "%s: A2DP suspend failed: status=%d, initiator=%s",
             __func__, p_av_suspend->status,
             (p_av_suspend->initiator ? "true" : "false"));
    if (p_av_suspend->initiator) {
    if (p_av_suspend->initiator) {
      LOG_WARN(LOG_TAG, "%s: A2DP suspend request failed: status=%d", __func__,
               p_av_suspend->status);
      if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
      if (bluetooth::audio::a2dp::is_hal_2_0_enabled()) {
        bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_FAILURE);
        bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_FAILURE);
      } else {
      } else {
        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
      }
      }
    }
    }
  }
  } else if (btif_av_is_a2dp_offload_enabled()) {
  if (btif_av_is_a2dp_offload_enabled()) {
    bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
    bluetooth::audio::a2dp::ack_stream_suspended(A2DP_CTRL_ACK_SUCCESS);
    return;
    return;
  }
  }
  /* once stream is fully stopped we will ack back */


  /* ensure tx frames are immediately flushed */
  // ensure tx frames are immediately suspended
  btif_a2dp_source_cb.tx_flush = true;
  btif_a2dp_source_cb.tx_flush = true;


  /* stop timer tick */
  // stop timer tick
  btif_a2dp_source_stop_audio_req();
  btif_a2dp_source_stop_audio_req();

  // once software stream is fully stopped we will ack back
}
}


/* when true media task discards any tx frames */
/* when true media task discards any tx frames */
@@ -853,7 +852,7 @@ static void btif_a2dp_source_audio_tx_stop_event(void) {
    UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO);
    UIPC_Close(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO);


    /*
    /*
     * Try to send acknowldegment once the media stream is
     * Try to send acknowledgement once the media stream is
     * stopped. This will make sure that the A2DP HAL layer is
     * stopped. This will make sure that the A2DP HAL layer is
     * un-blocked on wait for acknowledgment for the sent command.
     * un-blocked on wait for acknowledgment for the sent command.
     * This resolves a corner cases AVDTP SUSPEND collision
     * This resolves a corner cases AVDTP SUSPEND collision
+43 −26
Original line number Original line Diff line number Diff line
@@ -1830,18 +1830,27 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
      // If remote tries to start A2DP when DUT is A2DP Source, then Suspend.
      // If remote tries to start A2DP when DUT is A2DP Source, then Suspend.
      // If A2DP is Sink and call is active, then disconnect the AVDTP channel.
      // If A2DP is Sink and call is active, then disconnect the AVDTP channel.
      bool should_suspend = false;
      bool should_suspend = false;
      if (peer_.IsSink() && !peer_.CheckFlags(BtifAvPeer::kFlagPendingStart |
      if (peer_.IsSink()) {
        if (!peer_.CheckFlags(BtifAvPeer::kFlagPendingStart |
                              BtifAvPeer::kFlagRemoteSuspend)) {
                              BtifAvPeer::kFlagRemoteSuspend)) {
        LOG(WARNING) << __PRETTY_FUNCTION__ << ": Peer " << peer_.PeerAddress()
          LOG(WARNING) << __PRETTY_FUNCTION__ << ": Peer "
                       << peer_.PeerAddress()
                       << " : trigger Suspend as remote initiated";
                       << " : trigger Suspend as remote initiated";
          should_suspend = true;
          should_suspend = true;
        } else if (!peer_.IsActivePeer()) {
          LOG(WARNING) << __PRETTY_FUNCTION__ << ": Peer "
                       << peer_.PeerAddress()
                       << " : trigger Suspend as non-active";
          should_suspend = true;
        }
        }


      // If peer is A2DP Source, do ACK commands to audio HAL and start media task
        // If peer is A2DP Source, do ACK commands to audio HAL and start media
      if (peer_.IsSink() && btif_a2dp_on_started(peer_.PeerAddress(), &p_av->start)) {
        // task
        if (btif_a2dp_on_started(peer_.PeerAddress(), &p_av->start)) {
          // Only clear pending flag after acknowledgement
          // Only clear pending flag after acknowledgement
          peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
          peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
        }
        }
      }


      // Remain in Open state if status failed
      // Remain in Open state if status failed
      if (p_av->start.status != BTA_AV_SUCCESS) return false;
      if (p_av->start.status != BTA_AV_SUCCESS) return false;
@@ -1875,17 +1884,20 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,


    case BTA_AV_CLOSE_EVT:
    case BTA_AV_CLOSE_EVT:
      // AVDTP link is closed
      // AVDTP link is closed
      if (peer_.IsActivePeer()) {
        btif_a2dp_on_stopped(nullptr);
      }

      // Change state to Idle, send acknowledgement if start is pending
      // Change state to Idle, send acknowledgement if start is pending
      if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
      if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
        BTIF_TRACE_WARNING("%s: Peer %s : failed pending start request",
        BTIF_TRACE_WARNING("%s: Peer %s : failed pending start request",
                           __PRETTY_FUNCTION__,
                           __PRETTY_FUNCTION__,
                           peer_.PeerAddress().ToString().c_str());
                           peer_.PeerAddress().ToString().c_str());
        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
        tBTA_AV_START av_start = {.chnl = p_av->close.chnl,
                                  .hndl = p_av->close.hndl,
                                  .status = BTA_AV_FAIL_STREAM,
                                  .initiator = true,
                                  .suspending = true};
        btif_a2dp_on_started(peer_.PeerAddress(), &av_start);
        // Pending start flag will be cleared when exit current state
        // Pending start flag will be cleared when exit current state
      } else if (peer_.IsActivePeer()) {
        btif_a2dp_on_stopped(nullptr);
      }
      }


      // Inform the application that we are disconnected
      // Inform the application that we are disconnected
@@ -2020,16 +2032,15 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
      // always overrides.
      // always overrides.
      peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);
      peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);


      if (peer_.IsSink()) {
      if (peer_.IsSink() &&
          (peer_.IsActivePeer() || !btif_av_stream_started_ready())) {
        // Immediately stop transmission of frames while suspend is pending
        // Immediately stop transmission of frames while suspend is pending
        if (peer_.IsActivePeer()) {
        if (event == BTIF_AV_STOP_STREAM_REQ_EVT) {
        if (event == BTIF_AV_STOP_STREAM_REQ_EVT) {
          btif_a2dp_on_stopped(nullptr);
          btif_a2dp_on_stopped(nullptr);
        } else {
        } else {
            // (event == BTIF_AV_SUSPEND_STREAM_REQ_EVT)
          // ensure tx frames are immediately suspended
          btif_a2dp_source_set_tx_flush(true);
          btif_a2dp_source_set_tx_flush(true);
        }
        }
        }
      } else if (peer_.IsSource()) {
      } else if (peer_.IsSource()) {
        btif_a2dp_on_stopped(nullptr);
        btif_a2dp_on_stopped(nullptr);
      }
      }
@@ -2064,7 +2075,9 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
               p_av->suspend.initiator, peer_.FlagsToString().c_str());
               p_av->suspend.initiator, peer_.FlagsToString().c_str());


      // A2DP suspended, stop A2DP encoder / decoder until resumed
      // A2DP suspended, stop A2DP encoder / decoder until resumed
      if (peer_.IsActivePeer() || !btif_av_stream_started_ready()) {
        btif_a2dp_on_suspended(&p_av->suspend);
        btif_a2dp_on_suspended(&p_av->suspend);
      }


      // If not successful, remain in current state
      // If not successful, remain in current state
      if (p_av->suspend.status != BTA_AV_SUCCESS) {
      if (p_av->suspend.status != BTA_AV_SUCCESS) {
@@ -2106,7 +2119,11 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
      peer_.SetFlags(BtifAvPeer::kFlagPendingStop);
      peer_.SetFlags(BtifAvPeer::kFlagPendingStop);
      peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
      peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);


      // Don't change the encoder and audio provider state by a non-active peer
      // since they are shared between peers
      if (peer_.IsActivePeer() || !btif_av_stream_started_ready()) {
        btif_a2dp_on_stopped(&p_av->suspend);
        btif_a2dp_on_stopped(&p_av->suspend);
      }


      btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STOPPED);
      btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STOPPED);