diff mbox series

[BlueZ,v2,2/2] shared/bass: Introduce Add Source opcode handler

Message ID 20230628150705.248285-3-iulia.tanasescu@nxp.com (mailing list archive)
State Superseded
Headers show
Series shared/bass: Introduce Add Source opcode handler | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch success CheckPatch PASS
tedd_an/GitLint success Gitlint PASS
tedd_an/IncrementalBuild fail [BlueZ,v2,2/2] shared/bass: Introduce Add Source opcode handler src/shared/bass.c: In function ‘bass_handle_add_src_op’: src/shared/bass.c:835:21: error: ‘bis_sync_bit’ undeclared (first use in this function) 835 | bis[num_bis] = bis_sync_bit + 1; | ^~~~~~~~~~~~ src/shared/bass.c:835:21: note: each undeclared identifier is reported only once for each function it appears in src/shared/bass.c:855:10: error: ‘bc_addr’ undeclared (first use in this function); did you mean ‘in_addr’? 855 | bacpy(&bc_addr.bc_bdaddr, &bcast_src->addr); | ^~~~~~~ | in_addr make[1]: *** [Makefile:8399: src/shared/libshared_mainloop_la-bass.lo] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:4528: all] Error 2

Commit Message

Iulia Tanasescu June 28, 2023, 3:07 p.m. UTC
This implements the Control Point handler for the Add Source operation.
---
 Makefile.am           |   2 +-
 profiles/audio/bass.c |  26 ++-
 src/shared/bass.c     | 430 ++++++++++++++++++++++++++++++++++++++++--
 src/shared/bass.h     |  14 +-
 unit/test-bass.c      |   2 +-
 5 files changed, 456 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index 2bd547564..98eb185fc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -580,7 +580,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)
 
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index fae7fe004..7952105c5 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -37,10 +37,10 @@ 
 #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"
@@ -197,7 +197,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);
@@ -268,6 +269,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,
@@ -276,6 +296,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,
 };
 
diff --git a/src/shared/bass.c b/src/shared/bass.c
index 423ab5bf7..3557dda0f 100644
--- a/src/shared/bass.c
+++ b/src/shared/bass.c
@@ -14,9 +14,13 @@ 
 #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,341 @@  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_sync_bit + 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 */
+		bacpy(&bc_addr.bc_bdaddr, &bcast_src->addr);
+		bc_addr.bc_bdaddr_type = bcast_src->addr_type;
+
+		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 +922,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 +935,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 +949,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 +971,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 +1000,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 +1089,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 +1285,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 +1302,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 +1385,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 +1395,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 +1416,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 +1425,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 +1438,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 +1447,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 +1539,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);
+}
diff --git a/src/shared/bass.h b/src/shared/bass.h
index d3474f7cf..fb4b72d7d 100644
--- a/src/shared/bass.h
+++ b/src/shared/bass.h
@@ -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);
diff --git a/unit/test-bass.c b/unit/test-bass.c
index 8937c9478..2ab61f760 100644
--- a/unit/test-bass.c
+++ b/unit/test-bass.c
@@ -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);