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

Commit 27b215a8 authored by Pavlin Radoslavov's avatar Pavlin Radoslavov
Browse files

Multi-A2DP: stop or flush the A2DP queue only for Active peer

The A2DP queue should be flushed or the A2DP Tx/Rx operations
should be stopped only for the Active peer.
Otherwise, disconnecting a non-active A2DP Peer stops audio
output for the Active peer.

Bug: 73956686
Test: Manual: Connect two A2DP Sink devices, play music on the
      Active device, disconnect the non-Active device
Change-Id: I32a624c012ef2cd9ef0057f7289a6ed713f88039
parent 5417bc16
Loading
Loading
Loading
Loading
+50 −21
Original line number Original line Diff line number Diff line
@@ -232,6 +232,20 @@ class BtifAvPeer {
   */
   */
  bool CanBeDeleted() const;
  bool CanBeDeleted() const;


  /**
   * Check whether the peer is the active one.
   *
   * @return true if this peer is the active one
   */
  bool IsActivePeer() const { return (PeerAddress() == ActivePeerAddress()); }

  /**
   * Get the address of the active peer.
   *
   * @return the address of the active peer
   */
  const RawAddress& ActivePeerAddress() const;

  const RawAddress& PeerAddress() const { return peer_address_; }
  const RawAddress& PeerAddress() const { return peer_address_; }
  bool IsSource() const { return (peer_sep_ == AVDT_TSEP_SRC); }
  bool IsSource() const { return (peer_sep_ == AVDT_TSEP_SRC); }
  bool IsSink() const { return (peer_sep_ == AVDT_TSEP_SNK); }
  bool IsSink() const { return (peer_sep_ == AVDT_TSEP_SNK); }
@@ -800,6 +814,18 @@ bool BtifAvPeer::CanBeDeleted() const {
      (state_machine_.PreviousStateId() != BtifAvStateMachine::kStateInvalid));
      (state_machine_.PreviousStateId() != BtifAvStateMachine::kStateInvalid));
}
}


const RawAddress& BtifAvPeer::ActivePeerAddress() const {
  if (IsSource()) {
    return btif_av_sink.ActivePeer();
  }
  if (IsSink()) {
    return btif_av_source.ActivePeer();
  }
  LOG(FATAL) << __PRETTY_FUNCTION__ << ": A2DP peer " << PeerAddress()
             << " is neither Source nor Sink";
  return RawAddress::kEmpty;
}

bool BtifAvPeer::IsConnected() const {
bool BtifAvPeer::IsConnected() const {
  int state = state_machine_.StateId();
  int state = state_machine_.StateId();
  return ((state == BtifAvStateMachine::kStateOpened) ||
  return ((state == BtifAvStateMachine::kStateOpened) ||
@@ -1175,20 +1201,13 @@ void BtifAvStateMachine::StateIdle::OnEnter() {
  peer_.ClearAllFlags();
  peer_.ClearAllFlags();


  // Stop A2DP if this is the active peer
  // Stop A2DP if this is the active peer
  RawAddress active_peer = RawAddress::kEmpty;
  if (peer_.IsActivePeer() || peer_.ActivePeerAddress().IsEmpty()) {
  if (peer_.IsSink()) {
    active_peer = btif_av_source.ActivePeer();
  } else if (peer_.IsSource()) {
    active_peer = btif_av_sink.ActivePeer();
  }
  if (peer_.PeerAddress() == active_peer || active_peer.IsEmpty()) {
    btif_a2dp_on_idle();
    btif_a2dp_on_idle();
  }
  }


  // Reset the active peer if this was the active peer and
  // Reset the active peer if this was the active peer and
  // the Idle state was reentered
  // the Idle state was reentered
  if (peer_.PeerAddress() == active_peer && !active_peer.IsEmpty() &&
  if (peer_.IsActivePeer() && peer_.CanBeDeleted()) {
      peer_.CanBeDeleted()) {
    if (peer_.IsSink()) {
    if (peer_.IsSink()) {
      btif_av_source.SetActivePeer(RawAddress::kEmpty);
      btif_av_source.SetActivePeer(RawAddress::kEmpty);
    } else if (peer_.IsSource()) {
    } else if (peer_.IsSource()) {
@@ -1710,7 +1729,7 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
      // 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;


      if (peer_.IsSource()) {
      if (peer_.IsSource() && peer_.IsActivePeer()) {
        // Remove flush state, ready for streaming
        // Remove flush state, ready for streaming
        btif_a2dp_sink_set_rx_flush(false);
        btif_a2dp_sink_set_rx_flush(false);
      }
      }
@@ -1740,7 +1759,9 @@ 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);
        btif_a2dp_on_stopped(nullptr);
      }


      // Inform the application that we are disconnected
      // Inform the application that we are disconnected
      btif_report_connection_state(peer_.PeerAddress(),
      btif_report_connection_state(peer_.PeerAddress(),
@@ -1857,7 +1878,9 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,


      if (peer_.IsSink()) {
      if (peer_.IsSink()) {
        // Immediately stop transmission of frames while suspend is pending
        // Immediately stop transmission of frames while suspend is pending
        if (peer_.IsActivePeer()) {
          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);
      }
      }
@@ -1898,7 +1921,7 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
      if (p_av->suspend.status != BTA_AV_SUCCESS) {
      if (p_av->suspend.status != BTA_AV_SUCCESS) {
        peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
        peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);


        if (peer_.IsSink()) {
        if (peer_.IsSink() && peer_.IsActivePeer()) {
          // Suspend failed, reset back tx flush state
          // Suspend failed, reset back tx flush state
          btif_a2dp_source_set_tx_flush(false);
          btif_a2dp_source_set_tx_flush(false);
        }
        }
@@ -1952,7 +1975,9 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
      peer_.SetFlags(BtifAvPeer::kFlagPendingStop);
      peer_.SetFlags(BtifAvPeer::kFlagPendingStop);


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


      // Inform the application that we are disconnected
      // Inform the application that we are disconnected
      btif_report_connection_state(peer_.PeerAddress(),
      btif_report_connection_state(peer_.PeerAddress(),
@@ -1986,6 +2011,7 @@ void BtifAvStateMachine::StateClosing::OnEnter() {
  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
                   peer_.PeerAddress().ToString().c_str());
                   peer_.PeerAddress().ToString().c_str());


  if (peer_.IsActivePeer()) {
    if (peer_.IsSink()) {
    if (peer_.IsSink()) {
      // Immediately stop transmission of frames
      // Immediately stop transmission of frames
      btif_a2dp_source_set_tx_flush(true);
      btif_a2dp_source_set_tx_flush(true);
@@ -1994,6 +2020,7 @@ void BtifAvStateMachine::StateClosing::OnEnter() {
      btif_a2dp_sink_set_rx_flush(true);
      btif_a2dp_sink_set_rx_flush(true);
    }
    }
  }
  }
}


void BtifAvStateMachine::StateClosing::OnExit() {
void BtifAvStateMachine::StateClosing::OnExit() {
  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
  BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
@@ -2014,7 +2041,9 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event,


    case BTA_AV_STOP_EVT:
    case BTA_AV_STOP_EVT:
    case BTIF_AV_STOP_STREAM_REQ_EVT:
    case BTIF_AV_STOP_STREAM_REQ_EVT:
      if (peer_.IsActivePeer()) {
        btif_a2dp_on_stopped(nullptr);
        btif_a2dp_on_stopped(nullptr);
      }
      break;
      break;


    case BTA_AV_CLOSE_EVT:
    case BTA_AV_CLOSE_EVT: