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

Commit 36318676 authored by Jack He's avatar Jack He
Browse files

eSCO: Limit number of retries after mSBC connection failure

* When peer device supports mSBC and codec negotiation, Fluoride stack
  will try to do the following when establishing a eSCO/SCO connection:
    1) Negotiate to mSBC by sending +BCS:2
    2) Try establishing eSCO/SCO connection using mSBC T2 settings
    3) If that failed, downgrade to mSBC T1 settings and retry
    4) If that failed, re-negotiate codec to CVSD, by sending +BCS:1
    5) Retry using CVSD S4 (HFP 1.7 and above) or S3 settings
    6) If this failed stop trying and report failure to upper stack
* Retry is achieved by:
    * Retry is only possible when inuse_codec = BTA_AG_CODEC_MSBC
    * Set codec_msbc_settings to BTA_AG_SCO_MSBC_SETTINGS_T1 when T2
       failed to connect in step 3 above
    * Set codec_fallback to true when T1 failed so that CVSD is used
       in step 4 above
* Retry stop is achieved by:
    * Set inuse_codec = BTA_AG_CODEC_CVSD
    * Set codec_msbc_settings back to BTA_AG_SCO_MSBC_SETTINGS_T2
    * Set codec_fallback to false and codec_updated to true so that
      the stack is ready for the next application triggerred SCO
      connection attempt
* Removed retry_with_sco_only as both Setup Synchronous Connection
  Command (0x0028) and Enhanced Setup Synchronous Connection Command
  (0x003D) fall back to SCO connection if eSCO is not supported.
  See page 858/2772 and 895/2772 of BT4.2 specification document
* Besides both code paths are the same for retry_with_sco_only after
  eSCO changes went in

Bug: 62426841
Test: make, HFP regression, testplans/91406
Change-Id: I205311c55e8763c48b6eb43c27f242927384036e
(cherry picked from commit e82e56bb2a1e5565b73333b60dc6b30936f52e80)
parent 8bf035f6
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -251,7 +251,6 @@ typedef struct {
  uint8_t roam_ind;         /* CIEV roam indicator value */
  uint8_t battchg_ind;      /* CIEV battery charge indicator value */
  uint8_t callheld_ind;     /* CIEV call held indicator value */
  bool retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */
  uint32_t bia_masked_out;  /* indicators HF does not want us to send */
  alarm_t* collision_timer;
  alarm_t* ring_timer;
+1 −0
Original line number Diff line number Diff line
@@ -260,6 +260,7 @@ static tBTA_AG_SCB* bta_ag_scb_alloc(void) {
      p_scb->in_use = true;
      p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
      p_scb->codec_updated = false;
      p_scb->codec_fallback = false;
      p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
      p_scb->sco_codec = BTA_AG_CODEC_CVSD;
      /* set up timers */
+29 −65
Original line number Diff line number Diff line
@@ -175,14 +175,20 @@ static void bta_ag_sco_disc_cback(uint16_t sco_idx) {
        bta_ag_cb.sco.p_curr_scb->state = BTA_AG_SCO_CODEC_ST;
        if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings ==
            BTA_AG_SCO_MSBC_SETTINGS_T2) {
          APPL_TRACE_DEBUG("%s: Fallback to mSBC T1 settings", __func__);
          APPL_TRACE_WARNING(
              "%s: eSCO/SCO failed to open, falling back to mSBC T1 settings",
              __func__);
          bta_ag_cb.sco.p_curr_scb->codec_msbc_settings =
              BTA_AG_SCO_MSBC_SETTINGS_T1;
        } else {
          APPL_TRACE_DEBUG("%s: Fallback to CVSD", __func__);
          APPL_TRACE_WARNING(
              "%s: eSCO/SCO failed to open, falling back to CVSD", __func__);
          bta_ag_cb.sco.p_curr_scb->codec_fallback = true;
        }
      }
    } else if (bta_ag_sco_is_opening(bta_ag_cb.sco.p_curr_scb)) {
      APPL_TRACE_ERROR("%s: eSCO/SCO failed to open, no more fall back",
                       __func__);
    }

    bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
