@@ -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)
@@ -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,