diff mbox series

[BlueZ,v3,3/4] This adds the initial code for BAP broadcast source

Message ID 20230530141339.100733-4-silviu.barbulescu@nxp.com
State New
Headers show
Series Add initial support for BAP broadcast source | expand

Commit Message

Silviu Florian Barbulescu May 30, 2023, 2:13 p.m. UTC
This adds initial support for BAP broadcast source.

---
 src/shared/bap.c | 282 +++++++++++++++++++++++++++++++++++++++++------
 src/shared/bap.h |  38 +++++--
 2 files changed, 274 insertions(+), 46 deletions(-)
diff mbox series

Patch

diff --git a/src/shared/bap.c b/src/shared/bap.c
index dd9eb797a..26f41be76 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -121,6 +121,8 @@  struct bt_bap_db {
 	struct bt_ascs *ascs;
 	struct queue *sinks;
 	struct queue *sources;
+	struct queue *broadcast_sources;
+	struct queue *broadcast_sinks;
 };
 
 struct bt_bap_req {
@@ -623,6 +625,18 @@  static struct bt_bap_endpoint *bap_endpoint_new(struct bt_bap_db *bdb,
 	return ep;
 }
 
+static struct bt_bap_endpoint *bap_endpoint_new_broacast(struct bt_bap_db *bdb)
+{
+	struct bt_bap_endpoint *ep;
+
+	ep = new0(struct bt_bap_endpoint, 1);
+	ep->bdb = bdb;
+	ep->attr = NULL;
+	ep->dir = BT_BAP_BCAST_SOURCE;
+
+	return ep;
+}
+
 static struct bt_bap_endpoint *bap_get_endpoint(struct queue *endpoints,
 						struct bt_bap_db *db,
 						struct gatt_db_attribute *attr)
@@ -645,6 +659,30 @@  static struct bt_bap_endpoint *bap_get_endpoint(struct queue *endpoints,
 	return ep;
 }
 
+static struct bt_bap_endpoint *bap_get_endpoint_bcast(struct queue *endpoints,
+						struct bt_bap_db *db)
+{
+	struct bt_bap_endpoint *ep;
+
+	if (!db)
+		return NULL;
+	/*
+	 * We have support for only one stream so we will have
+	 * only one endpoint.
+	 * TO DO add support for more then one stream
+	 */
+	if (queue_length(endpoints) > 0)
+		return queue_peek_head(endpoints);
+
+	ep = bap_endpoint_new_broacast(db);
+	if (!ep)
+		return NULL;
+
+	queue_push_tail(endpoints, ep);
+
+	return ep;
+}
+
 static bool bap_endpoint_match_id(const void *data, const void *match_data)
 {
 	const struct bt_bap_endpoint *ep = data;
@@ -1261,6 +1299,37 @@  static void bap_stream_state_changed(struct bt_bap_stream *stream)
 	bt_bap_unref(bap);
 }
 
+static void stream_set_state_broadcast(struct bt_bap_stream *stream,
+					uint8_t state)
+{
+	struct bt_bap_endpoint *ep = stream->ep;
+	struct bt_bap *bap = stream->bap;
+	const struct queue_entry *entry;
+
+	ep->old_state = ep->state;
+	ep->state = state;
+
+	bt_bap_ref(bap);
+
+	for (entry = queue_get_entries(bap->state_cbs); entry;
+							entry = entry->next) {
+		struct bt_bap_state *state = entry->data;
+
+		if (state->func)
+			state->func(stream, stream->ep->old_state,
+					stream->ep->state, state->data);
+	}
+
+	/* Post notification updates */
+	switch (stream->ep->state) {
+	case BT_ASCS_ASE_STATE_IDLE:
+		bap_stream_detach(stream);
+		break;
+	}
+
+	bt_bap_unref(bap);
+}
+
 static void stream_set_state(struct bt_bap_stream *stream, uint8_t state)
 {
 	struct bt_bap_endpoint *ep = stream->ep;
@@ -1397,6 +1466,11 @@  static void ep_config_cb(struct bt_bap_stream *stream, int err)
 	if (err)
 		return;
 
+	if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_BROADCAST) {
+		stream_set_state_broadcast(stream, BT_BAP_STREAM_STATE_CONFIG);
+		return;
+	}
+
 	stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG);
 }
 
@@ -2222,6 +2296,8 @@  static struct bt_bap_db *bap_db_new(struct gatt_db *db)
 	bdb->db = gatt_db_ref(db);
 	bdb->sinks = queue_new();
 	bdb->sources = queue_new();
+	bdb->broadcast_sources = queue_new();
+	bdb->broadcast_sinks = queue_new();
 
 	if (!bap_db)
 		bap_db = queue_new();