@@ -352,6 +358,11 @@ static void bta_ag_cback_sco(tBTA_AG_SCB* p_scb, uint8_t event) {
 *
 ******************************************************************************/
static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
  APPL_TRACE_DEBUG(
      "%s: BEFORE codec_updated=%d, codec_fallback=%d, "
      "sco_codec=%d, peer_codec=%d, msbc_settings=%d",
      __func__, p_scb->codec_updated, p_scb->codec_fallback, p_scb->sco_codec,
      p_scb->peer_codecs, p_scb->codec_msbc_settings);
  tBTA_AG_PEER_CODEC esco_codec = BTA_AG_CODEC_CVSD;

  /* Make sure this SCO handle is not already in use */
@@ -361,18 +372,15 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
    return;
  }

  APPL_TRACE_DEBUG("%s: Using enhanced SCO setup command %d", __func__,
                   controller_get_interface()
                       ->supports_enhanced_setup_synchronous_connection());

  if ((p_scb->sco_codec == BTA_AG_CODEC_MSBC) && !p_scb->codec_fallback &&
      !p_scb->retry_with_sco_only)
  if ((p_scb->sco_codec == BTA_AG_CODEC_MSBC) && !p_scb->codec_fallback)
    esco_codec = BTA_AG_CODEC_MSBC;

  if (p_scb->codec_fallback) {
    p_scb->codec_fallback = false;
    /* Force AG to send +BCS for the next audio connection. */
    p_scb->codec_updated = true;
    /* Reset mSBC settings to T2 for the next audio connection */
    p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
  }

  esco_codec_t codec_index = ESCO_CODEC_CVSD;
@@ -404,32 +412,9 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
  /* If initiating, setup parameters to start SCO/eSCO connection */
  if (is_orig) {
    bta_ag_cb.sco.is_local = true;
    /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
    /* HSP does not prohibit eSCO, but no official support, CVSD only */
    if (p_scb->conn_service == BTA_AG_HFP &&
        p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only) {
    /* Set eSCO Mode */
    BTM_SetEScoMode(&params);
      /* If eSCO or EDR eSCO, retry with SCO only in case of failure */
      if ((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) ||
          !((params.packet_types &
             ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^
            BTA_AG_NO_EDR_ESCO)) {
        /* However, do not retry with SCO when using mSBC */
        if (esco_codec != BTA_AG_CODEC_MSBC) {
          p_scb->retry_with_sco_only = true;
        }
        APPL_TRACE_API("%s: eSCO supported, retry_with_sco_only=%d", __func__,
                       p_scb->retry_with_sco_only);
      }
    } else {
      APPL_TRACE_API("%s: eSCO not supported, retry_with_sco_only=%d", __func__,
                     p_scb->retry_with_sco_only);
      p_scb->retry_with_sco_only = false;
      BTM_SetEScoMode(&params);
    }

    bta_ag_cb.sco.p_curr_scb = p_scb;

    /* save the current codec as sco_codec can be updated while SCO is open. */
    p_scb->inuse_codec = esco_codec;

@@ -441,7 +426,6 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
  } else {
    /* Not initiating, go to listen mode */
    uint8_t* p_bd_addr = NULL;
    p_scb->retry_with_sco_only = false;
    p_bd_addr = p_scb->peer_addr;

    tBTM_STATUS status =
@@ -454,6 +438,11 @@ static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
                   __func__, is_orig, p_scb->sco_idx, status,
                   params.packet_types);
  }
  APPL_TRACE_DEBUG(
      "%s: AFTER codec_updated=%d, codec_fallback=%d, "
      "sco_codec=%d, peer_codec=%d, msbc_settings=%d",
      __func__, p_scb->codec_updated, p_scb->codec_fallback, p_scb->sco_codec,
      p_scb->peer_codecs, p_scb->codec_msbc_settings);
}

/*******************************************************************************
@@ -526,25 +515,6 @@ static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) {
  }
}

/*******************************************************************************
 *
 * Function         bta_ag_attempt_msbc_safe_settings
 *
 * Description    Checks if ESCO connection needs to be attempted using mSBC
 *                T1(safe) settings
 *
 *
 * Returns          true if T1 settings has to be used, false otherwise
 *
 ******************************************************************************/
