shared/bass: Introduce Add Source opcode handler
authorIulia Tanasescu <iulia.tanasescu@nxp.com>
Thu, 29 Jun 2023 08:07:35 +0000 (11:07 +0300)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 5 Jan 2024 13:34:03 +0000 (19:04 +0530)
This implements the Control Point handler for the Add Source operation.

Makefile.am
profiles/audio/bass.c
src/shared/bass.c
src/shared/bass.h
unit/test-bass.c

index f05e8f7117ab44add7c772f2a1316b1e847e52e7..c25119656e9b25724d31c042a891cc6db5af8a37 100755 (executable)
@@ -572,7 +572,7 @@ unit_test_bap_LDADD = src/libshared-glib.la \
 
 unit_tests += unit/test-bass
 
-unit_test_bass_SOURCES = unit/test-bass.c
+unit_test_bass_SOURCES = unit/test-bass.c $(btio_sources)
 unit_test_bass_LDADD = src/libshared-glib.la \
                                lib/libbluetooth-internal.la $(GLIB_LIBS)
 
index d28809098058e6030a8d77fd1ccbfe1f221e4c9d..9cc6944ca99301b749766a2dc39e3a603be1c126 100644 (file)
 #include "src/shared/gatt-db.h"
 #include "src/shared/gatt-client.h"
 #include "src/shared/gatt-server.h"
+#include "src/adapter.h"
 #include "src/shared/bass.h"
 
 #include "src/plugin.h"
-#include "src/adapter.h"
 #include "src/gatt-database.h"
 #include "src/device.h"
 #include "src/profile.h"
@@ -195,7 +195,8 @@ static int bass_probe(struct btd_service *service)
        data->service = service;
 
        data->bass = bt_bass_new(btd_gatt_database_get_db(database),
-                                       btd_device_get_gatt_db(device));
+                                       btd_device_get_gatt_db(device),
+                                       btd_adapter_get_address(adapter));
        if (!data->bass) {
                error("Unable to create BASS instance");
                free(data);
@@ -266,6 +267,25 @@ static int bass_disconnect(struct btd_service *service)
        return 0;
 }
 