@@ -2397,6 +2473,16 @@  static void bap_add_source(struct bt_bap_pac *pac)
 				iov.iov_len, NULL);
 }
 
+static void bap_add_broadcast_source(struct bt_bap_pac *pac)
+{
+	queue_push_tail(pac->bdb->broadcast_sources, pac);
+}
+
+static void bap_add_broadcast_sink(struct bt_bap_pac *pac)
+{
+	queue_push_tail(pac->bdb->broadcast_sinks, pac);
+}
+
 static void notify_pac_added(void *data, void *user_data)
 {
 	struct bt_bap_pac_changed *changed = data;
@@ -2413,6 +2499,54 @@  static void notify_session_pac_added(void *data, void *user_data)
 	queue_foreach(bap->pac_cbs, notify_pac_added, user_data);
 }
 
+struct bt_bap_pac *bt_bap_add_vendor_pac_bcast(struct gatt_db *db,
+					const char *name, uint8_t type,
+					uint8_t id, uint16_t cid, uint16_t vid,
+					struct bt_bap_pac_qos *qos,
+					struct iovec *data,
+					struct iovec *metadata,
+					struct bt_bap_pac_ops *pac_ops,
+					void *user_data)
+{
+	struct bt_bap_db *bdb;
+	struct bt_bap_pac *pac, *pac_brodcast_sink;
+	struct bt_bap_codec codec;
+
+	if (!db)
+		return NULL;
+
+	bdb = bap_get_db(db);
+	if (!bdb)
+		return NULL;
+
+	if ((id != 0xff) && ((cid != 0U)  || (vid != 0U)))
+		return NULL;
+
+	codec.id = id;
+	codec.cid = cid;
+	codec.vid = vid;
+
+	pac = bap_pac_new(bdb, name, type, &codec, qos, data, metadata);
+
+	switch (type) {
+	case BT_BAP_BCAST_SOURCE:
+		// For broadcast, add local pac and remote pac.
+		bap_add_broadcast_source(pac);
+		pac_brodcast_sink = bap_pac_new(bdb, name, type, &codec, qos,
+					data, metadata);
+		bap_add_broadcast_sink(pac_brodcast_sink);
+		break;
+	default:
+		bap_pac_free(pac);
+		return NULL;
+	}
+
+	bt_bap_pac_set_ops(pac, pac_ops, user_data);
+	queue_foreach(sessions, notify_session_pac_added, pac);
+
+	return pac;
+}
+
 struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db,
 					const char *name, uint8_t type,
 					uint8_t id, uint16_t cid, uint16_t vid,
@@ -2489,6 +2623,21 @@  uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac)
 	}
 }
 
+uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream)
+{
+	if (!stream)
+		return BT_BAP_STREAM_TYPE_UNKNOWN;
+
+	if ((bt_bap_pac_get_type(stream->lpac) == BT_BAP_SINK) ||
+		(bt_bap_pac_get_type(stream->lpac) == BT_BAP_SOURCE))
+		return BT_BAP_STREAM_TYPE_UNICAST;
+	else if ((bt_bap_pac_get_type(stream->lpac) == BT_BAP_BCAST_SOURCE) ||
+		(bt_bap_pac_get_type(stream->lpac) == BT_BAP_BCAST_SINK))
+		return BT_BAP_STREAM_TYPE_BROADCAST;
+	else
+		return BT_BAP_STREAM_TYPE_UNKNOWN;
+}
+
 static void notify_pac_removed(void *data, void *user_data)
 {
 	struct bt_bap_pac_changed *changed = data;
@@ -2547,6 +2696,9 @@  bool bt_bap_remove_pac(struct bt_bap_pac *pac)
 	if (queue_remove_if(pac->bdb->sources, NULL, pac))
 		goto found;
 
+	if (queue_remove_if(pac->bdb->broadcast_sources, NULL, pac))
+		goto found;
+
 	return false;
 
 found:
@@ -3879,6 +4031,25 @@  clone:
 	return true;
 }
 
+bool bt_bap_attach_broadcast(struct bt_bap *bap)
+{
+	struct bt_bap_endpoint *ep;
+
+	if (queue_find(sessions, NULL, bap))
+		return true;
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, bap);
+
+	ep = bap_get_endpoint_bcast(bap->remote_eps, bap->ldb);
+	if (ep)
+		ep->bap = bap;
+
+	return true;
+}
+
 static void stream_foreach_detach(void *data, void *user_data)
 {
 	struct bt_bap_stream *stream = data;
@@ -4083,7 +4254,11 @@  void bt_bap_foreach_pac(struct bt_bap *bap, uint8_t type,
 							func, user_data);
 	case BT_BAP_SOURCE:
 		return bap_foreach_pac(bap->ldb->sinks, bap->rdb->sources,
-							func, user_data);
+							   func, user_data);
+	case BT_BAP_BCAST_SOURCE:
+		return bap_foreach_pac(bap->ldb->broadcast_sources,
+					bap->ldb->broadcast_sinks,
+					func, user_data);
 	}
 }
 
