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

Commit ee35660f authored by Jakub Rotkiewicz (xWF)'s avatar Jakub Rotkiewicz (xWF) Committed by Gerrit Code Review
Browse files

Merge changes Ib5c2104a,If4620e7c into main

* changes:
  flags: a2dp_sm_ignore_connect_events_in_connecting_state
  avdt: handle signaling on peer failure
parents 31f8b078 1aa5b75b
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ from bumble.avdtp import (
    AVDTP_OPEN_STATE,
    AVDTP_PSM,
    AVDTP_STREAMING_STATE,
    AVDTP_TSEP_SRC,
    Listener,
    MediaCodecCapabilities,
    Protocol,
@@ -74,6 +75,7 @@ from typing import Optional, Tuple
logger = logging.getLogger(__name__)

AVDTP_HANDLE_SUSPEND_CFM_BAD_STATE = 'com.android.bluetooth.flags.avdt_handle_suspend_cfm_bad_state'
AVDTP_HANDLE_SIGNALING_ON_PEER_FAILURE = 'com.android.bluetooth.flags.avdt_handle_signaling_on_peer_failure'


async def initiate_pairing(device, address) -> Connection:
@@ -660,6 +662,76 @@ class A2dpTest(base_test.BaseTestClass): # type: ignore[misc]
        # Wait for AVDTP Close
        await asyncio.wait_for(avdtp_future, timeout=10.0)

    @avatar.asynchronous
    async def test_avdt_open_after_timeout(self) -> None:
        """Test AVDTP automatically opens stream after timeout if peer device only configures codec.

        1. Pair and Connect RD1 -> DUT
        2. Connect AVDTP RD1 -> DUT but do not send AVDT Open Command
        3. Check that the DUT will abort and reopen the AVDTP as initiator
        """

        class TestAvdtProtocol(Protocol):

            def on_open_command(self, command):
                nonlocal avdtp_future
                logger.info("<< AVDTP Open received >>")
                avdtp_future.set_result(None)
                return super().on_open_command(command)

        # Enable BAD_STATE handling
        for server in self.devices._servers:
            if isinstance(server, AndroidPandoraServer):
                server.device.adb.shell(
                    ['device_config override bluetooth', AVDTP_HANDLE_SIGNALING_ON_PEER_FAILURE,
                     'true'])  # type: ignore
                break

        # Connect and pair RD1.
        ref1_dut, dut_ref1 = await asyncio.gather(
            initiate_pairing(self.ref1, self.dut.address),
            accept_pairing(self.dut, self.ref1.address),
        )

        # Create a listener to wait for AVDTP open
        avdtp_future = asyncio.get_running_loop().create_future()

        # Retrieve Bumble connection object from Pandora connection token
        connection = pandora.get_raw_connection(device=self.ref1, connection=ref1_dut)
        assert connection is not None

        channel = await connection.create_l2cap_channel(spec=ClassicChannelSpec(psm=AVDTP_PSM))
        client = TestAvdtProtocol(channel)
        sink = client.add_sink(sbc_codec_capabilities())
        endpoints = await client.discover_remote_endpoints()
        logger.info(f"endpoints: {endpoints}")
        assert len(endpoints) >= 1
        remote_source = list(endpoints)[0]
        assert remote_source.in_use == 0
        assert remote_source.media_type == AVDTP_AUDIO_MEDIA_TYPE
        assert remote_source.tsep == AVDTP_TSEP_SRC
        logger.info(f"remote_source: {remote_source}")

        configuration = MediaCodecCapabilities(
            media_type=AVDTP_AUDIO_MEDIA_TYPE,
            media_codec_type=A2DP_SBC_CODEC_TYPE,
            media_codec_information=SbcMediaCodecInformation.from_lists(
                sampling_frequencies=[44100],
                channel_modes=[SBC_JOINT_STEREO_CHANNEL_MODE],
                block_lengths=[16],
                subbands=[8],
                allocation_methods=[SBC_LOUDNESS_ALLOCATION_METHOD],
                minimum_bitpool_value=2,
                maximum_bitpool_value=53,
            ),
        )

        response = await remote_source.set_configuration(sink.seid, [configuration])
        logger.info(f"response: {response}")

        # Wait for AVDTP Open from DUT
        await asyncio.wait_for(avdtp_future, timeout=10.0)


if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
+10 −0
Original line number Diff line number Diff line
@@ -135,3 +135,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "a2dp_sm_ignore_connect_events_in_connecting_state"
    namespace: "bluetooth"
    description: "When received CONNECT event in Connecting state, with no prior DISCONNECT - ignore the event"
    bug: "383576378"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
+62 −2
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/list.h"
#include "osi/include/osi.h"  // UINT_TO_PTR PTR_TO_UINT
#include "osi/include/properties.h"
#include "sdpdefs.h"
#include "stack/include/a2dp_ext.h"
@@ -114,6 +115,13 @@ constexpr char kBtmLogTag[] = "A2DP";
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4

/* Time to wait for open from SNK when signaling is initiated from SNK. */
/* If not, we abort and try to initiate the connection as SRC. */
#ifndef BTA_AV_ACCEPT_OPEN_TIMEOUT_MS
#define BTA_AV_ACCEPT_OPEN_TIMEOUT_MS (2 * 1000) /* 2 seconds */
#endif

static void bta_av_accept_open_timer_cback(void* data);
static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, tBT_A2DP_OFFLOAD* p_a2dp_offload);

