From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> When processing a CP operation the CP shall be notified ahead of the ASE itself: 'If the server successfully completes a client-initiated ASE Control operation for an ASE, the server shall send a notification of the ASE Control Point characteristic value formatted as defined in Table 4.7. The server shall then perform the behavior defined in Section 5.1 through Section 5.8 for that ASE Control operation and send notifications of any ASE characteristic values written during that ASE Control operation.' So this delays the processing of notifications of ASE states so the CP responses always appears first in the notification e.g: > ACL Data RX: Handle 42 flags 0x02 dlen 59 ATT: Handle Multiple Value Notification (0x23) len 54 Length: 0x0008 Handle: 0x0036 Type: ASE Control Point (0x2bc6) Data[8]: 0202030000010000 Opcode: QoS Configuration (0x02) Number of ASE(s): 2 ASE: #0 ASE ID: 0x03 ASE Response Code: Success (0x00) ASE Response Reason: None (0x00) ASE: #1 ASE ID: 0x01 ASE Response Code: Success (0x00) ASE Response Reason: None (0x00) Length: 0x0011 Handle: 0x0030 Type: Source ASE (0x2bc5) Data[17]: 0302000010270000022800020a00409c00 ASE ID: 3 State: QoS Configured (0x02) CIG ID: 0x00 CIS ID: 0x00 SDU Interval: 10000 usec Framing: Unframed (0x00) PHY: 0x02 LE 2M PHY (0x02) Max SDU: 40 RTN: 2 Max Transport Latency: 10 Presentation Delay: 40000 us Length: 0x0011 Handle: 0x002a Type: Sink ASE (0x2bc4) Data[17]: 0102000010270000025000020a00409c00 ASE ID: 1 State: QoS Configured (0x02) CIG ID: 0x00 CIS ID: 0x00 SDU Interval: 10000 usec Framing: Unframed (0x00) PHY: 0x02 LE 2M PHY (0x02) Max SDU: 80 RTN: 2 Max Transport Latency: 10 Presentation Delay: 40000 us --- src/shared/bap.c | 53 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/shared/bap.c b/src/shared/bap.c index 3a4c1f9d3a98..d59eac8cca16 100644 --- a/src/shared/bap.c +++ b/src/shared/bap.c @@ -169,6 +169,7 @@ struct bt_bap { unsigned int process_id; unsigned int disconn_id; unsigned int idle_id; + bool in_cp_write; struct queue *reqs; struct queue *notify; @@ -266,6 +267,7 @@ struct bt_bap_stream { const struct bt_bap_stream_ops *ops; uint8_t old_state; uint8_t state; + unsigned int state_id; bool client; void *user_data; }; @@ -1102,6 +1104,8 @@ static void bap_stream_free(void *data) { struct bt_bap_stream *stream = data; + timeout_remove(stream->state_id); + if (stream->ep) stream->ep->stream = NULL; @@ -1579,20 +1583,17 @@ static bool bap_queue_req(struct bt_bap *bap, struct bt_bap_req *req) return true; } -static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state) +static bool stream_notify_state(void *data) { + struct bt_bap_stream *stream = data; struct bt_bap_endpoint *ep = stream->ep; - ep->old_state = ep->state; - ep->state = state; + DBG(stream->bap, "stream %p", stream); - DBG(stream->bap, "stream %p dir 0x%02x: %s -> %s", stream, - bt_bap_stream_get_dir(stream), - bt_bap_stream_statestr(stream->ep->old_state), - bt_bap_stream_statestr(stream->ep->state)); - - if (stream->lpac->type == BT_BAP_BCAST_SINK || stream->client) - goto done; + if (stream->state_id) { + timeout_remove(stream->state_id); + stream->state_id = 0; + } switch (ep->state) { case BT_ASCS_ASE_STATE_IDLE: @@ -1610,6 +1611,31 @@ static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state) break; } + return false; +} + +static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state) +{ + struct bt_bap_endpoint *ep = stream->ep; + + ep->old_state = ep->state; + ep->state = state; + + DBG(stream->bap, "stream %p dir 0x%02x: %s -> %s", stream, + bt_bap_stream_get_dir(stream), + bt_bap_stream_statestr(stream->ep->old_state), + bt_bap_stream_statestr(stream->ep->state)); + + if (stream->client) + goto done; + + if (!stream->bap->in_cp_write) + stream_notify_state(stream); + else if (!stream->state_id) + stream->state_id = timeout_add(BAP_PROCESS_TIMEOUT, + stream_notify_state, + stream, NULL); + done: bap_stream_state_changed(stream); } @@ -3069,8 +3095,15 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib, DBG(bap, "%s", handler->str); + /* Set in_cp_write so ASE notification are not sent ahead of + * CP notifcation. + */ + bap->in_cp_write = true; + for (i = 0; i < hdr->num; i++) ret = handler->func(ascs, bap, &iov, rsp); + + bap->in_cp_write = false; } else { DBG(bap, "Unknown opcode 0x%02x", hdr->op); ascs_ase_rsp_add_errno(rsp, 0x00, -ENOTSUP); -- 2.45.2