+static int bass_server_probe(struct btd_profile *p,
+                               struct btd_adapter *adapter)
+{
+       struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+
+       DBG("BASS path %s", adapter_get_path(adapter));
+
+       bt_bass_add_db(btd_gatt_database_get_db(database),
+                               btd_adapter_get_address(adapter));
+
+       return 0;
+}
+
+static void bass_server_remove(struct btd_profile *p,
+                                       struct btd_adapter *adapter)
+{
+       DBG("BASS remove Adapter");
+}
+
 static struct btd_profile bass_service = {
        .name           = "bass",
        .priority       = BTD_PROFILE_PRIORITY_MEDIUM,
@@ -274,6 +294,8 @@ static struct btd_profile bass_service = {
        .device_remove  = bass_remove,
        .accept         = bass_accept,
        .disconnect     = bass_disconnect,
+       .adapter_probe  = bass_server_probe,
+       .adapter_remove = bass_server_remove,
        .experimental   = true,
 };
 
index 423ab5bf72702e9de9d2a9800c3894e8c5f20b4b..1bb40877fad91c00deb83056a063af78c64645d8 100644 (file)
 #include <stdbool.h>
 #include <unistd.h>
 #include <errno.h>
+#include <poll.h>
 
 #include "lib/bluetooth.h"
 #include "lib/uuid.h"
+#include "lib/iso.h"
+
+#include "btio/btio.h"
 
 #include "src/shared/queue.h"
 #include "src/shared/util.h"
@@ -25,6 +29,8 @@
 #include "src/shared/gatt-client.h"
 #include "src/shared/bass.h"
 
+#define MAX_BIS_BITMASK_IDX            31
+
 #define DBG(_bass, fmt, arg...) \
        bass_debug(_bass, "%s:%s() " fmt, __FILE__, __func__, ## arg)
 
@@ -45,6 +51,7 @@ struct bt_bcast_recv_state {
 
 struct bt_bass_db {
        struct gatt_db *db;
+       bdaddr_t adapter_bdaddr;
        struct queue *bcast_srcs;
        struct gatt_db_attribute *service;
        struct gatt_db_attribute *bcast_audio_scan_cp;
@@ -82,6 +89,35 @@ static struct queue *bass_db;
 static struct queue *bass_cbs;
 static struct queue *sessions;
 
+#define DEFAULT_IO_QOS \
+{ \
+       .interval       = 10000, \
+       .latency        = 10, \
+       .sdu            = 40, \
+       .phy            = 0x02, \
+       .rtn            = 2, \
+}
+
+static struct bt_iso_qos default_qos = {
+       .bcast = {
+               .big                    = BT_ISO_QOS_BIG_UNSET,
+               .bis                    = BT_ISO_QOS_BIS_UNSET,
+               .sync_interval          = 0x07,
+               .packing                = 0x00,
+               .framing                = 0x00,
+               .in                     = DEFAULT_IO_QOS,
+               .out                    = DEFAULT_IO_QOS,
+               .encryption             = 0x00,
+               .bcode                  = {0x00},
+               .options                = 0x00,
+               .skip                   = 0x0000,
+               .sync_timeout           = 0x4000,
+               .sync_cte_type          = 0x00,
+               .mse                    = 0x00,
+               .timeout                = 0x4000,
+       }
+};
+
 static void bass_bcast_src_free(void *data);
 
 static void bass_debug(struct bt_bass *bass, const char *format, ...)
@@ -461,7 +497,7 @@ static bool bass_check_cp_command_len(const uint8_t *value, size_t len)
        return true;
 }
 
-static void bass_handle_remote_scan_stopped_op(struct bt_bass_db *bdb,
+static void bass_handle_remote_scan_stopped_op(struct bt_bass *bass,
                                        struct gatt_db_attribute *attrib,
                                        uint8_t opcode,
                                        unsigned int id,
@@ -472,7 +508,7 @@ static void bass_handle_remote_scan_stopped_op(struct bt_bass_db *bdb,
                gatt_db_attribute_write_result(attrib, id, 0x00);
 }
 
-static void bass_handle_remote_scan_started_op(struct bt_bass_db *bdb,
+static void bass_handle_remote_scan_started_op(struct bt_bass *bass,
                                        struct gatt_db_attribute *attrib,
                                        uint8_t opcode,
                                        unsigned int id,
@@ -491,7 +527,7 @@ static bool bass_src_id_match(const void *data, const void *match_data)
        return (bcast_src->id == *id);
 }
 
-static void bass_handle_remove_src_op(struct bt_bass_db *bdb,
+static void bass_handle_remove_src_op(struct bt_bass *bass,
                                        struct gatt_db_attribute *attrib,
                                        uint8_t opcode,
                                        unsigned int id,
@@ -504,7 +540,7 @@ static void bass_handle_remove_src_op(struct bt_bass_db *bdb,
        /* Get Remove Source command parameters */
        params = util_iov_pull_mem(iov, sizeof(*params));
 
-       bcast_src = queue_find(bdb->bcast_srcs,
+       bcast_src = queue_find(bass->ldb->bcast_srcs,
                                                bass_src_id_match,
                                                &params->id);
 
@@ -531,7 +567,7 @@ static void bass_handle_remove_src_op(struct bt_bass_db *bdb,
                        return;
 
        /* Accept the operation and remove source */
-       queue_remove(bdb->bcast_srcs, bcast_src);
+       queue_remove(bass->ldb->bcast_srcs, bcast_src);
        gatt_db_attribute_notify(bcast_src->attr, NULL, 0, att);
        bass_bcast_src_free(bcast_src);
 
@@ -539,6 +575,338 @@ static void bass_handle_remove_src_op(struct bt_bass_db *bdb,
                gatt_db_attribute_write_result(attrib, id, 0x00);
 }
 
+static bool bass_src_attr_match(const void *data, const void *match_data)
+{
+       const struct bt_bcast_src *bcast_src = data;
+       const struct gatt_db_attribute *attr = match_data;
+
+       return (bcast_src->attr == attr);
+}
+
+static gboolean check_io_err(GIOChannel *io)
+{
+       struct pollfd fds;
+
+       memset(&fds, 0, sizeof(fds));
+       fds.fd = g_io_channel_unix_get_fd(io);
+       fds.events = POLLERR;
+
+       if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLERR))
+               return TRUE;
+
+       return FALSE;
+}
+
+static void bass_bis_unref(void *data)
+{
+       GIOChannel *io = data;
+
+       g_io_channel_unref(io);
+}
+
+static void connect_cb(GIOChannel *io, GError *gerr,
+                               gpointer user_data)
+{
+       struct bt_bcast_src *bcast_src = user_data;
+       uint8_t *notify_data;
+       size_t notify_data_len;
+       int bis_idx;
+       int i;
+
+       if (bcast_src->sync_state == BT_BASS_NOT_SYNCHRONIZED_TO_PA)
+               bcast_src->sync_state = BT_BASS_SYNCHRONIZED_TO_PA;
+
+       /* Keep io reference */
+       g_io_channel_ref(io);
+       queue_push_tail(bcast_src->bises, io);
+
+       for (i = 0; i < bcast_src->num_subgroups; i++) {
+               struct bt_bass_subgroup_data *data =
+                               &bcast_src->subgroup_data[i];
+
+               for (bis_idx = 0; bis_idx < MAX_BIS_BITMASK_IDX; bis_idx++) {
+                       if (data->pending_bis_sync & (1 << bis_idx)) {
+                               data->bis_sync |= (1 << bis_idx);
+                               data->pending_bis_sync &= ~(1 << bis_idx);
+                               break;
+                       }
+               }
+
+               if (bis_idx < MAX_BIS_BITMASK_IDX)
+                       break;
+       }
+
+       for (i = 0; i < bcast_src->num_subgroups; i++) {
+               if (bcast_src->subgroup_data[i].pending_bis_sync)
+                       break;
+       }
+
+       /* If there are still pending bises, wait for their
+        * notifications also before sending notification to
+        * client
+        */
+       if (i != bcast_src->num_subgroups)
+               return;
+
+       /* All connections have been notified */
+       if (check_io_err(io)) {
+               DBG(bcast_src->bass, "BIG sync failed");
+
+               /* Close all connected bises */
+               queue_destroy(bcast_src->bises, bass_bis_unref);
+               bcast_src->bises = NULL;
+
+               /* Close listen io */
+               g_io_channel_shutdown(bcast_src->listen_io, TRUE, NULL);
+               g_io_channel_unref(bcast_src->listen_io);
+               bcast_src->listen_io = NULL;
+
+               for (i = 0; i < bcast_src->num_subgroups; i++)
+                       bcast_src->subgroup_data[i].bis_sync =
+                               BT_BASS_BIG_SYNC_FAILED_BITMASK;
+       }
+
+       /* Send notification to client */
+       notify_data = bass_build_notif_from_bcast_src(bcast_src,
+                                               &notify_data_len);
+
+       gatt_db_attribute_notify(bcast_src->attr,
+                                       (void *)notify_data,
+                                       notify_data_len,
+                                       bt_bass_get_att(bcast_src->bass));
+
+       free(notify_data);
+}
+
+static struct bt_bass *bass_get_session(struct bt_att *att, struct gatt_db *db,
+               const bdaddr_t *adapter_bdaddr)
+{
+       const struct queue_entry *entry;
+       struct bt_bass *bass;
+
+       for (entry = queue_get_entries(sessions); entry; entry = entry->next) {
+               struct bt_bass *bass = entry->data;
+
+               if (att == bt_bass_get_att(bass))
+                       return bass;
+       }
+
+       bass = bt_bass_new(db, NULL, adapter_bdaddr);
+       bass->att = att;
+
+       bt_bass_attach(bass, NULL);
+
+       return bass;
+}
+
+static void bass_handle_add_src_op(struct bt_bass *bass,
+                                       struct gatt_db_attribute *attrib,
+                                       uint8_t opcode,
+                                       unsigned int id,
+                                       struct iovec *iov,
+                                       struct bt_att *att)
+{
+       struct bt_bcast_src *bcast_src, *src;
+       uint8_t src_id = 0;
+       struct gatt_db_attribute *attr;
+       uint8_t *pa_sync;
+       GIOChannel *io;
+       GError *err = NULL;
+       struct bt_iso_qos iso_qos = default_qos;
+       uint8_t num_bis = 0;
+       uint8_t bis[ISO_MAX_NUM_BIS];
+       uint8_t *notify_data;
+       size_t notify_data_len;
+
+       if (opcode == BT_ATT_OP_WRITE_REQ)
+               gatt_db_attribute_write_result(attrib, id, 0x00);
+
+       /* Allocate a new broadcast source */
+       bcast_src = malloc(sizeof(*bcast_src));
+       if (!bcast_src) {
+               DBG(bass, "Unable to allocate broadcast source");
+               return;
+       }
+
+       queue_push_tail(bass->ldb->bcast_srcs, bcast_src);
+
+       memset(bcast_src, 0, sizeof(*bcast_src));
+       memset(bis, 0, ISO_MAX_NUM_BIS);
+
+       bcast_src->bass = bass;
+
+       /* Map the source to a Broadcast Receive State characteristic */
+       for (int i = 0; i < NUM_BCAST_RECV_STATES; i++) {
+               src = queue_find(bass->ldb->bcast_srcs,
+                               bass_src_attr_match,
+                               bass->ldb->bcast_recv_states[i]->attr);
+               if (!src) {
+                       /* Found and empty characteristic */
+                       bcast_src->attr =
+                               bass->ldb->bcast_recv_states[i]->attr;
+                       break;
+               }
+       }
+
+       if (!bcast_src->attr) {
+               /* If no empty characteristic has been found,
+                * overwrite an existing one
+                */
+               attr = bass->ldb->bcast_recv_states[0]->attr;
+
+               src = queue_find(bass->ldb->bcast_srcs,
+                                       bass_src_attr_match,
+                                       attr);
+
+               queue_remove(bass->ldb->bcast_srcs, src);
+               bass_bcast_src_free(src);
+               bcast_src->attr = attr;
+       }
+
+       /* Allocate source id */
+       while (true) {
+               src = queue_find(bass->ldb->bcast_srcs,
+                               bass_src_id_match,
+                               &src_id);
+               if (!src)
+                       break;
+
+               if (src_id == 0xFF) {
+                       DBG(bass, "Unable to allocate broadcast source id");
+                       return;
+               }
+
+               src_id++;
+       }
+
+       bcast_src->id = src_id;
+
+       /* Populate broadcast source fields from command parameters */
+       if (*(uint8_t *)util_iov_pull_mem(iov, sizeof(bcast_src->addr_type)))
+               bcast_src->addr_type = BDADDR_LE_RANDOM;
+       else
+               bcast_src->addr_type = BDADDR_LE_PUBLIC;
+
+       bacpy(&bcast_src->addr, (bdaddr_t *)util_iov_pull_mem(iov,
+                                               sizeof(bdaddr_t)));
+       bcast_src->sid = *(uint8_t *)util_iov_pull_mem(iov,
+                                               sizeof(bcast_src->sid));
+       util_iov_pull_le24(iov, &bcast_src->bid);
+
+       pa_sync = util_iov_pull_mem(iov, sizeof(*pa_sync));
+       bcast_src->sync_state = BT_BASS_NOT_SYNCHRONIZED_TO_PA;
+
+       /* TODO: Set the encryption field based on observed BIGInfo reports,
+        * after PA sync establishment
+        */
+       bcast_src->enc = BT_BASS_BIG_ENC_STATE_NO_ENC;
+
+       /* TODO: Use the pa_interval field for the sync transfer procedure */
+       util_iov_pull_mem(iov, sizeof(uint16_t));
+
+       bcast_src->num_subgroups = *(uint8_t *)util_iov_pull_mem(iov,
+                                       sizeof(bcast_src->num_subgroups));
+
+       if (!bcast_src->num_subgroups)
+               return;
+
+       bcast_src->subgroup_data = malloc(bcast_src->num_subgroups *
+                                       sizeof(*bcast_src->subgroup_data));
+       if (!bcast_src->subgroup_data) {
+               DBG(bass, "Unable to allocate subgroup data");
+               goto err;
+       }
+
+       memset(bcast_src->subgroup_data, 0, sizeof(*bcast_src->subgroup_data));
+
+       for (int i = 0; i < bcast_src->num_subgroups; i++) {
+               struct bt_bass_subgroup_data *data =
+                               &bcast_src->subgroup_data[i];
+
+               util_iov_pull_le32(iov, &data->pending_bis_sync);
+
+               if (data->pending_bis_sync != BIS_SYNC_NO_PREF)
+                       /* Iterate through the bis sync bitmask written
+                        * by the client and store the bis indexes that
+                        * the BASS server will try to synchronize to
+                        */
+                       for (int bis_idx = 0; bis_idx < 31; bis_idx++) {
+                               if (data->pending_bis_sync & (1 << bis_idx)) {
+                                       bis[num_bis] = bis_idx + 1;
+                                       num_bis++;
+                               }
+                       }
+
+               data->meta_len = *(uint8_t *)util_iov_pull_mem(iov,
+                                               sizeof(data->meta_len));
+               if (!data->meta_len)
+                       continue;
+
+               data->meta = malloc(data->meta_len);
+               if (!data->meta)
+                       goto err;
+
+               memcpy(data->meta, (uint8_t *)util_iov_pull_mem(iov,
+                                       data->meta_len), data->meta_len);
+       }
+
+       if (pa_sync != PA_SYNC_NO_SYNC && num_bis > 0) {
+               /* If requested by client, try to synchronize to the source */
+               io = bt_io_listen(connect_cb, NULL, bcast_src, NULL, &err,
+                                       BT_IO_OPT_SOURCE_BDADDR,
+                                       &bass->ldb->adapter_bdaddr,
+                                       BT_IO_OPT_DEST_BDADDR,
+                                       &bcast_src->addr,
+                                       BT_IO_OPT_DEST_TYPE,
+                                       bcast_src->addr_type,
+                                       BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+                                       BT_IO_OPT_QOS, &iso_qos,
+                                       BT_IO_OPT_ISO_BC_SID, bcast_src->sid,
+                                       BT_IO_OPT_ISO_BC_NUM_BIS, num_bis,
+                                       BT_IO_OPT_ISO_BC_BIS, bis,
+                                       BT_IO_OPT_INVALID);
+
+               if (!io) {
+                       DBG(bass, "%s", err->message);
+                       g_error_free(err);
+                       goto err;
+               }
+
+               bcast_src->listen_io = io;
+               g_io_channel_ref(bcast_src->listen_io);
+
+               if (!bcast_src->bises)
+                       bcast_src->bises = queue_new();
+       } else {
+               for (int i = 0; i < bcast_src->num_subgroups; i++)
+                       bcast_src->subgroup_data[i].bis_sync =
+                               bcast_src->subgroup_data[i].pending_bis_sync;
+
+               notify_data = bass_build_notif_from_bcast_src(bcast_src,
+                                                       &notify_data_len);
+
+               gatt_db_attribute_notify(bcast_src->attr,
+                               (void *)notify_data,
+                               notify_data_len,
+                               bt_bass_get_att(bcast_src->bass));
+
+               free(notify_data);
+       }
+
+       return;
+
+err:
+       if (bcast_src->subgroup_data) {
+               for (int i = 0; i < bcast_src->num_subgroups; i++)
+                       free(bcast_src->subgroup_data[i].meta);
+
+               free(bcast_src->subgroup_data);
+       }
+
+       free(bcast_src);
+}
+
+
 #define BASS_OP(_str, _op, _size, _func) \
        { \
                .str = _str, \
@@ -551,7 +919,7 @@ struct bass_op_handler {
        const char      *str;
        uint8_t         op;
        size_t          size;
-       void            (*func)(struct bt_bass_db *bdb,
+       void            (*func)(struct bt_bass *bass,
                                struct gatt_db_attribute *attrib,
                                uint8_t opcode,
                                unsigned int id,
@@ -564,6 +932,8 @@ struct bass_op_handler {
                0, bass_handle_remote_scan_started_op),
        BASS_OP("Remove Source", BT_BASS_REMOVE_SRC,
                0, bass_handle_remove_src_op),
+       BASS_OP("Add Source", BT_BASS_ADD_SRC,
+               0, bass_handle_add_src_op),
        {}
 };
 
@@ -576,6 +946,8 @@ static void bass_bcast_audio_scan_cp_write(struct gatt_db_attribute *attrib,
        struct bt_bass_db *bdb = user_data;
        struct bt_bass_bcast_audio_scan_cp_hdr *hdr;
        struct bass_op_handler *handler;
+       struct bt_bass *bass = bass_get_session(att, bdb->db,
+                                               &bdb->adapter_bdaddr);
        struct iovec iov = {
                .iov_base = (void *)value,
                .iov_len = len,
@@ -596,7 +968,7 @@ static void bass_bcast_audio_scan_cp_write(struct gatt_db_attribute *attrib,
        /* Call the appropriate opcode handler */
        for (handler = bass_handlers; handler && handler->str; handler++) {
                if (handler->op == hdr->op) {
-                       handler->func(bdb, attrib, opcode, id, &iov, att);
+                       handler->func(bass, attrib, opcode, id, &iov, att);
                        return;
                }
        }
@@ -625,8 +997,10 @@ static void bass_bcast_recv_state_read(struct gatt_db_attribute *attrib,
        uint8_t *rsp;
        size_t rsp_len;
        struct bt_bcast_src *bcast_src;
+       struct bt_bass *bass = bass_get_session(att, bdb->db,
+                                               &bdb->adapter_bdaddr);
 
-       bcast_src = queue_find(bdb->bcast_srcs,
+       bcast_src = queue_find(bass->ldb->bcast_srcs,
                                        bass_src_match_attrib,
                                        attrib);
 
@@ -712,6 +1086,14 @@ static void bass_bcast_src_free(void *data)
                free(bcast_src->subgroup_data[i].meta);
 
        free(bcast_src->subgroup_data);
+
+       if (bcast_src->listen_io) {
+               g_io_channel_shutdown(bcast_src->listen_io, TRUE, NULL);
+               g_io_channel_unref(bcast_src->listen_io);
+       }
+
+       queue_destroy(bcast_src->bises, bass_bis_unref);
+
        free(bcast_src);
 }
 
@@ -900,6 +1282,14 @@ static void foreach_bass_service(struct gatt_db_attribute *attr,
        gatt_db_service_foreach_char(attr, foreach_bass_char, bass);
 }
 
+static void bass_attached(void *data, void *user_data)
+{
+       struct bt_bass_cb *cb = data;
+       struct bt_bass *bass = user_data;
+
+       cb->attached(bass, cb->user_data);
+}
+
 bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client)
 {
        bt_uuid_t uuid;
@@ -909,6 +1299,8 @@ bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client)
 
        queue_push_tail(sessions, bass);
 
+       queue_foreach(bass_cbs, bass_attached, bass);
+
        if (!client)
                return true;
 
@@ -990,7 +1382,8 @@ bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data)
        return true;
 }
 
-static struct bt_bass_db *bass_db_new(struct gatt_db *db)
+static struct bt_bass_db *bass_db_new(struct gatt_db *db,
+                               const bdaddr_t *adapter_bdaddr)
 {
        struct bt_bass_db *bdb;
 
@@ -999,6 +1392,7 @@ static struct bt_bass_db *bass_db_new(struct gatt_db *db)
 
        bdb = new0(struct bt_bass_db, 1);
        bdb->db = gatt_db_ref(db);
+       bacpy(&bdb->adapter_bdaddr, adapter_bdaddr);
        bdb->bcast_srcs = queue_new();
 
        if (!bass_db)
@@ -1019,7 +1413,8 @@ static bool bass_db_match(const void *data, const void *match_data)
        return (bdb->db == db);
 }
 
-static struct bt_bass_db *bass_get_db(struct gatt_db *db)
+static struct bt_bass_db *bass_get_db(struct gatt_db *db,
+                               const bdaddr_t *adapter_bdaddr)
 {
        struct bt_bass_db *bdb;
 
@@ -1027,7 +1422,7 @@ static struct bt_bass_db *bass_get_db(struct gatt_db *db)
        if (bdb)
                return bdb;
 
-       return bass_db_new(db);
+       return bass_db_new(db, adapter_bdaddr);
 }
 
 static struct bt_bass *bt_bass_ref(struct bt_bass *bass)
@@ -1040,7 +1435,8 @@ static struct bt_bass *bt_bass_ref(struct bt_bass *bass)
        return bass;
 }
 
-struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb)
+struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb,
+                               const bdaddr_t *adapter_bdaddr)
 {
        struct bt_bass *bass;
        struct bt_bass_db *db;
@@ -1048,7 +1444,7 @@ struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb)
        if (!ldb)
                return NULL;
 
-       db = bass_get_db(ldb);
+       db = bass_get_db(ldb, adapter_bdaddr);
        if (!db)
                return NULL;
 
@@ -1140,3 +1536,8 @@ bool bt_bass_unregister(unsigned int id)
 
        return true;
 }
+
+void bt_bass_add_db(struct gatt_db *db, const bdaddr_t *adapter_bdaddr)
+{
+       bass_db_new(db, adapter_bdaddr);
+}
index d3474f7cfa7d0fa8879091c34fcfb3607fafb1a9..fb4b72d7d82b626e8ab53f30e30f36657c943476 100644 (file)
@@ -56,6 +56,8 @@ struct bt_bcast_src {
        uint8_t bad_code[BT_BASS_BCAST_CODE_SIZE];
        uint8_t num_subgroups;
        struct bt_bass_subgroup_data *subgroup_data;
+       GIOChannel *listen_io;
+       struct queue *bises;
 };
 
 /* Broadcast Audio Scan Control Point
@@ -71,6 +73,14 @@ struct bt_bass_bcast_audio_scan_cp_hdr {
 
 #define BT_BASS_ADD_SRC                                        0x02
 
+/* PA_Sync values */
+#define PA_SYNC_NO_SYNC                                        0x00
+#define PA_SYNC_PAST                                   0x01
+#define PA_SYNC_NO_PAST                                        0x02
+
+/* BIS_Sync no preference bitmask */
+#define BIS_SYNC_NO_PREF                               0xFFFFFFFF
+
 struct bt_bass_add_src_params {
        uint8_t addr_type;
        bdaddr_t addr;
@@ -115,8 +125,10 @@ unsigned int bt_bass_register(bt_bass_func_t attached, bt_bass_func_t detached,
 bool bt_bass_unregister(unsigned int id);
 bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func,
                        void *user_data, bt_bass_destroy_func_t destroy);
-struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb);
+struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb,
+                       const bdaddr_t *adapter_bdaddr);
 bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data);
 void bt_bass_unref(struct bt_bass *bass);
 bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client);
 void bt_bass_detach(struct bt_bass *bass);
+void bt_bass_add_db(struct gatt_db *db, const bdaddr_t *adapter_bdaddr);
index 8937c9478779dd126af2bfc12ab712b80c4f99d9..2ab61f760fb8d5edd04c64fed732c82801e3e374 100644 (file)
@@ -309,7 +309,7 @@ static void test_server(const void *user_data)
        gatt_db_ccc_register(data->db, gatt_ccc_read_cb, NULL,
                                        NULL, data);
 
-       data->bass = bt_bass_new(data->db, NULL);
+       data->bass = bt_bass_new(data->db, NULL, BDADDR_ANY);
        g_assert(data->bass);
 
        data->server = bt_gatt_server_new(data->db, att, 64, 0);