/* state machine states */
@@ -866,6 +874,9 @@ void bta_av_cleanup(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* /* p_data */) {
  alarm_cancel(p_scb->avrc_ct_timer);
  alarm_cancel(p_scb->link_signalling_timer);
  alarm_cancel(p_scb->accept_signalling_timer);
  if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
    alarm_cancel(p_scb->accept_open_timer);
  }

  /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
    vendor_get_interface()->send_command(
@@ -1009,7 +1020,9 @@ void bta_av_disconnect_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* /* p_data */) {
  alarm_cancel(p_scb->link_signalling_timer);
  alarm_cancel(p_scb->accept_signalling_timer);
  alarm_cancel(p_scb->avrc_ct_timer);

  if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
    alarm_cancel(p_scb->accept_open_timer);
  }
  // conn_lcb is the index bitmask of all used LCBs, and since LCB and SCB use
  // the same index, it should be safe to use SCB index here.
  if ((bta_av_cb.conn_lcb & (1 << p_scb->hdi)) != 0) {
@@ -1117,6 +1130,14 @@ void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
      p_scb->uuid_int = p_scb->open_api.uuid;
    }
    bta_av_discover_req(p_scb, NULL);
    if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
      // Set timer to initiate stream opening if peer doesn't
      if (!p_scb->accept_open_timer) {
        p_scb->accept_open_timer = alarm_new("accept_open_timer");
      }
      alarm_set_on_mloop(p_scb->accept_open_timer, BTA_AV_ACCEPT_OPEN_TIMEOUT_MS,
                         bta_av_accept_open_timer_cback, UINT_TO_PTR(p_scb->hdi));
    }
  }
}

@@ -1136,6 +1157,9 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {

  log::verbose("peer {} bta_handle: 0x{:x}", p_scb->PeerAddress(), p_scb->hndl);

  if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
    alarm_cancel(p_scb->accept_open_timer);
  }
  msg.hdr.layer_specific = p_scb->hndl;
  msg.is_up = true;
  msg.peer_addr = p_scb->PeerAddress();
@@ -2962,8 +2986,14 @@ void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
    /* API open will be handled at timeout if SNK did not start signalling. */
    /* API open will be ignored if SNK starts signalling.                   */
  } else {
    /* SNK did not start signalling, API was called N seconds timeout. */
    /* SNK did not start signalling or failed to complete the AVDT configuration in time. */
    /* API was called N seconds timeout. */
    /* We need to switch to INIT state and start opening connection. */
    if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
      // Reset peer device
      bta_av_cco_close(p_scb, p_data);
      alarm_cancel(p_scb->avrc_ct_timer);
    }
    p_scb->coll_mask = 0;
    bta_av_set_scb_sst_init(p_scb);

@@ -3332,3 +3362,33 @@ void bta_av_api_set_peer_sep(tBTA_AV_DATA* p_data) {
    }
  }
}

/*******************************************************************************
 *
 * Function         bta_av_accept_open_timer_cback
 *
 * Description      Process the timeout when SRC is accepting connection
 *                  and SNK did not open the stream.
 *
 * Returns          void
 *
 ******************************************************************************/
static void bta_av_accept_open_timer_cback(void* data) {
  uint32_t hdi = PTR_TO_UINT(data);
  tBTA_AV_SCB* p_scb = NULL;
  if (hdi < BTA_AV_NUM_STRS) {
    p_scb = bta_av_cb.p_scb[hdi];
  }
  if (p_scb == nullptr) {
    log::error("SCB not found for index {}", hdi);
    return;
  }

  /* Abort the current connection */
  AVDT_AbortReq(p_scb->avdt_handle);

  /* Try connecting and opening as initiator with event: BTA_AV_API_OPEN_EVT */
  tBTA_AV_API_OPEN* p_buf = (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
  memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
  bta_sys_sendmsg(p_buf);
}
 No newline at end of file
+5 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#define LOG_TAG "bluetooth-a2dp"

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>

#include <cstddef>
#include <cstdint>
@@ -1408,7 +1409,10 @@ void bta_av_disable(tBTA_AV_CB* p_cb, tBTA_AV_DATA* /* p_data */) {
      p_cb->p_scb[xx]->link_signalling_timer = NULL;
      alarm_free(p_cb->p_scb[xx]->accept_signalling_timer);
      p_cb->p_scb[xx]->accept_signalling_timer = NULL;

      if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
        alarm_free(p_cb->p_scb[xx]->accept_open_timer);
        p_cb->p_scb[xx]->accept_open_timer = NULL;
      }
      hdr.layer_specific = xx + 1;
      bta_av_api_deregister((tBTA_AV_DATA*)&hdr);
      disabling_in_progress = true;
+1 −0
Original line number Diff line number Diff line
@@ -492,6 +492,7 @@ public:
  alarm_t* avrc_ct_timer;                   /* delay timer for AVRC CT */
  alarm_t* link_signalling_timer;
  alarm_t* accept_signalling_timer; /* timer to monitor signalling when accepting */
  alarm_t* accept_open_timer;       /* timer to monitor AVDT open when accepting */
  uint16_t l2c_cid;                 /* L2CAP channel ID */
  uint16_t stream_mtu;              /* MTU of stream */
  uint8_t media_type;               /* Media type: AVDT_MEDIA_TYPE_* */
Loading