Bluetooth: controller: Reduce ISO peripheral CIS establishement delay

New LLCP will process the CIS establishement in the TX path, meaning it
will only process once every ACL connection interval.
If ACL connection interval is significantly longer than the ISO
interval, CIS packets corresponding to the ACL connection interval will
be lost. This may cause latency in audio rendition.

By processing the CIS establishment in the RX path, notification will be
sent immediately, and audio path is enabled fast to reduce latency.

When a CIS fails to establish, the controller shall complete the
procedure by sending a CIS_ESTABLISHED event containing the error.

Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
Morten Priess 2022-12-06 13:08:12 +01:00 committed by Fabio Baltieri
commit 60b1f2b36b
6 changed files with 144 additions and 17 deletions

View file

@ -72,6 +72,7 @@
#include "lll_conn_iso.h"
#include "ull_conn_iso_types.h"
#include "ull_central_iso_internal.h"
#include "ull_llcp.h"
#include "ull_conn_iso_internal.h"
#include "ull_peripheral_iso_internal.h"
@ -2781,6 +2782,25 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx)
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */
#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY) && \
defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
case NODE_RX_TYPE_CIS_ESTABLISHED:
{
struct ll_conn *conn;
(void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL);
conn = ll_conn_get(rx->handle);
if (ull_cp_cc_awaiting_established(conn)) {
ull_cp_cc_established(conn, BT_HCI_ERR_SUCCESS);
}
rx->type = NODE_RX_TYPE_RELEASE;
ll_rx_put_sched(link, rx);
}
break;
#endif /* !CONFIG_BT_LL_SW_LLCP_LEGACY && CONFIG_BT_CTLR_PERIPHERAL_ISO */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \
defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT:

View file