@@ -4196,42 +4371,51 @@  unsigned int bt_bap_stream_config(struct bt_bap_stream *stream,
 	if (!bap_stream_valid(stream))
 		return 0;
 
-	if (!stream->client) {
-		stream_config(stream, data, NULL);
-		return 0;
-	}
+	if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_UNICAST) {
+		if (!stream->client) {
+			stream_config(stream, data, NULL);
+			return 0;
+		}
 
-	memset(&config, 0, sizeof(config));
+		memset(&config, 0, sizeof(config));
 
-	config.ase = stream->ep->id;
-	config.latency = qos->ucast.target_latency;
-	config.phy = qos->ucast.io_qos.phy;
-	config.codec = stream->rpac->codec;
+		config.ase = stream->ep->id;
+		config.latency = qos->ucast.target_latency;
+		config.phy = qos->ucast.io_qos.phy;
+		config.codec = stream->rpac->codec;
 
-	iov[0].iov_base = &config;
-	iov[0].iov_len = sizeof(config);
+		iov[0].iov_base = &config;
+		iov[0].iov_len = sizeof(config);
 
-	if (data) {
-		if (!bap_print_cc(data->iov_base, data->iov_len,
-					stream->bap->debug_func,
-					stream->bap->debug_data))
-			return 0;
+		if (data) {
+			if (!bap_print_cc(data->iov_base, data->iov_len,
+						stream->bap->debug_func,
+						stream->bap->debug_data))
+				return 0;
 
-		config.cc_len = data->iov_len;
-		iov[1] = *data;
-		iovlen++;
-	}
+			config.cc_len = data->iov_len;
+			iov[1] = *data;
+			iovlen++;
+		}
 
-	req = bap_req_new(stream, BT_ASCS_CONFIG, iov, iovlen, func, user_data);
+		req = bap_req_new(stream, BT_ASCS_CONFIG, iov, iovlen,
+					func, user_data);
 
-	if (!bap_queue_req(stream->bap, req)) {
-		bap_req_free(req);
-		return 0;
-	}
+		if (!bap_queue_req(stream->bap, req)) {
+			bap_req_free(req);
+			return 0;
+		}
 
-	stream->qos = *qos;
+		stream->qos = *qos;
 
-	return req->id;
+		return req->id;
+	} else if (bt_bap_stream_get_type(stream) ==
+			BT_BAP_STREAM_TYPE_BROADCAST) {
+		stream->qos = *qos;
+		return 0;
+	} else {
+		return 0;
+	}
 }
 
 static bool match_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
