samples: Bluetooth: Add stereo support for broadcast audio sink
The broadcast audio sink now supports stereo if
CONFIG_TARGET_BROADCAST_CHANNEL=3 (LEFT | RIGHT).
It parses the BASE to find a set of BIS (1 or 2) that contain
the channel allocation from CONFIG_TARGET_BROADCAST_CHANNEL.
Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig b/samples/bluetooth/broadcast_audio_sink/Kconfig
index 72a31d6..7faffd0 100644
--- a/samples/bluetooth/broadcast_audio_sink/Kconfig
+++ b/samples/bluetooth/broadcast_audio_sink/Kconfig
@@ -35,6 +35,14 @@
Name of target broadcast device. If not empty string, sink device
will only listen to the specified broadcast source. Not case sensitive.
+config MAX_CODEC_FRAMES_PER_SDU
+ int "The maximum number of codec frame per SDU supported"
+ default 1
+ range 1 255
+ help
+ Maximum number of codec frames per SDU supported by this device. Increasing this value
+ allows support for a greater variaty of broadcasts, but also increases memory usage.
+
config ENABLE_LC3
bool "Enable the LC3 codec"
# By default let's enable it in the platforms we know are capable of supporting it
@@ -64,7 +72,7 @@
config TARGET_BROADCAST_CHANNEL
int "Broadcast Channel Audio Location to sync to"
- range 0 2
+ range 0 3
default 1
depends on USE_SPECIFIC_BROADCAST_CHANNEL
help
diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c
index 979da4f..562b4cc 100644
--- a/samples/bluetooth/broadcast_audio_sink/src/main.c
+++ b/samples/bluetooth/broadcast_audio_sink/src/main.c
@@ -112,7 +112,8 @@
static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_CAP_FREQ_16KHZ | BT_AUDIO_CODEC_CAP_FREQ_24KHZ,
- BT_AUDIO_CODEC_CAP_DURATION_10, BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u,
+ BT_AUDIO_CODEC_CAP_DURATION_10, BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), 40u, 60u,
+ CONFIG_MAX_CODEC_FRAMES_PER_SDU,
(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
/* Create a mask for the maximum BIS we can sync to using the number of streams
@@ -132,53 +133,18 @@
RING_BUF_DECLARE(usb_ring_buf, USB_RING_BUF_SIZE);
NET_BUF_POOL_DEFINE(usb_tx_buf_pool, USB_ENQUEUE_COUNT, USB_STEREO_SAMPLE_SIZE, 0, net_buf_destroy);
-static void mix_mono_to_stereo(int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]);
static void add_to_usb_ring_buf(const int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]);
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
#if defined(CONFIG_LIBLC3)
static K_SEM_DEFINE(lc3_decoder_sem, 0, 1);
-static bool do_lc3_decode(struct broadcast_sink_stream *sink_stream,
- int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]);
+static void do_lc3_decode(lc3_decoder_t decoder, const void *in_data, uint8_t octets_per_frame,
+ int16_t out_data[LC3_MAX_NUM_SAMPLES_MONO]);
static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3);
K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread,
NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1);
-/* Consumer thread of the decoded stream data */
-static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3)
-{
- while (true) {
- static int16_t lc3_audio_buf[LC3_MAX_NUM_SAMPLES_STEREO];
-
- k_sem_take(&lc3_decoder_sem, K_FOREVER);
-#if defined(CONFIG_USB_DEVICE_AUDIO)
-
- /* For now we only handle one BIS, so always only decode the first element
- * in streams.
- */
- struct broadcast_sink_stream *stream_for_usb = &streams[0];
-
- /* Not enough space to store data */
- if (ring_buf_space_get(&usb_ring_buf) < sizeof(lc3_audio_buf)) {
- continue;
- }
-
- /* lc3_audio_buf will be filled with the last decoded value, so e.g. if the stream
- * contains both left and right, the lc3_audio_buf will always contain right.
- */
- if (do_lc3_decode(stream_for_usb, lc3_audio_buf)) {
- mix_mono_to_stereo(lc3_audio_buf);
- add_to_usb_ring_buf(lc3_audio_buf);
- }
-#else
- for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
- (void)do_lc3_decode(&streams[i], lc3_audio_buf);
- }
-#endif /* #if defined(CONFIG_USB_DEVICE_AUDIO) */
- }
-}
-
static size_t get_chan_cnt(enum bt_audio_location chan_allocation)
{
size_t cnt = 0U;
@@ -195,61 +161,171 @@
return cnt;
}
-/** Decode LC3 data on a stream and returns true if successful */
-static bool do_lc3_decode(struct broadcast_sink_stream *sink_stream,
- int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO])
+/* Consumer thread of the decoded stream data */
+static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3)
{
- const uint8_t frames_blocks_per_sdu = sink_stream->lc3_frames_blocks_per_sdu;
- const uint16_t octets_per_frame = sink_stream->lc3_octets_per_frame;
- uint16_t frames_per_block;
- struct net_buf *buf;
+ while (true) {
+#if defined(CONFIG_USB_DEVICE_AUDIO)
+ static int16_t right_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU]
+ [LC3_MAX_NUM_SAMPLES_MONO];
+ static int16_t left_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU]
+ [LC3_MAX_NUM_SAMPLES_MONO];
+ size_t right_frames_cnt = 0;
+ size_t left_frames_cnt = 0;
- k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER);
+ memset(right_frames, 0, sizeof(right_frames));
+ memset(left_frames, 0, sizeof(left_frames));
+#else
+ static int16_t lc3_audio_buf[LC3_MAX_NUM_SAMPLES_MONO];
+#endif /* CONFIG_USB_DEVICE_AUDIO */
- if (sink_stream->in_buf == NULL) {
- k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
+ k_sem_take(&lc3_decoder_sem, K_FOREVER);
- return false;
- }
+ for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
+ struct broadcast_sink_stream *stream = &streams[i];
+ const uint8_t frames_blocks_per_sdu = stream->lc3_frames_blocks_per_sdu;
+ const uint16_t octets_per_frame = stream->lc3_octets_per_frame;
+ uint16_t frames_per_block;
+ struct net_buf *buf;
- buf = net_buf_ref(sink_stream->in_buf);
- net_buf_unref(sink_stream->in_buf);
- sink_stream->in_buf = NULL;
- k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
+ k_mutex_lock(&stream->lc3_decoder_mutex, K_FOREVER);
- frames_per_block = get_chan_cnt(sink_stream->chan_allocation);
- if (buf->len != (frames_per_block * octets_per_frame * frames_blocks_per_sdu)) {
- printk("Expected %u frame blocks with %u frames of size %u, but length is %u\n",
- frames_blocks_per_sdu, frames_per_block, octets_per_frame, buf->len);
+ if (stream->in_buf == NULL) {
+ k_mutex_unlock(&stream->lc3_decoder_mutex);
- net_buf_unref(buf);
+ continue;
+ }
- return false;
- }
+ buf = net_buf_ref(stream->in_buf);
+ net_buf_unref(stream->in_buf);
+ stream->in_buf = NULL;
+ k_mutex_unlock(&stream->lc3_decoder_mutex);
- for (uint8_t i = 0U; i < frames_blocks_per_sdu; i++) {
- for (uint16_t j = 0U; j < frames_per_block; j++) {
- const void *data = net_buf_pull_mem(buf, octets_per_frame);
- int err;
-
- err = lc3_decode(sink_stream->lc3_decoder, data, octets_per_frame,
- LC3_PCM_FORMAT_S16, audio_buf, 1);
-
- if (err == 1) {
- printk(" decoder performed PLC\n");
- } else if (err < 0) {
- printk(" decoder failed - wrong parameters? (err = %d)\n", err);
+ frames_per_block = get_chan_cnt(stream->chan_allocation);
+ if (buf->len !=
+ (frames_per_block * octets_per_frame * frames_blocks_per_sdu)) {
+ printk("Expected %u frame blocks with %u frames of size %u, but "
+ "length is %u\n",
+ frames_blocks_per_sdu, frames_per_block, octets_per_frame,
+ buf->len);
net_buf_unref(buf);
- return false;
+ continue;
}
+
+#if defined(CONFIG_USB_DEVICE_AUDIO)
+ const bool has_left =
+ (stream->chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0;
+ const bool has_right =
+ (stream->chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0;
+ const bool is_mono =
+ stream->chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO;
+
+ /* Split the SDU into frames*/
+ for (uint8_t i = 0U; i < frames_blocks_per_sdu; i++) {
+ for (uint16_t j = 0U; j < frames_per_block; j++) {
+ const bool is_left = j == 0 && has_left;
+ const bool is_right =
+ has_right && (j == 0 || (j == 1 && has_left));
+ const void *data = net_buf_pull_mem(buf, octets_per_frame);
+ int16_t *out_frame;
+
+ if (is_left) {
+ out_frame = left_frames[left_frames_cnt++];
+ } else if (is_right) {
+ out_frame = right_frames[right_frames_cnt++];
+ } else if (is_mono) {
+ /* Use left as mono*/
+ out_frame = left_frames[left_frames_cnt++];
+ } else {
+ /* unused channel */
+ break;
+ }
+
+ do_lc3_decode(stream->lc3_decoder, data, octets_per_frame,
+ out_frame);
+ }
+ }
+#else
+ /* Dummy behavior: Decode and discard data */
+ for (uint8_t i = 0U; i < frames_blocks_per_sdu; i++) {
+ for (uint16_t j = 0U; j < frames_per_block; j++) {
+ const void *data = net_buf_pull_mem(buf, octets_per_frame);
+
+ do_lc3_decode(stream->lc3_decoder, data, octets_per_frame,
+ lc3_audio_buf);
+ }
+ }
+#endif /* CONFIG_USB_DEVICE_AUDIO */
+
+ net_buf_unref(buf);
}
+
+#if defined(CONFIG_USB_DEVICE_AUDIO)
+ const bool is_left_only = right_frames_cnt == 0U;
+ const bool is_right_only = left_frames_cnt == 0U;
+
+ if (!is_left_only && !is_right_only && left_frames_cnt != right_frames_cnt) {
+ printk("Mismatch between number of left (%zu) and right (%zu) frames, "
+ "discard SDU",
+ left_frames_cnt, right_frames_cnt);
+ continue;
+ }
+
+ /* Send frames to USB - If we only have a single channel we mix it to stereo */
+ for (size_t i = 0U; i < MAX(left_frames_cnt, right_frames_cnt); i++) {
+ const bool is_single_channel = is_left_only || is_right_only;
+ static int16_t stereo_frame[LC3_MAX_NUM_SAMPLES_STEREO];
+ int16_t *right_frame = right_frames[i];
+ int16_t *left_frame = left_frames[i];
+
+ /* Not enough space to store data */
+ if (ring_buf_space_get(&usb_ring_buf) < sizeof(stereo_frame)) {
+ break;
+ }
+
+ memset(stereo_frame, 0, sizeof(stereo_frame));
+
+ /* Generate the stereo frame
+ *
+ * If we only have single channel then that is always stored in the
+ * left_frame, and we mix that to stereo
+ */
+ for (int j = 0; j < LC3_MAX_NUM_SAMPLES_MONO; j++) {
+ if (is_single_channel) {
+ /* Mix to stereo */
+ if (is_left_only) {
+ stereo_frame[j * 2] = left_frame[j];
+ stereo_frame[j * 2 + 1] = left_frame[j];
+ } else if (is_right_only) {
+ stereo_frame[j * 2] = right_frame[j];
+ stereo_frame[j * 2 + 1] = right_frame[j];
+ }
+ } else {
+ stereo_frame[j * 2] = left_frame[j];
+ stereo_frame[j * 2 + 1] = right_frame[j];
+ }
+ }
+
+ add_to_usb_ring_buf(stereo_frame);
+ }
+#endif /* CONFIG_USB_DEVICE_AUDIO */
}
+}
- net_buf_unref(buf);
+/** Decode LC3 data on a stream and returns true if successful */
+static void do_lc3_decode(lc3_decoder_t decoder, const void *in_data, uint8_t octets_per_frame,
+ int16_t out_data[LC3_MAX_NUM_SAMPLES_MONO])
+{
+ int err;
- return true;
+ err = lc3_decode(decoder, in_data, octets_per_frame, LC3_PCM_FORMAT_S16, out_data, 1);
+ if (err == 1) {
+ printk(" decoder performed PLC\n");
+ } else if (err < 0) {
+ printk(" decoder failed - wrong parameters? (err = %d)\n", err);
+ }
}
static int lc3_enable(struct broadcast_sink_stream *sink_stream)
@@ -342,21 +418,6 @@
#endif /* defined(CONFIG_LIBLC3) */
#if defined(CONFIG_USB_DEVICE_AUDIO)
-/* Duplicate the audio from one channel and put it in both channels */
-static void mix_mono_to_stereo(int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO])
-{
- /* Interleave the channel sample inline
- * Take the first LC3_MAX_NUM_SAMPLES_MONO samples from audio_buf and mix it to
- * interleaved stereo, so that 012345 becomes 001122334455
- */
- for (int i = LC3_MAX_NUM_SAMPLES_MONO - 1; i >= 0; i--) {
- const int16_t sample = audio_buf[i];
-
- audio_buf[i * 2] = sample;
- audio_buf[i * 2 + 1] = sample;
- }
-}
-
/* Move the LC3 data to the USB ring buffer */
static void add_to_usb_ring_buf(const int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO])
{
@@ -508,67 +569,221 @@
};
#if defined(CONFIG_TARGET_BROADCAST_CHANNEL)
+struct find_valid_bis_data {
+ struct {
+ uint8_t index;
+ enum bt_audio_location chan_allocation;
+ } bis[BT_ISO_BIS_INDEX_MAX];
+
+ uint8_t cnt;
+};
+
+/**
+ * This is called for each BIS in a subgroup
+ *
+ * It returns `false` if the current BIS contains all of the channels we are looking for,
+ * or if it does not contain any and we are looking for BT_AUDIO_LOCATION_MONO_AUDIO. This stops
+ * the iteration of the remaining BIS in the subgroup.
+ *
+ * It returns `true` if the BIS either contains none or some of the channels we are looking for.
+ * If it contains some, then that is being stored in the user_data, so that the calling function
+ * can check if a combination of the BIS satisfy the channel allocations we want.
+ */
static bool find_valid_bis_cb(const struct bt_bap_base_subgroup_bis *bis,
void *user_data)
{
- int err;
+ struct find_valid_bis_data *data = user_data;
struct bt_audio_codec_cfg codec_cfg = {0};
enum bt_audio_location chan_allocation;
- uint8_t *bis_index = user_data;
+ int err;
err = bt_bap_base_subgroup_bis_codec_to_codec_cfg(bis, &codec_cfg);
if (err != 0) {
- printk("Could not find codec configuration (err=%d)\n", err);
+ printk("Could not get codec configuration for BIS: %d\n", err);
return true;
}
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation);
if (err != 0) {
- printk("Could not find channel allocation (err=%d)\n", err);
- if (err == -ENODATA && strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) {
+ printk("Could not find channel allocation for BIS: %d\n", err);
+
+ /* Absence of channel allocation is implicitly mono as per the BAP spec */
+ if (CONFIG_TARGET_BROADCAST_CHANNEL == BT_AUDIO_LOCATION_MONO_AUDIO) {
+ data->bis[0].index = bis->index;
+ data->bis[0].chan_allocation = chan_allocation;
+ data->cnt = 1;
+
+ return false;
+ } else if (err == -ENODATA && strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) {
/* Accept no channel allocation data available
* if TARGET_BROADCAST_NAME defined. Use current index.
*/
- *bis_index = bis->index;
+ data->bis[0].index = bis->index;
+ data->bis[0].chan_allocation = chan_allocation;
+ data->cnt = 1;
return false;
}
+ } else {
+ if ((chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) ==
+ CONFIG_TARGET_BROADCAST_CHANNEL) {
+ /* Found single BIS with all channels we want - keep as only and stop
+ * parsing
+ */
+ data->bis[0].index = bis->index;
+ data->bis[0].chan_allocation = chan_allocation;
+ data->cnt = 1;
- return true;
- }
-
- if ((CONFIG_TARGET_BROADCAST_CHANNEL == BT_AUDIO_LOCATION_MONO_AUDIO &&
- chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) ||
- chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) {
- *bis_index = bis->index;
-
- return false;
+ return false;
+ } else if ((chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) != 0) {
+ /* BIS contains part of what we are looking for - Store and see if there are
+ * other BIS that may fill the gaps
+ */
+ data->bis[data->cnt].index = bis->index;
+ data->bis[data->cnt].chan_allocation = chan_allocation;
+ data->cnt++;
+ }
}
return true;
}
+/**
+ * This function searches all the BIS in a subgroup for a set of BIS indexes that satisfy
+ * CONFIG_TARGET_BROADCAST_CHANNEL
+ *
+ * Returns `true` if the right channels were found, otherwise `false`.
+ */
+static bool find_valid_bis_in_subgroup_bis(const struct bt_bap_base_subgroup *subgroup,
+ uint32_t *bis_indexes)
+{
+ struct find_valid_bis_data data = {0};
+ int err;
+
+ err = bt_bap_base_subgroup_foreach_bis(subgroup, find_valid_bis_cb, &data);
+ if (err == -ECANCELED) {
+ /* We found what we are looking for in a single BIS */
+
+ *bis_indexes = BIT(data.bis[0].index);
+
+ return true;
+ } else if (err == 0) {
+ /* We are finished parsing all BIS - Try to find a combination that satisfy our
+ * channel allocation. For simplicity this is using a greedy approach, rather than
+ * an optimal one.
+ */
+ enum bt_audio_location chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;
+ *bis_indexes = 0;
+
+ for (uint8_t i = 0U; i < data.cnt; i++) {
+ chan_allocation |= data.bis[i].chan_allocation;
+ *bis_indexes |= BIT(data.bis[i].index);
+
+ if ((chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) ==
+ CONFIG_TARGET_BROADCAST_CHANNEL) {
+ return true;
+ }
+ }
+ }
+
+ /* Some error occurred or we did not find expected channel allocation */
+ return false;
+}
+
+/**
+ * Called for each subgroup in the BASE. Will populate the 32-bit bitfield of BIS indexes if the
+ * subgroup contains it.
+ *
+ * The channel allocation may
+ * - Not exist at all, implicitly meaning BT_AUDIO_LOCATION_MONO_AUDIO
+ * - Exist only in the subgroup codec configuration
+ * - Exist only in the BIS codec configuration
+ * - Exist in both the subgroup and BIS codec configuration, in which case, the BIS codec
+ * configuration overwrites the subgroup values
+ *
+ * This function returns `true` if the subgroup does not support the channels in
+ * CONFIG_TARGET_BROADCAST_CHANNEL which makes it iterate over the next subgroup, and returns
+ * `false` if this subgroup satisfies our CONFIG_TARGET_BROADCAST_CHANNEL.
+ */
static bool find_valid_bis_in_subgroup_cb(const struct bt_bap_base_subgroup *subgroup,
void *user_data)
{
- return bt_bap_base_subgroup_foreach_bis(subgroup, find_valid_bis_cb, user_data)
- == -ECANCELED ? false : true;
+ enum bt_audio_location chan_allocation;
+ struct bt_audio_codec_cfg codec_cfg;
+ uint32_t *bis_indexes = user_data;
+ int err;
+
+ /* We only want indexes from a single subgroup, so reset between each of them*/
+ *bis_indexes = 0U;
+
+ err = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &codec_cfg);
+ if (err != 0) {
+ printk("Could not get codec configuration: %d\n", err);
+
+ return true;
+ }
+
+ err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation);
+ if (err != 0) {
+ printk("Could not find subgroup channel allocation: %d - Looking in the BISes\n",
+ err);
+
+ /* Find chan alloc in BIS */
+ if (find_valid_bis_in_subgroup_bis(subgroup, bis_indexes)) {
+ /* Found BISes with correct channel allocation */
+ return false;
+ }
+ } else {
+ /* If the subgroup contains a single channel, then we just grab the first BIS index
+ */
+ if (get_chan_cnt(chan_allocation) == 1 &&
+ chan_allocation == CONFIG_TARGET_BROADCAST_CHANNEL) {
+ uint32_t subgroup_bis_indexes;
+
+ /* Set bis_indexes to the first bit set */
+ err = bt_bap_base_subgroup_get_bis_indexes(subgroup, &subgroup_bis_indexes);
+ if (err != 0) {
+ /* Should never happen as that would indicate an invalid
+ * subgroup If it does, we just parse the next subgroup
+ */
+ return true;
+ }
+
+ /* We found the BIS index we want, stop parsing*/
+ *bis_indexes = BIT(find_lsb_set(subgroup_bis_indexes) - 1);
+
+ return false;
+ } else if ((chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) ==
+ CONFIG_TARGET_BROADCAST_CHANNEL) {
+ /* The subgroup contains all channels we are looking for/
+ * We continue searching each BIS to get the minimal amount of BIS that
+ * satisfy CONFIG_TARGET_BROADCAST_CHANNEL.
+ */
+
+ if (find_valid_bis_in_subgroup_bis(subgroup, bis_indexes)) {
+ /* Found BISes with correct channel allocation */
+ return false;
+ }
+ }
+ }
+
+ return true;
}
-static int base_get_first_valid_bis(const struct bt_bap_base *base, uint32_t *bis_index)
+/**
+ * This function gets a 32-bit bitfield of BIS indexes that cover the channel allocation values in
+ * CONFIG_TARGET_BROADCAST_CHANNEL.
+ */
+static int base_get_valid_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes)
{
int err;
- uint8_t valid_bis_index = 0U;
- err = bt_bap_base_foreach_subgroup(base, find_valid_bis_in_subgroup_cb, &valid_bis_index);
+ err = bt_bap_base_foreach_subgroup(base, find_valid_bis_in_subgroup_cb, bis_indexes);
if (err != -ECANCELED) {
printk("Failed to parse subgroups: %d\n", err);
return err != 0 ? err : -ENOENT;
}
- *bis_index = 0;
- *bis_index |= ((uint8_t)1 << valid_bis_index);
-
return 0;
}
#endif /* CONFIG_TARGET_BROADCAST_CHANNEL */
@@ -587,7 +802,7 @@
bt_bap_base_get_subgroup_count(base), sink);
#if defined(CONFIG_TARGET_BROADCAST_CHANNEL)
- err = base_get_first_valid_bis(base, &base_bis_index_bitfield);
+ err = base_get_valid_bis_indexes(base, &base_bis_index_bitfield);
if (err != 0) {
printk("Failed to find a valid BIS\n");
return;