bass: Add support to request bcode
authorIulia Tanasescu <iulia.tanasescu@nxp.com>
Tue, 8 Oct 2024 08:01:22 +0000 (11:01 +0300)
committerWootak Jung <wootak.jung@samsung.com>
Thu, 20 Feb 2025 07:43:23 +0000 (16:43 +0900)
This adds support for a Scan Delegator to request the Broadcast Code
from peer Broadcast Assistants and to update a BAP stream QoS with the
value.

A BASS API is added to update the BIG encryption status of a Broadcast
Receive State characteristic and to notify peers. When a peer provides
the Code using the BASS "Set Broadcast Code" operation, the BAP stream
QoS is updated. The driver calling this API will pass a callback as
parameter, which will be called to signal that the Broadcast Code has
been received and stored in the stream QoS.

A timeout is set to wait for Broadcast Assistants to provide the Code.
If the timeout expires, the callback will be code with the appropriate
error status.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
profiles/audio/bass.c
profiles/audio/bass.h

index 2316f8e24d462aeafef7ede52e450a42c40a1004..8af4b6c331e9e2c07c0e2f0959565c85a1deb8b8 100644 (file)
@@ -102,6 +102,15 @@ struct bass_delegator {
        struct bt_bcast_src *src;
        struct bt_bap *bap;
        unsigned int state_id;
+       uint8_t *bcode;
+       unsigned int timeout;
+       struct queue *bcode_reqs;
+};
+
+struct bass_bcode_req {
+       struct bt_bap_stream *stream;
+       bt_bass_bcode_func_t cb;
+       void *user_data;
 };
 
 static struct queue *sessions;
@@ -115,6 +124,90 @@ static void bass_debug(const char *str, void *user_data)
        DBG_IDX(0xffff, "%s", str);
 }
 
+static gboolean req_timeout(gpointer user_data)
+{
+       struct bass_delegator *dg = user_data;
+       struct bass_bcode_req *req;
+
+       DBG("delegator %p", dg);
+
+       dg->timeout = 0;
+
+       while ((req = queue_pop_head(dg->bcode_reqs))) {
+               if (req->cb)
+                       req->cb(req->user_data, -ETIMEDOUT);
+
+               free(req);
+       }
+
+       return FALSE;
+}
+
+static bool delegator_match_bap(const void *data, const void *match_data)
+{
+       const struct bass_delegator *dg = data;
+       const struct bt_bap *bap = match_data;
+
+       return dg->bap == bap;
+}
+
+static void stream_set_bcode(uint8_t *bcode, struct bt_bap_stream *stream,
+                               bt_bass_bcode_func_t cb, void *user_data)
+{
+       struct bt_bap_qos *qos = bt_bap_stream_get_qos(stream);
+
+       /* Allocate Broadcast Code inside stream QoS */
+       qos->bcast.bcode = util_iov_new(bcode, BT_BASS_BCAST_CODE_SIZE);
+
+       if (cb)
+               cb(user_data, 0);
+}
+
+void bass_req_bcode(struct bt_bap_stream *stream,
+                               bt_bass_bcode_func_t cb,
+                               void *user_data)
+{
+       struct bt_bap *bap = bt_bap_stream_get_session(stream);
+       struct bass_delegator *dg;
+       struct bass_bcode_req *req;
+
+       dg = queue_find(delegators, delegator_match_bap, bap);
+       if (!dg) {
+               cb(user_data, -EINVAL);
+               return;
+       }
+
+       if (dg->bcode) {
+               /* Broadcast Code has already been received before. */
+               stream_set_bcode(dg->bcode, stream, cb, user_data);
+               return;
+       }
+
+       /* Create a request for the Broadcast Code. The request
+        * will be considered handled when the Broadcast Code is
+        * received from a Broadcast Assistant.
+        */
+       req = new0(struct bass_bcode_req, 1);
+       if (!req)
+               return;
+
+       req->stream = stream;
+       req->cb = cb;
+       req->user_data = user_data;
+
+       queue_push_tail(dg->bcode_reqs, req);
+
+       /* Mark the encryption status as "Broadcast Code Required"
+        * in the Broadcast Receive State characteristic and notify
+        * Broadcast Assistants.
+        */
+       bt_bass_set_enc(dg->src, BT_BASS_BIG_ENC_STATE_BCODE_REQ);
+
+       /* Add timeout for Broadcast Assistants to provide the Code. */
+       if (!dg->timeout)
+               dg->timeout = g_timeout_add_seconds(10, req_timeout, dg);
+}
+
 static bool delegator_match_device(const void *data, const void *match_data)
 {
        const struct bass_delegator *dg = data;
@@ -231,6 +324,13 @@ bool bass_bcast_remove(struct btd_device *device)
        /* Unregister BAP stream state changed callback. */
        bt_bap_state_unregister(dg->bap, dg->state_id);
 
+       if (dg->timeout)
+               g_source_remove(dg->timeout);
+
+       queue_destroy(dg->bcode_reqs, free);
+
+       free(dg->bcode);
+
        free(dg);
 
        return true;
@@ -792,6 +892,7 @@ probe:
 
        dg->device = device;
        dg->src = bcast_src;
+       dg->bcode_reqs = queue_new();
 
        if (!delegators)
                delegators = queue_new();
@@ -806,6 +907,43 @@ probe:
        return 0;
 }
 
+static bool delegator_match_src(const void *data, const void *match_data)
+{
+       const struct bass_delegator *dg = data;
+       const struct bt_bcast_src *src = match_data;
+
+       return dg->src == src;
+}
+
+static int handle_set_bcode_req(struct bt_bcast_src *bcast_src,
+                       struct bt_bass_set_bcast_code_params *params,
+                       struct bass_data *data)
+{
+       struct bass_delegator *dg;
+       struct bass_bcode_req *req;
+
+       dg = queue_find(delegators, delegator_match_src, bcast_src);
+       if (!dg)
+               return -EINVAL;
+
+       dg->bcode = new0(uint8_t, BT_BASS_BCAST_CODE_SIZE);
+       memcpy(dg->bcode, params->bcast_code, BT_BASS_BCAST_CODE_SIZE);
+
+       if (dg->timeout) {
+               g_source_remove(dg->timeout);
+               dg->timeout = 0;
+       }
+
+       /* Set the Broadcast Code for each stream that required it. */
+       while ((req = queue_pop_head(dg->bcode_reqs))) {
+               stream_set_bcode(dg->bcode, req->stream, req->cb,
+                                                       req->user_data);
+               free(req);
+       }
+
+       return 0;
+}
+
 static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params,
                void *user_data)
 {
@@ -816,6 +954,9 @@ static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params,
        case BT_BASS_ADD_SRC:
                err = handle_add_src_req(bcast_src, params, data);
                break;
+       case BT_BASS_SET_BCAST_CODE:
+               err = handle_set_bcode_req(bcast_src, params, data);
+               break;
        }
 
        return err;
index 5e34db90afef07bcb15e83c8b423558bc5b169fd..257346374ef179ca64b63631bd412897ff8b0909 100644 (file)
@@ -16,3 +16,9 @@ bool bass_bcast_probe(struct btd_device *device, struct bt_bap *bap);
 bool bass_bcast_remove(struct btd_device *device);
 
 bool bass_check_bis(struct btd_device *device, uint8_t bis);
+
+typedef void (*bt_bass_bcode_func_t)(void *user_data, int err);
+
+void bass_req_bcode(struct bt_bap_stream *stream,
+                               bt_bass_bcode_func_t cb,
+                               void *user_data);