@@ -4292,7 +4476,7 @@  struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap,
 		if (rpac)
 			type = rpac->type;
 		else if (lpac) {
-			switch(lpac->type) {
+			switch (lpac->type) {
 			case BT_BAP_SINK:
 				type = BT_BAP_SOURCE;
 				break;
@@ -4357,6 +4541,10 @@  bool bt_bap_stream_set_user_data(struct bt_bap_stream *stream, void *user_data)
 
 	stream->user_data = user_data;
 
+	if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_BROADCAST)
+		stream->lpac->ops->config(stream, stream->cc, &stream->qos,
+					ep_config_cb, stream->lpac->user_data);
+
 	return true;
 }
 
@@ -4466,7 +4654,7 @@  unsigned int bt_bap_stream_enable(struct bt_bap_stream *stream,
 					bt_bap_stream_func_t func,
 					void *user_data)
 {
-	int ret;
+	int ret = 0;
 
 	/* Table 3.2: ASE state machine transition
 	 * Initiating device - client Only
@@ -4474,12 +4662,19 @@  unsigned int bt_bap_stream_enable(struct bt_bap_stream *stream,
 	if (!bap_stream_valid(stream) || !stream->client)
 		return 0;
 
-	ret = bap_stream_metadata(stream, BT_ASCS_ENABLE, metadata, func,
-								user_data);
-	if (!ret || !enable_links)
-		return ret;
+	if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_UNICAST) {
+		ret = bap_stream_metadata(stream, BT_ASCS_ENABLE, metadata,
+							func, user_data);
+		if (!ret || !enable_links)
+			return ret;
 
-	queue_foreach(stream->links, bap_stream_enable_link, metadata);
+		queue_foreach(stream->links, bap_stream_enable_link, metadata);
+	} else if (bt_bap_stream_get_type(stream) ==
+				BT_BAP_STREAM_TYPE_BROADCAST) {
+		stream_set_state_broadcast(stream,
+				BT_BAP_STREAM_STATE_STREAMING);
+		return 1;
+	}
 
 	return ret;
 }
@@ -4658,6 +4853,16 @@  unsigned int bt_bap_stream_release(struct bt_bap_stream *stream,
 
 	bap = stream->bap;
 
+	/* If stream is broadcast, no BT_ASCS_RELEASE is required */
+	if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_BROADCAST) {
+		if (!bap_stream_valid(stream)) {
+			stream_set_state_broadcast(stream,
+					BT_BAP_STREAM_STATE_IDLE);
+			stream = NULL;
+		}
+		return 0;
+	}
+
 	/* If stream does not belong to a client session, clean it up now */
 	if (!bap_stream_valid(stream)) {
 		stream_set_state(stream, BT_BAP_STREAM_STATE_IDLE);
@@ -4693,8 +4898,13 @@  uint32_t bt_bap_stream_get_location(struct bt_bap_stream *stream)
 
 	if (stream->ep->dir == BT_BAP_SOURCE)
 		return pacs->source_loc_value;
-	else
+	else if (stream->ep->dir == BT_BAP_SINK)
 		return pacs->sink_loc_value;
+	else
+		/* TO DO get the location values from metadata
+		 * for brodcast source and sink
+		 */
+		return stream->bap->ldb->pacs->source_loc_value;
 }
 
 struct iovec *bt_bap_stream_get_config(struct bt_bap_stream *stream)
diff --git a/src/shared/bap.h b/src/shared/bap.h
index 0c42e730f..f1dab5f39 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -17,6 +17,12 @@ 
 
 #define BT_BAP_SINK			0x01
 #define	BT_BAP_SOURCE			0x02
+#define	BT_BAP_BCAST_SOURCE		0x03
+#define	BT_BAP_BCAST_SINK		0x04
+
+#define BT_BAP_STREAM_TYPE_UNICAST	0x01
+#define	BT_BAP_STREAM_TYPE_BROADCAST	0x02
+#define	BT_BAP_STREAM_TYPE_UNKNOWN	0x03
 
 #define BT_BAP_STREAM_STATE_IDLE	0x00
 #define BT_BAP_STREAM_STATE_CONFIG	0x01
@@ -128,6 +134,25 @@  struct bt_bap_pac_qos {
 	uint32_t ppd_max;
 };
 
+struct bt_bap_pac_ops {
+	int (*select)(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
+			struct bt_bap_pac_qos *qos,
+			bt_bap_pac_select_t cb, void *cb_data, void *user_data);
+	int (*config)(struct bt_bap_stream *stream, struct iovec *cfg,
+			struct bt_bap_qos *qos, bt_bap_pac_config_t cb,
+			void *user_data);
+	void (*clear)(struct bt_bap_stream *stream, void *user_data);
+};
+
+struct bt_bap_pac *bt_bap_add_vendor_pac_bcast(struct gatt_db *db,
+					const char *name, uint8_t type,
+					uint8_t id, uint16_t cid, uint16_t vid,
+					struct bt_bap_pac_qos *qos,
+					struct iovec *data,
+					struct iovec *metadata,
+					struct bt_bap_pac_ops *pac_ops,
+					void *user_data);
+
 struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db,
 					const char *name, uint8_t type,
 					uint8_t id, uint16_t cid, uint16_t vid,
@@ -141,16 +166,6 @@  struct bt_bap_pac *bt_bap_add_pac(struct gatt_db *db, const char *name,
 					struct iovec *data,
 					struct iovec *metadata);
 
-struct bt_bap_pac_ops {
-	int (*select)(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
-			struct bt_bap_pac_qos *qos,
-			bt_bap_pac_select_t cb, void *cb_data, void *user_data);
-	int (*config)(struct bt_bap_stream *stream, struct iovec *cfg,
-			struct bt_bap_qos *qos, bt_bap_pac_config_t cb,
-			void *user_data);
-	void (*clear)(struct bt_bap_stream *stream, void *user_data);
-};
-
 bool bt_bap_pac_set_ops(struct bt_bap_pac *pac, struct bt_bap_pac_ops *ops,
 					void *user_data);
 
@@ -160,6 +175,8 @@  uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac);
 
 uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac);
 
+uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream);
+
 struct bt_bap_stream *bt_bap_pac_get_stream(struct bt_bap_pac *pac);
 
 /* Session related function */
@@ -179,6 +196,7 @@  struct bt_bap *bt_bap_ref(struct bt_bap *bap);
 void bt_bap_unref(struct bt_bap *bap);
 
 bool bt_bap_attach(struct bt_bap *bap, struct bt_gatt_client *client);
+bool bt_bap_attach_broadcast(struct bt_bap *bap);
 void bt_bap_detach(struct bt_bap *bap);
 
 bool bt_bap_set_debug(struct bt_bap *bap, bt_bap_debug_func_t cb,