@ -36,6 +36,7 @@
#include "ull_conn_iso_internal.h"
#include "ull_peripheral_iso_internal.h"
#include "ull_internal.h"
#include "ull_llcp.h"
#include "lll/lll_vendor.h"
#include "ll.h"
@ -258,8 +259,6 @@ uint8_t ll_conn_iso_accept_timeout_set(uint16_t timeout)
void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis)
{
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
struct node_rx_conn_iso_estab *est;
struct node_rx_pdu *node_rx;
node_rx = ull_pdu_rx_alloc();
@ -268,8 +267,12 @@ void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis)
return;
}
/* TODO: Send CIS_ESTABLISHED with status != 0 in error scenarios */
node_rx->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED;
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
struct node_rx_conn_iso_estab *est;
/* TODO: Send CIS_ESTABLISHED with status != 0 in error scenarios */
node_rx->hdr.handle = 0xFFFF;
node_rx->hdr.rx_ftr.param = cis;
@ -277,6 +280,11 @@ void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis)
est->status = 0;
est->cis_handle = cis->lll.handle;
ll_rx_put_sched(node_rx->hdr.link, node_rx);
#else
/* Send node to ULL RX demuxer for triggering LLCP state machine */
node_rx->hdr.handle = cis->lll.acl_handle;
ll_rx_put_sched(node_rx->hdr.link, node_rx);
#endif /* defined(CONFIG_BT_LL_SW_LLCP_LEGACY) */
@ -332,7 +340,11 @@ void ull_conn_iso_done(struct node_rx_event_done *done)
}
if (--cis->event_expire == 0) {
/* Stop CIS and defer cleanup to after teardown. */
/* Stop CIS and defer cleanup to after teardown. This will
* only generate a terminate event to the host if CIS has
* been established. If CIS was not established, the
* teardown will send CIS_ESTABLISHED with failure.
*/
ull_conn_iso_cis_stop(cis, NULL,
cis->established ?
BT_HCI_ERR_CONN_TIMEOUT :
@ -835,6 +847,7 @@ static void cis_disabled_cb(void *param)
struct ll_conn_iso_group *cig;
struct ll_conn_iso_stream *cis;
uint32_t ticker_status;
struct ll_conn *conn;
uint16_t handle_iter;
uint8_t is_last_cis;
uint8_t cis_idx;
@ -850,7 +863,6 @@ static void cis_disabled_cb(void *param)
if (cis->lll.flushed) {
ll_iso_stream_released_cb_t cis_released_cb;
struct ll_conn *conn;
conn = ll_conn_get(cis->lll.acl_handle);
cis_released_cb = cis->released_cb;
@ -883,16 +895,25 @@ static void cis_disabled_cb(void *param)
struct node_rx_pdu *node_terminate;
uint32_t ret;
/* Create and enqueue termination node. This shall prevent
* further enqueuing of TX nodes for terminating CIS.
*/
node_terminate = ull_pdu_rx_alloc();
LL_ASSERT(node_terminate);
node_terminate->hdr.handle = cis->lll.handle;
node_terminate->hdr.type = NODE_RX_TYPE_TERMINATE;
*((uint8_t *)node_terminate->pdu) = cis->terminate_reason;
if (cis->established) {
/* Create and enqueue termination node. This shall prevent
* further enqueuing of TX nodes for terminating CIS.
*/
node_terminate = ull_pdu_rx_alloc();
LL_ASSERT(node_terminate);
node_terminate->hdr.handle = cis->lll.handle;
node_terminate->hdr.type = NODE_RX_TYPE_TERMINATE;
*((uint8_t *)node_terminate->pdu) = cis->terminate_reason;
ll_rx_put_sched(node_terminate->hdr.link, node_terminate);
ll_rx_put_sched(node_terminate->hdr.link, node_terminate);
} else {
conn = ll_conn_get(cis->lll.acl_handle);
/* CIS was not established - complete the procedure with error */
if (ull_cp_cc_awaiting_established(conn)) {
ull_cp_cc_established(conn, cis->terminate_reason);
}
}
if (cig->lll.resume_cis == cis->lll.handle) {
/* Resume pending for terminating CIS - stop ticker */

View file

@ -1230,6 +1230,7 @@ void ull_cp_cte_req_set_disable(struct ll_conn *conn)
conn->llcp.cte_req.req_interval = 0U;
}
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
#if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
bool ull_cp_cc_awaiting_reply(struct ll_conn *conn)
{
@ -1276,7 +1277,50 @@ void ull_cp_cc_reject(struct ll_conn *conn, uint8_t error_code)
llcp_rp_cc_reject(conn, ctx);
}
}
#endif /* defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_CTLR_PERIPHERAL_ISO */
#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) || defined(CONFIG_BT_CTLR_CENTRAL_ISO)
bool ull_cp_cc_awaiting_established(struct ll_conn *conn)
{
struct proc_ctx *ctx;
#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
ctx = llcp_rr_peek(conn);
if (ctx && ctx->proc == PROC_CIS_CREATE) {
return llcp_rp_cc_awaiting_established(ctx);
}
#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO)
ctx = llcp_lr_peek(conn);
if (ctx && ctx->proc == PROC_CIS_CREATE) {
return llcp_lp_cc_awaiting_established(ctx);
}
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */
return false;
}
void ull_cp_cc_established(struct ll_conn *conn, uint8_t error_code)
{
struct proc_ctx *ctx;
#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
ctx = llcp_rr_peek(conn);
if (ctx && ctx->proc == PROC_CIS_CREATE) {
ctx->data.cis_create.error = error_code;
llcp_rp_cc_established(conn, ctx);
}
#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO)
ctx = llcp_lr_peek(conn);
if (ctx && ctx->proc == PROC_CIS_CREATE) {
ctx->data.cis_create.error = error_code;
llcp_lp_cc_established(conn, ctx);
}
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */
}
#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO || CONFIG_BT_CTLR_CENTRAL_ISO */
#if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_CENTRAL_ISO)
bool ull_lp_cc_is_active(struct ll_conn *conn)

View file

@ -191,6 +191,11 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis);
*/
bool ull_cp_cc_awaiting_reply(struct ll_conn *conn);
/**
* @brief Is ongoing create cis procedure expecting an established event?
*/
bool ull_cp_cc_awaiting_established(struct ll_conn *conn);
/**
* @brief Get handle of ongoing create cis procedure.
* @return 0xFFFF if none
@ -203,7 +208,7 @@ uint16_t ull_cp_cc_ongoing_handle(struct ll_conn *conn);
void ull_cp_cc_accept(struct ll_conn *conn);
/**
* @brief Rejset the remote devices request to create cis.
* @brief Reject the remote devices request to create cis.
*/
void ull_cp_cc_reject(struct ll_conn *conn, uint8_t error_code);

View file

@ -127,6 +127,9 @@ enum {
/* Reject response received */
RP_CC_EVT_REJECT,
/* Established */
RP_CC_EVT_CIS_ESTABLISHED,
/* Unknown response received */
RP_CC_EVT_UNKNOWN,
};
@ -433,7 +436,6 @@ static void rp_cc_state_wait_ntf_cis_create(struct ll_conn *conn, struct proc_ct
}
}
static void rp_cc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
@ -535,6 +537,10 @@ static void rp_cc_state_wait_cis_established(struct ll_conn *conn, struct proc_c
rp_cc_complete(conn, ctx, evt, param);
}
break;
case RP_CC_EVT_CIS_ESTABLISHED:
/* CIS was established, so let's go ahead and complete procedure */
rp_cc_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
@ -623,6 +629,11 @@ bool llcp_rp_cc_awaiting_reply(struct proc_ctx *ctx)
return (ctx->state == RP_CC_STATE_WAIT_REPLY);
}
bool llcp_rp_cc_awaiting_established(struct proc_ctx *ctx)
{
return (ctx->state == RP_CC_STATE_WAIT_CIS_ESTABLISHED);
}
void llcp_rp_cc_accept(struct ll_conn *conn, struct proc_ctx *ctx)
{
rp_cc_execute_fsm(conn, ctx, RP_CC_EVT_CIS_REQ_ACCEPT, NULL);
@ -642,6 +653,11 @@ bool llcp_rp_cc_awaiting_instant(struct proc_ctx *ctx)
{
return (ctx->state == RP_CC_STATE_WAIT_INSTANT);
}
void llcp_rp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx)
{
rp_cc_execute_fsm(conn, ctx, RP_CC_EVT_CIS_ESTABLISHED, NULL);
}
#endif /* CONFIG_BT_PERIPHERAL */
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO)
@ -669,6 +685,9 @@ enum {
/* Reject response received */
LP_CC_EVT_REJECT,
/* CIS established */
LP_CC_EVT_ESTABLISHED,
/* Unknown response received */
LP_CC_EVT_UNKNOWN,
};
@ -898,6 +917,10 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx
lp_cc_complete(conn, ctx, evt, param);
}
break;
case LP_CC_EVT_ESTABLISHED:
/* CIS was established, so let's go ahead and complete procedure */
lp_cc_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
@ -956,4 +979,14 @@ bool llcp_lp_cc_is_active(struct proc_ctx *ctx)
{
return ctx->state != LP_CC_STATE_IDLE;
}
bool llcp_lp_cc_awaiting_established(struct proc_ctx *ctx)
{
return (ctx->state == LP_CC_STATE_WAIT_ESTABLISHED);
}
void llcp_lp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx)
{
lp_cc_execute_fsm(conn, ctx, LP_CC_EVT_ESTABLISHED, NULL);
}
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */

View file

@ -711,14 +711,18 @@ void llcp_lp_cc_init_proc(struct proc_ctx *ctx);
void llcp_lp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx);
void llcp_lp_cc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param);
bool llcp_lp_cc_is_active(struct proc_ctx *ctx);
bool llcp_lp_cc_awaiting_established(struct proc_ctx *ctx);
void llcp_lp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_rp_cc_init_proc(struct proc_ctx *ctx);
void llcp_rp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx);
void llcp_rp_cc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param);
bool llcp_rp_cc_awaiting_reply(struct proc_ctx *ctx);
bool llcp_rp_cc_awaiting_established(struct proc_ctx *ctx);
void llcp_rp_cc_accept(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_rp_cc_reject(struct ll_conn *conn, struct proc_ctx *ctx);
bool llcp_rp_cc_awaiting_instant(struct proc_ctx *ctx);
void llcp_rp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_pdu_decode_cis_req(struct proc_ctx *ctx, struct pdu_data *pdu);
void llcp_pdu_encode_cis_rsp(struct proc_ctx *ctx, struct pdu_data *pdu);