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

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

A2DP: When changing codec, resume the audio session after AVDTP_Reconfig done

When changing the codec configuration, we need to wait for AVDTP data
channel opened again, so have the updated MTU to share with our encoder.
This had to be done before starting the new HAL session, or might
provide an incorrect configuration with IOP issues.

This also reverts commit 97dd8bc5 since
we had all latest configurations before starting the new HAL session,
and is no needed to force update.

Bug: 132217607
Bug: 134125165
Test: manually
Change-Id: Id82f506190729881349f4ac8d2f8aef38f946ef2
parent 56a709bc
Loading
Loading
Loading
Loading
+16 −22
Original line number Diff line number Diff line
@@ -417,10 +417,14 @@ class BtaAvCo {
   *
   * @param peer_address the peer address
   * @param codec_user_config the codec user configuration to set
   * @param p_restart_output if there is a change in the encoder configuration
   * that requires restarting of the A2DP connection, flag |p_restart_output|
   * will be set to true.
   * @return true on success, otherwise false
   */
  bool SetCodecUserConfig(const RawAddress& peer_address,
                          const btav_a2dp_codec_config_t& codec_user_config);
                          const btav_a2dp_codec_config_t& codec_user_config,
                          bool* p_restart_output);

  /**
   * Set the codec audio configuration.
@@ -1379,31 +1383,17 @@ void BtaAvCo::ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle,

void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle,
                        const RawAddress& peer_address, uint16_t mtu) {
  APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x mtu: %d", __func__,
                   peer_address.ToString().c_str(), bta_av_handle, mtu);
  LOG(INFO) << __func__ << ": peer " << peer_address
            << " bta_av_handle: " << loghex(bta_av_handle) << " mtu: " << mtu;

  // Find the peer
  BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address);
  if (p_peer == nullptr) {
    APPL_TRACE_ERROR(
        "%s: could not find peer entry for bta_av_handle 0x%x peer %s",
        __func__, bta_av_handle, peer_address.ToString().c_str());
    LOG(ERROR) << __func__ << ": could not find peer entry for bta_av_handle "
               << loghex(bta_av_handle) << " peer " << peer_address;
    return;
  }

  if (p_peer->mtu == mtu) return;

  p_peer->mtu = mtu;
  if (active_peer_ == p_peer) {
    LOG(INFO) << __func__ << ": update the codec encoder with peer "
              << peer_address << " bta_av_handle: " << loghex(bta_av_handle)
              << ", new MTU: " << mtu;
    // Send a request with NONE config values to update only the MTU.
    SetCodecAudioConfig(
        {.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE,
         .bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE,
         .channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE});
  }
}

bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) {
@@ -1472,7 +1462,7 @@ const tA2DP_DECODER_INTERFACE* BtaAvCo::GetSinkDecoderInterface() {

bool BtaAvCo::SetCodecUserConfig(
    const RawAddress& peer_address,
    const btav_a2dp_codec_config_t& codec_user_config) {
    const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) {
  uint8_t result_codec_config[AVDT_CODEC_SIZE];
  const BtaAvCoSep* p_sink = nullptr;
  bool restart_input = false;
@@ -1483,6 +1473,8 @@ bool BtaAvCo::SetCodecUserConfig(
  VLOG(1) << __func__ << ": peer_address=" << peer_address
          << " codec_user_config={" << codec_user_config.ToString() << "}";

  *p_restart_output = false;

  BtaAvCoPeer* p_peer = FindPeer(peer_address);
  if (p_peer == nullptr) {
    LOG(ERROR) << __func__ << ": cannot find peer " << peer_address
@@ -1544,6 +1536,7 @@ bool BtaAvCo::SetCodecUserConfig(
            << loghex(p_peer->BtaAvHandle()) << ")";
    BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
                   p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
    *p_restart_output = true;
  }

done:
@@ -2177,8 +2170,9 @@ const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) {

bool bta_av_co_set_codec_user_config(
    const RawAddress& peer_address,
    const btav_a2dp_codec_config_t& codec_user_config) {
  return bta_av_co_cb.SetCodecUserConfig(peer_address, codec_user_config);
    const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) {
  return bta_av_co_cb.SetCodecUserConfig(peer_address, codec_user_config,
                                         p_restart_output);
}

bool bta_av_co_set_codec_audio_config(
+2 −1
Original line number Diff line number Diff line
@@ -89,7 +89,8 @@ void btif_a2dp_source_stop_audio_req(void);
// |codec_user_config| contains the preferred codec user configuration.
void btif_a2dp_source_encoder_user_config_update_req(
    const RawAddress& peer_addr,
    const btav_a2dp_codec_config_t& codec_user_config);
    const std::vector<btav_a2dp_codec_config_t>& codec_user_preferences,
    std::promise<void> peer_ready_promise);

// Process a request to update the A2DP audio encoding with new audio
// configuration feeding parameters stored in |codec_audio_config|.
+2 −1
Original line number Diff line number Diff line
@@ -48,10 +48,11 @@ const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void);
// Sets the user preferred codec configuration.
// The peer address is |peer_addr|.
// |codec_user_config| contains the preferred codec configuration.
// |restart_output| is used to know whether AV is reconfiguring with remote.
// Returns true on success, otherwise false.
bool bta_av_co_set_codec_user_config(
    const RawAddress& peer_addr,
    const btav_a2dp_codec_config_t& codec_user_config);
    const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output);

// Sets the Audio HAL selected audio feeding parameters.
// Those parameters are applied only to the currently selected codec.
+49 −14
Original line number Diff line number Diff line
@@ -246,7 +246,8 @@ static void btif_a2dp_source_setup_codec_delayed(
    const RawAddress& peer_address);
static void btif_a2dp_source_encoder_user_config_update_event(
    const RawAddress& peer_address,
    const btav_a2dp_codec_config_t& codec_user_config);
    const std::vector<btav_a2dp_codec_config_t>& codec_user_preferences,
    std::promise<void> peer_ready_promise);
static void btif_a2dp_source_audio_feeding_update_event(
    const btav_a2dp_codec_config_t& codec_audio_config);
static bool btif_a2dp_source_audio_tx_flush_req(void);
@@ -618,23 +619,57 @@ void btif_a2dp_source_stop_audio_req(void) {

void btif_a2dp_source_encoder_user_config_update_req(
    const RawAddress& peer_address,
    const btav_a2dp_codec_config_t& codec_user_config) {
  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
           peer_address.ToString().c_str(),
           btif_a2dp_source_cb.StateStr().c_str());
  btif_a2dp_source_thread.DoInThread(
      FROM_HERE, base::Bind(&btif_a2dp_source_encoder_user_config_update_event,
                            peer_address, codec_user_config));
    const std::vector<btav_a2dp_codec_config_t>& codec_user_preferences,
    std::promise<void> peer_ready_promise) {
  LOG(INFO) << __func__ << ": peer_address=" << peer_address
            << " state=" << btif_a2dp_source_cb.StateStr() << " "
            << codec_user_preferences.size() << " codec_preference(s)";
  if (!btif_a2dp_source_thread.DoInThread(
          FROM_HERE,
          base::BindOnce(&btif_a2dp_source_encoder_user_config_update_event,
                         peer_address, codec_user_preferences,
                         std::move(peer_ready_promise)))) {
    // cannot set promise but triggers crash
    LOG(FATAL) << __func__ << ": peer_address=" << peer_address
               << " state=" << btif_a2dp_source_cb.StateStr()
               << " fails to context switch";
  }
}

static void btif_a2dp_source_encoder_user_config_update_event(
    const RawAddress& peer_address,
    const btav_a2dp_codec_config_t& codec_user_config) {
  LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
           peer_address.ToString().c_str(),
           btif_a2dp_source_cb.StateStr().c_str());
  if (!bta_av_co_set_codec_user_config(peer_address, codec_user_config)) {
    LOG_ERROR(LOG_TAG, "%s: cannot update codec user configuration", __func__);
    const std::vector<btav_a2dp_codec_config_t>& codec_user_preferences,
    std::promise<void> peer_ready_promise) {
  bool restart_output = false;
  bool success = false;
  for (auto codec_user_config : codec_user_preferences) {
    success = bta_av_co_set_codec_user_config(peer_address, codec_user_config,
                                              &restart_output);
    if (success) {
      LOG(INFO) << __func__ << ": peer_address=" << peer_address
                << " state=" << btif_a2dp_source_cb.StateStr()
                << " codec_preference={" << codec_user_config.ToString()
                << "} restart_output=" << (restart_output ? "true" : "false");
      break;
    }
  }
  if (success && restart_output) {
    // Codec reconfiguration is in progress, and it is safe to unlock since
    // remaining tasks like starting audio session and reporting new codec
    // will be handled by BTA_AV_RECONFIG_EVT later.
    peer_ready_promise.set_value();
    return;
  }
  if (!success) {
    LOG(ERROR) << __func__ << ": cannot update codec user configuration(s)";
  }
  if (!peer_address.IsEmpty() && peer_address == btif_av_source_active_peer()) {
    // No more actions needed with remote, and if succeed, user had changed the
    // config like the bits per sample only. Let's resume the session now.
    btif_a2dp_source_start_session(peer_address, std::move(peer_ready_promise));
  } else {
    // Unlock for non-active peer
    peer_ready_promise.set_value();
  }
}

+37 −25
Original line number Diff line number Diff line
@@ -494,23 +494,12 @@ class BtifAvSource {
      const std::vector<btav_a2dp_codec_config_t>& codec_preferences,
      std::promise<void> peer_ready_promise) {
    // Restart the session if the codec for the active peer is updated
    bool restart_session =
        ((active_peer_ == peer_address) && !active_peer_.IsEmpty());
    if (restart_session) {
    if (!peer_address.IsEmpty() && active_peer_ == peer_address) {
      btif_a2dp_source_end_session(active_peer_);
    }

    for (auto cp : codec_preferences) {
      BTIF_TRACE_DEBUG("%s: codec_preference=%s", __func__,
                       cp.ToString().c_str());
      btif_a2dp_source_encoder_user_config_update_req(peer_address, cp);
    }
    if (restart_session) {
      btif_a2dp_source_start_session(active_peer_,
                                     std::move(peer_ready_promise));
    } else {
      peer_ready_promise.set_value();
    }
    btif_a2dp_source_encoder_user_config_update_req(
        peer_address, codec_preferences, std::move(peer_ready_promise));
  }

  const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
@@ -1906,19 +1895,37 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event,
      break;

    case BTA_AV_RECONFIG_EVT:
      if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart) &&
          (p_av->reconfig.status == BTA_AV_SUCCESS)) {
        LOG_INFO(LOG_TAG,
                 "%s : Peer %s : Reconfig done - calling BTA_AvStart()",
                 __PRETTY_FUNCTION__, peer_.PeerAddress().ToString().c_str());
        BTA_AvStart(peer_.BtaHandle());
      } else if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
        BTIF_TRACE_WARNING("%s: Peer %s : failed reconfiguration",
                           __PRETTY_FUNCTION__,
                           peer_.PeerAddress().ToString().c_str());
      if (p_av->reconfig.status != BTA_AV_SUCCESS) {
        LOG(WARNING) << __PRETTY_FUNCTION__ << ": Peer " << peer_.PeerAddress()
                     << " : failed reconfiguration";
        if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
          LOG(ERROR) << __PRETTY_FUNCTION__ << ": Peer " << peer_.PeerAddress()
                     << " : cannot proceed to do AvStart";
          peer_.ClearFlags(BtifAvPeer::kFlagPendingStart);
          btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
        }
        if (peer_.IsSink()) {
          src_disconnect_sink(peer_.PeerAddress());
        } else if (peer_.IsSource()) {
          sink_disconnect_src(peer_.PeerAddress());
        }
        break;
      }

      if (peer_.IsActivePeer()) {
        LOG(INFO) << __PRETTY_FUNCTION__ << " : Peer " << peer_.PeerAddress()
                  << " : Reconfig done - calling startSession() to audio HAL";
        std::promise<void> peer_ready_promise;
        std::future<void> peer_ready_future = peer_ready_promise.get_future();
        btif_a2dp_source_start_session(peer_.PeerAddress(),
                                       std::move(peer_ready_promise));
      }
      if (peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
        LOG(INFO) << __PRETTY_FUNCTION__ << " : Peer " << peer_.PeerAddress()
                  << " : Reconfig done - calling BTA_AvStart("
                  << loghex(peer_.BtaHandle()) << ")";
        BTA_AvStart(peer_.BtaHandle());
      }
      break;

    case BTIF_AV_CONNECT_REQ_EVT: {
@@ -2805,6 +2812,11 @@ static bt_status_t codec_config_src(
    return BT_STATUS_NOT_READY;
  }

  if (peer_address.IsEmpty()) {
    LOG(WARNING) << __func__ << ": BTIF AV Source needs peer to config";
    return BT_STATUS_PARM_INVALID;
  }

  std::promise<void> peer_ready_promise;
  std::future<void> peer_ready_future = peer_ready_promise.get_future();
  bt_status_t status = do_in_main_thread(