bool bta_ag_attempt_msbc_safe_settings(tBTA_AG_SCB* p_scb) {
  if (p_scb->svc_conn && p_scb->sco_codec == BTM_SCO_CODEC_MSBC &&
      p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1)
    return true;
  else
    return false;
}

/*******************************************************************************
 *
 * Function         bta_ag_codec_negotiation_timer_cback
@@ -1289,7 +1259,6 @@ void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb,
  /* call app callback */
  bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);

  p_scb->retry_with_sco_only = false;
  /* reset to mSBC T2 settings as the preferred */
  p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
}
@@ -1311,17 +1280,13 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb,
  p_scb->sco_idx = BTM_INVALID_SCO_INDEX;

  /* codec_fallback is set when AG is initiator and connection failed for mSBC.
   */
  /* OR if codec is msbc and T2 settings failed, then retry Safe T1 settings */
  if ((p_scb->codec_fallback && p_scb->svc_conn) ||
      bta_ag_attempt_msbc_safe_settings(p_scb)) {
   * OR if codec is msbc and T2 settings failed, then retry Safe T1 settings */
  if (p_scb->svc_conn &&
      (p_scb->codec_fallback ||
       (p_scb->sco_codec == BTM_SCO_CODEC_MSBC &&
        p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1))) {
    bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
  } else if (p_scb->retry_with_sco_only && p_scb->svc_conn) {
    /* retry_with_sco_only is set when AG is initiator and connection failed for
     * eSCO */
    bta_ag_create_sco(p_scb, true);
  }
  else {
  } else {
    /* Indicate if the closing of audio is because of transfer */
    bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);

@@ -1339,7 +1304,6 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb,
    bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
    p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
  }
  p_scb->retry_with_sco_only = false;
}

/*******************************************************************************
+0 −1
Original line number Diff line number Diff line
@@ -174,7 +174,6 @@ typedef struct {
  uint16_t sco_idx;                       /* SCO handle */
  uint8_t sco_state;                      /* SCO state variable */
  bool sco_close_rfc; /* true if also close RFCOMM after SCO */
  bool retry_with_sco_only;
  tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
  bool svc_conn;      /* set to true when service level connection is up */
  bool send_at_reply; /* set to true to notify framework about AT results */
+9 −39
Original line number Diff line number Diff line
@@ -236,30 +236,9 @@ static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,

  /* if initiating set current scb and peer bd addr */
  if (is_orig) {
    /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
    if (client_cb->peer_version >= HFP_VERSION_1_5 &&
        !client_cb->retry_with_sco_only) {
    BTM_SetEScoMode(&params);
      /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
      if ((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) ||
          !((params.packet_types &
             ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^
            BTA_HF_CLIENT_NO_EDR_ESCO)) {
        client_cb->retry_with_sco_only = true;
        APPL_TRACE_API("Setting retry_with_sco_only to true");
      }
    } else {
      if (client_cb->retry_with_sco_only)
        APPL_TRACE_API("retrying with SCO only");
      client_cb->retry_with_sco_only = false;

      BTM_SetEScoMode(&params);
    }

    /* tell sys to stop av if any */
    bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
  } else {
    client_cb->retry_with_sco_only = false;
  }

  p_bd_addr = client_cb->peer_addr;
@@ -583,8 +562,6 @@ void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
  } else {
    bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
  }

  client_cb->retry_with_sco_only = false;
}

/*******************************************************************************
@@ -611,11 +588,6 @@ void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
  /* clear current scb */
  client_cb->sco_idx = BTM_INVALID_SCO_INDEX;

  /* retry_with_sco_only, will be set only when initiator
  ** and HFClient is first trying to establish an eSCO connection */
  if (client_cb->retry_with_sco_only && client_cb->svc_conn) {
    bta_hf_client_sco_create(client_cb, true);
  } else {
  bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);

  bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
@@ -630,8 +602,6 @@ void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
    bta_hf_client_rfc_do_close(p_data);
  }
}
  client_cb->retry_with_sco_only = false;
}

/*******************************************************************************
 *