Bluetooth: BAP: Remove ISO limitation on BASE parsing
BASE is now parsed on-the-fly on sink sync, removing unnecessary restriction in intermediate parsed storage and without requiring an excessive amount of memory. Signed-off-by: Lars Knudsen <LAKD@demant.com>
This commit is contained in:
parent
d619fd607c
commit
bc4a2f37f3
@ -47,6 +47,9 @@ extern "C" {
|
||||
#define BT_BAP_BASS_MAX_SUBGROUPS 0
|
||||
#endif /* CONFIG_BT_BAP_BASS_MAX_SUBGROUPS*/
|
||||
|
||||
/** Maximum size of BASE excluding service data header */
|
||||
#define BT_BASE_MAX_SIZE (UINT8_MAX - 1 /* type */ - BT_UUID_SIZE_16)
|
||||
|
||||
/** An invalid Broadcast ID */
|
||||
#define BT_BAP_INVALID_BROADCAST_ID 0xFFFFFFFFU
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ LOG_MODULE_REGISTER(bt_bap_base, CONFIG_BT_BAP_BASE_LOG_LEVEL);
|
||||
/* The BASE and the following defines are defined by BAP v1.0.1, section 3.7.2.2 Basic Audio
|
||||
* Announcements
|
||||
*/
|
||||
#define BASE_MAX_SIZE (UINT8_MAX - 1 /* type */ - BT_UUID_SIZE_16)
|
||||
#define BASE_CODEC_ID_SIZE (1 /* id */ + 2 /* cid */ + 2 /* vid */)
|
||||
#define BASE_PD_SIZE 3
|
||||
#define BASE_SUBGROUP_COUNT_SIZE 1
|
||||
@ -39,14 +38,14 @@ LOG_MODULE_REGISTER(bt_bap_base, CONFIG_BT_BAP_BASE_LOG_LEVEL);
|
||||
#define BASE_META_LEN_SIZE 1
|
||||
#define BASE_BIS_INDEX_SIZE 1
|
||||
#define BASE_BIS_CC_LEN_SIZE 1
|
||||
#define BASE_SUBGROUP_MAX_SIZE (BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE)
|
||||
#define BASE_SUBGROUP_MAX_SIZE (BT_BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE)
|
||||
#define BASE_SUBGROUP_MIN_SIZE \
|
||||
(BASE_NUM_BIS_SIZE + BASE_CODEC_ID_SIZE + BASE_CC_LEN_SIZE + BASE_META_LEN_SIZE + \
|
||||
BASE_BIS_INDEX_SIZE + BASE_BIS_CC_LEN_SIZE)
|
||||
#define BASE_MIN_SIZE \
|
||||
(BT_UUID_SIZE_16 + BASE_PD_SIZE + BASE_SUBGROUP_COUNT_SIZE + BASE_SUBGROUP_MIN_SIZE)
|
||||
#define BASE_SUBGROUP_MAX_COUNT \
|
||||
((BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE) / BASE_SUBGROUP_MIN_SIZE)
|
||||
((BT_BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE) / BASE_SUBGROUP_MIN_SIZE)
|
||||
|
||||
static uint32_t base_pull_pd(struct net_buf_simple *net_buf)
|
||||
{
|
||||
@ -233,7 +232,7 @@ int bt_bap_base_get_size(const struct bt_bap_base *base)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE);
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)base, BT_BASE_MAX_SIZE);
|
||||
base_pull_pd(&net_buf);
|
||||
size += BASE_PD_SIZE;
|
||||
subgroup_count = net_buf_simple_pull_u8(&net_buf);
|
||||
@ -301,7 +300,7 @@ int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE);
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)base, BT_BASE_MAX_SIZE);
|
||||
base_pull_pd(&net_buf);
|
||||
subgroup_count = net_buf_simple_pull_u8(&net_buf);
|
||||
|
||||
@ -329,7 +328,7 @@ int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE);
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)base, BT_BASE_MAX_SIZE);
|
||||
base_pull_pd(&net_buf);
|
||||
subgroup_count = net_buf_simple_pull_u8(&net_buf);
|
||||
|
||||
|
||||
@ -554,187 +554,6 @@ static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink,
|
||||
}
|
||||
}
|
||||
|
||||
struct store_base_info_data {
|
||||
struct bt_bap_broadcast_sink_bis bis[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||
struct bt_bap_broadcast_sink_subgroup subgroups[CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT];
|
||||
struct bt_audio_codec_cfg *subgroup_codec_cfg;
|
||||
uint32_t valid_indexes_bitfield;
|
||||
uint8_t subgroup_count;
|
||||
uint8_t bis_count;
|
||||
};
|
||||
|
||||
static bool merge_bis_and_subgroup_data_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
int err;
|
||||
|
||||
err = bt_audio_codec_cfg_set_val(codec_cfg, data->type, data->data, data->data_len);
|
||||
if (err < 0) {
|
||||
LOG_DBG("Failed to set type %u with len %u in codec_cfg: %d", data->type,
|
||||
data->data_len, err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool base_subgroup_bis_index_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data)
|
||||
{
|
||||
struct bt_bap_broadcast_sink_subgroup *sink_subgroup;
|
||||
struct store_base_info_data *data = user_data;
|
||||
struct bt_bap_broadcast_sink_bis *sink_bis;
|
||||
|
||||
if (data->bis_count == ARRAY_SIZE(data->bis)) {
|
||||
/* We've parsed as many subgroups as we support */
|
||||
LOG_DBG("Could only store %u BIS", data->bis_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
sink_bis = &data->bis[data->bis_count];
|
||||
sink_subgroup = &data->subgroups[data->subgroup_count];
|
||||
|
||||
sink_bis->index = bis->index;
|
||||
sink_subgroup->bis_indexes |= BT_ISO_BIS_INDEX_BIT(bis->index);
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
|
||||
memcpy(&sink_bis->codec_cfg, data->subgroup_codec_cfg, sizeof(sink_bis->codec_cfg));
|
||||
|
||||
if (bis->data_len > 0) {
|
||||
/* Merge subgroup codec configuration with the BIS configuration
|
||||
* As per the BAP spec, if a value exist at level 2 (subgroup) and 3 (BIS), then it
|
||||
* is the value at level 3 that shall be used
|
||||
*/
|
||||
if (sink_bis->codec_cfg.id == BT_HCI_CODING_FORMAT_LC3) {
|
||||
int err;
|
||||
|
||||
memcpy(&sink_bis->codec_cfg, data->subgroup_codec_cfg,
|
||||
sizeof(sink_bis->codec_cfg));
|
||||
|
||||
err = bt_audio_data_parse(bis->data, bis->data_len,
|
||||
merge_bis_and_subgroup_data_cb,
|
||||
&sink_bis->codec_cfg);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Could not merge BIS and subgroup config in codec_cfg: %d",
|
||||
err);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* If it is not LC3, then we don't know how to merge the subgroup and BIS
|
||||
* codecs, so we just append them
|
||||
*/
|
||||
if (sink_bis->codec_cfg.data_len + bis->data_len >
|
||||
sizeof(sink_bis->codec_cfg.data)) {
|
||||
LOG_DBG("Could not store BIS and subgroup config in codec_cfg (%u "
|
||||
"> %u)",
|
||||
sink_bis->codec_cfg.data_len + bis->data_len,
|
||||
sizeof(sink_bis->codec_cfg.data));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&sink_bis->codec_cfg.data[sink_bis->codec_cfg.data_len], bis->data,
|
||||
bis->data_len);
|
||||
sink_bis->codec_cfg.data_len += bis->data_len;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
data->bis_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data)
|
||||
{
|
||||
struct bt_bap_broadcast_sink_subgroup *sink_subgroup;
|
||||
struct store_base_info_data *data = user_data;
|
||||
const struct bt_audio_codec_cap *codec_cap;
|
||||
struct bt_audio_codec_cfg codec_cfg;
|
||||
struct bt_pac_codec codec_id;
|
||||
int ret;
|
||||
|
||||
if (data->subgroup_count == ARRAY_SIZE(data->subgroups)) {
|
||||
/* We've parsed as many subgroups as we support */
|
||||
LOG_DBG("Could only store %u subgroups", data->subgroup_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
sink_subgroup = &data->subgroups[data->subgroup_count];
|
||||
|
||||
ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &codec_cfg);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not store codec_cfg: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Lookup and assign path_id based on capabilities */
|
||||
codec_id.id = codec_cfg.id;
|
||||
codec_id.cid = codec_cfg.cid;
|
||||
codec_id.vid = codec_cfg.vid;
|
||||
|
||||
codec_cap = bt_pacs_get_codec_cap(BT_AUDIO_DIR_SINK, &codec_id);
|
||||
if (codec_cap == NULL) {
|
||||
LOG_DBG("Codec with id 0x%02x cid 0x%04x and vid 0x%04x is not supported by our "
|
||||
"capabilities",
|
||||
codec_id.id, codec_id.cid, codec_id.vid);
|
||||
} else {
|
||||
codec_cfg.path_id = codec_cap->path_id;
|
||||
codec_cfg.ctlr_transcode = codec_cap->ctlr_transcode;
|
||||
|
||||
data->subgroup_codec_cfg = &codec_cfg;
|
||||
|
||||
ret = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_index_cb, data);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not parse BISes: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add BIS to bitfield of valid BIS indexes we support */
|
||||
data->valid_indexes_bitfield |= sink_subgroup->bis_indexes;
|
||||
data->subgroup_count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int store_base_info(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
||||
{
|
||||
/* data is static due to its size, which easily can exceed the stack size */
|
||||
static struct store_base_info_data data;
|
||||
uint32_t pres_delay;
|
||||
int ret;
|
||||
|
||||
ret = bt_bap_base_get_pres_delay(base);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not get presentation delay: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pres_delay = (uint32_t)ret;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &data);
|
||||
if (ret != 0) {
|
||||
LOG_DBG("Failed to parse all subgroups: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Ensure that we have not synced while parsing the BASE */
|
||||
if (sink->big == NULL) {
|
||||
sink->qos_cfg.pd = pres_delay;
|
||||
memcpy(sink->bis, data.bis, sizeof(sink->bis));
|
||||
memcpy(sink->subgroups, data.subgroups, sizeof(sink->subgroups));
|
||||
sink->subgroup_count = data.subgroup_count;
|
||||
sink->valid_indexes_bitfield = data.valid_indexes_bitfield;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool base_subgroup_bis_count_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data)
|
||||
{
|
||||
uint8_t *bis_cnt = user_data;
|
||||
@ -764,6 +583,66 @@ static int base_get_bis_count(const struct bt_bap_base *base)
|
||||
return bis_cnt;
|
||||
}
|
||||
|
||||
static bool base_decode_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data)
|
||||
{
|
||||
uint32_t *base_bis_index_bitfield = user_data;
|
||||
|
||||
*base_bis_index_bitfield |= BT_ISO_BIS_INDEX_BIT(bis->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool base_decode_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data)
|
||||
{
|
||||
struct bt_bap_broadcast_sink *sink = (struct bt_bap_broadcast_sink *)user_data;
|
||||
const struct bt_audio_codec_cap *codec_cap;
|
||||
struct bt_audio_codec_cfg codec_cfg;
|
||||
struct bt_pac_codec codec_id;
|
||||
int ret;
|
||||
|
||||
if (sink->subgroup_count == ARRAY_SIZE(sink->subgroups)) {
|
||||
/* We've parsed as many subgroups as we support */
|
||||
LOG_DBG("Could only store %u subgroups", sink->subgroup_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t *subgroup_bis_indexes = &sink->subgroups[sink->subgroup_count].bis_indexes;
|
||||
|
||||
*subgroup_bis_indexes = 0;
|
||||
|
||||
ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &codec_cfg);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not store codec_cfg: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Lookup and assign path_id based on capabilities */
|
||||
codec_id.id = codec_cfg.id;
|
||||
codec_id.cid = codec_cfg.cid;
|
||||
codec_id.vid = codec_cfg.vid;
|
||||
|
||||
codec_cap = bt_pacs_get_codec_cap(BT_AUDIO_DIR_SINK, &codec_id);
|
||||
if (codec_cap == NULL) {
|
||||
LOG_DBG("Codec with id 0x%02x cid 0x%04x and vid 0x%04x is not supported by our "
|
||||
"capabilities",
|
||||
codec_id.id, codec_id.cid, codec_id.vid);
|
||||
} else {
|
||||
ret = bt_bap_base_subgroup_foreach_bis(subgroup, base_decode_subgroup_bis_cb,
|
||||
subgroup_bis_indexes);
|
||||
|
||||
if (ret != 0) {
|
||||
LOG_DBG("Could not parse BISes: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
sink->valid_indexes_bitfield |= *subgroup_bis_indexes;
|
||||
}
|
||||
|
||||
sink->subgroup_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pa_decode_base(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_bap_broadcast_sink *sink = (struct bt_bap_broadcast_sink *)user_data;
|
||||
@ -791,37 +670,27 @@ static bool pa_decode_base(struct bt_data *data, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
/* We provide the BASE without the service data UUID */
|
||||
base_size = bt_bap_base_get_size(base);
|
||||
|
||||
/* Store newest BASE info until we are BIG synced */
|
||||
if (sink->big == NULL) {
|
||||
sink->qos_cfg.pd = bt_bap_base_get_pres_delay(base);
|
||||
|
||||
sink->subgroup_count = 0;
|
||||
sink->valid_indexes_bitfield = 0;
|
||||
bt_bap_base_foreach_subgroup(base, base_decode_subgroup_cb, sink);
|
||||
|
||||
LOG_DBG("Updating BASE for sink %p with %d subgroups\n", sink,
|
||||
bt_bap_base_get_subgroup_count(base));
|
||||
sink->subgroup_count);
|
||||
|
||||
ret = store_base_info(sink, base);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not store BASE information: %d", ret);
|
||||
|
||||
/* If it returns -ECANCELED it means that we stopped parsing ourselves due
|
||||
* to lack of memory. In this case we can still provide the BASE to the
|
||||
* application else abort
|
||||
*/
|
||||
if (ret != -ECANCELED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
memcpy(sink->base, base, base_size);
|
||||
}
|
||||
|
||||
if (atomic_test_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID)) {
|
||||
update_recv_state_base(sink, base);
|
||||
}
|
||||
|
||||
/* We provide the BASE without the service data UUID */
|
||||
base_size = bt_bap_base_get_size(base);
|
||||
if (base_size < 0) {
|
||||
LOG_DBG("BASE get size failed (%d)", base_size);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&sink_cbs, listener, _node) {
|
||||
if (listener->base_recv != NULL) {
|
||||
listener->base_recv(sink, base, (size_t)base_size);
|
||||
@ -1139,23 +1008,6 @@ static void broadcast_sink_cleanup(struct bt_bap_broadcast_sink *sink)
|
||||
(void)memset(sink, 0, sizeof(*sink)); /* also clears flags */
|
||||
}
|
||||
|
||||
static struct bt_audio_codec_cfg *codec_cfg_from_base_by_index(struct bt_bap_broadcast_sink *sink,
|
||||
uint8_t index)
|
||||
{
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(sink->bis); i++) {
|
||||
struct bt_bap_broadcast_sink_bis *bis = &sink->bis[i];
|
||||
|
||||
if (bis->index == index) {
|
||||
return &bis->codec_cfg;
|
||||
} else if (bis->index == 0) {
|
||||
/* index 0 is invalid, so we can use that as a terminator in the array */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t broadcast_id,
|
||||
struct bt_bap_broadcast_sink **out_sink)
|
||||
{
|
||||
@ -1213,15 +1065,166 @@ int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t br
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t bit_count(uint32_t bitfield)
|
||||
{
|
||||
#ifdef POPCOUNT
|
||||
return POPCOUNT(bitfield);
|
||||
#else
|
||||
uint8_t cnt = 0U;
|
||||
|
||||
while (bitfield != 0U) {
|
||||
cnt += bitfield & 1U;
|
||||
bitfield >>= 1U;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct sync_base_info_data {
|
||||
struct bt_audio_codec_cfg codec_cfgs[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||
struct bt_audio_codec_cfg *subgroup_codec_cfg;
|
||||
uint32_t sync_indexes_bitfield;
|
||||
uint8_t subgroup_count;
|
||||
uint8_t stream_count;
|
||||
};
|
||||
|
||||
static bool merge_bis_and_subgroup_data_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
int err;
|
||||
|
||||
err = bt_audio_codec_cfg_set_val(codec_cfg, data->type, data->data, data->data_len);
|
||||
if (err < 0) {
|
||||
LOG_DBG("Failed to set type %u with len %u in codec_cfg: %d", data->type,
|
||||
data->data_len, err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sync_base_subgroup_bis_index_cb(const struct bt_bap_base_subgroup_bis *bis,
|
||||
void *user_data)
|
||||
{
|
||||
struct sync_base_info_data *data = user_data;
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
|
||||
/* Only process selected BISes */
|
||||
if ((data->sync_indexes_bitfield & BT_ISO_BIS_INDEX_BIT(bis->index)) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
|
||||
codec_cfg = &data->codec_cfgs[data->stream_count];
|
||||
|
||||
memcpy(codec_cfg, data->subgroup_codec_cfg, sizeof(struct bt_audio_codec_cfg));
|
||||
|
||||
if (bis->data_len > 0) {
|
||||
/* Merge subgroup codec configuration with the BIS configuration
|
||||
* As per the BAP spec, if a value exist at level 2 (subgroup) and 3 (BIS), then it
|
||||
* is the value at level 3 that shall be used
|
||||
*/
|
||||
if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
|
||||
int err;
|
||||
|
||||
memcpy(codec_cfg, data->subgroup_codec_cfg,
|
||||
sizeof(struct bt_audio_codec_cfg));
|
||||
|
||||
err = bt_audio_data_parse(bis->data, bis->data_len,
|
||||
merge_bis_and_subgroup_data_cb, codec_cfg);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Could not merge BIS and subgroup config in codec_cfg: %d",
|
||||
err);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* If it is not LC3, then we don't know how to merge the subgroup and BIS
|
||||
* codecs, so we just append them
|
||||
*/
|
||||
if (codec_cfg->data_len + bis->data_len > sizeof(codec_cfg->data)) {
|
||||
LOG_DBG("Could not store BIS and subgroup config in codec_cfg (%u "
|
||||
"> %u)",
|
||||
codec_cfg->data_len + bis->data_len,
|
||||
sizeof(codec_cfg->data));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&codec_cfg->data[codec_cfg->data_len], bis->data, bis->data_len);
|
||||
codec_cfg->data_len += bis->data_len;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
data->stream_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sync_base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data)
|
||||
{
|
||||
struct sync_base_info_data *data = user_data;
|
||||
const struct bt_audio_codec_cap *codec_cap;
|
||||
struct bt_audio_codec_cfg codec_cfg;
|
||||
struct bt_pac_codec codec_id;
|
||||
int ret;
|
||||
|
||||
if (data->subgroup_count == CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT) {
|
||||
/* We've parsed as many subgroups as we support */
|
||||
LOG_DBG("Could only store %u subgroups", data->subgroup_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &codec_cfg);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not store codec_cfg: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Lookup and assign path_id based on capabilities */
|
||||
codec_id.id = codec_cfg.id;
|
||||
codec_id.cid = codec_cfg.cid;
|
||||
codec_id.vid = codec_cfg.vid;
|
||||
|
||||
codec_cap = bt_pacs_get_codec_cap(BT_AUDIO_DIR_SINK, &codec_id);
|
||||
if (codec_cap == NULL) {
|
||||
LOG_DBG("Codec with id 0x%02x cid 0x%04x and vid 0x%04x is not supported by our "
|
||||
"capabilities",
|
||||
codec_id.id, codec_id.cid, codec_id.vid);
|
||||
} else {
|
||||
codec_cfg.path_id = codec_cap->path_id;
|
||||
codec_cfg.ctlr_transcode = codec_cap->ctlr_transcode;
|
||||
|
||||
data->subgroup_codec_cfg = &codec_cfg;
|
||||
|
||||
ret = bt_bap_base_subgroup_foreach_bis(subgroup, sync_base_subgroup_bis_index_cb,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not parse BISes: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
data->subgroup_count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t indexes_bitfield,
|
||||
struct bt_bap_stream *streams[],
|
||||
const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])
|
||||
{
|
||||
static struct sync_base_info_data data;
|
||||
struct bt_iso_big_sync_param param;
|
||||
struct bt_audio_codec_cfg *codec_cfgs[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT] = {NULL};
|
||||
struct bt_iso_chan *bis_channels[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||
uint8_t bis_count;
|
||||
uint8_t stream_count;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
CHECKIF(sink == NULL) {
|
||||
LOG_DBG("sink is NULL");
|
||||
@ -1261,32 +1264,34 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate that number of bits set is less than number of streams */
|
||||
/* Validate that number of bits set is within supported range */
|
||||
bis_count = bit_count(indexes_bitfield);
|
||||
if (bis_count > CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT) {
|
||||
LOG_DBG("Cannot sync to more than %d streams (%u was requested)",
|
||||
CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT, bis_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate that the bits set are present in BASE */
|
||||
if ((indexes_bitfield & sink->valid_indexes_bitfield) != indexes_bitfield) {
|
||||
LOG_DBG("Request BIS indexes 0x%08X contains bits not support by the Broadcast "
|
||||
"Sink 0x%08X",
|
||||
LOG_DBG("Request BIS indexes (0x%08X) contains bits not present in BASE (0x%08X)",
|
||||
indexes_bitfield, sink->valid_indexes_bitfield);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stream_count = 0;
|
||||
for (int i = 1; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) {
|
||||
if ((indexes_bitfield & BT_ISO_BIS_INDEX_BIT(i)) != 0) {
|
||||
struct bt_audio_codec_cfg *codec_cfg =
|
||||
codec_cfg_from_base_by_index(sink, i);
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
__ASSERT(codec_cfg != NULL, "Index %d not found in sink", i);
|
||||
data.sync_indexes_bitfield = indexes_bitfield;
|
||||
|
||||
codec_cfgs[stream_count++] = codec_cfg;
|
||||
|
||||
if (stream_count > CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT) {
|
||||
LOG_DBG("Cannot sync to more than %d streams (%u was requested)",
|
||||
CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT, stream_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
ret = bt_bap_base_foreach_subgroup((const struct bt_bap_base *)sink->base,
|
||||
sync_base_subgroup_cb, &data);
|
||||
if (ret != 0) {
|
||||
LOG_DBG("Failed to parse all subgroups: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
stream_count = data.stream_count;
|
||||
|
||||
for (size_t i = 0; i < stream_count; i++) {
|
||||
CHECKIF(streams[i] == NULL) {
|
||||
LOG_DBG("streams[%zu] is NULL", i);
|
||||
@ -1300,7 +1305,7 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
|
||||
stream = streams[i];
|
||||
codec_cfg = codec_cfgs[i];
|
||||
codec_cfg = &data.codec_cfgs[i];
|
||||
|
||||
err = bt_bap_broadcast_sink_setup_stream(sink, stream, codec_cfg);
|
||||
if (err != 0) {
|
||||
|
||||
@ -180,6 +180,7 @@ struct bt_bap_broadcast_sink {
|
||||
struct bt_bap_qos_cfg qos_cfg;
|
||||
struct bt_le_per_adv_sync *pa_sync;
|
||||
struct bt_iso_big *big;
|
||||
uint8_t base[BT_BASE_MAX_SIZE];
|
||||
struct bt_bap_broadcast_sink_bis bis[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||
struct bt_bap_broadcast_sink_subgroup subgroups[CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT];
|
||||
const struct bt_bap_scan_delegator_recv_state *recv_state;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user