Bluetooth: Audio: add bt_audio_get_chan_count

Implement a function bt_audio_get_chan_count that takes an enum
bt_audio_location and returns the number of channels in that value.

This PR fixes #69617
(https://github.com/zephyrproject-rtos/zephyr/issues/69617)

Signed-off-by: Babak Arisian <bbaa@demant.com>
diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h
index 4274279..a7d2480 100644
--- a/include/zephyr/bluetooth/audio/audio.h
+++ b/include/zephyr/bluetooth/audio/audio.h
@@ -631,6 +631,15 @@
 int bt_audio_data_parse(const uint8_t ltv[], size_t size,
 			bool (*func)(struct bt_data *data, void *user_data), void *user_data);
 
+/**
+ * @brief Function to get the number of channels from the channel allocation
+ *
+ * @param chan_allocation The channel allocation
+ *
+ * @return The number of channels
+ */
+uint8_t bt_audio_get_chan_count(enum bt_audio_location chan_allocation);
+
 /** @brief Audio Capability type */
 enum bt_audio_dir {
 	BT_AUDIO_DIR_SINK = 0x01,
diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c
index 38f9f54..b08c4f9 100644
--- a/samples/bluetooth/broadcast_audio_sink/src/main.c
+++ b/samples/bluetooth/broadcast_audio_sink/src/main.c
@@ -151,22 +151,6 @@
 K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread,
 		NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1);
 
-static size_t get_chan_cnt(enum bt_audio_location chan_allocation)
-{
-	size_t cnt = 0U;
-
-	if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) {
-		return 1;
-	}
-
-	while (chan_allocation != 0) {
-		cnt += chan_allocation & 1U;
-		chan_allocation >>= 1;
-	}
-
-	return cnt;
-}
-
 /* Consumer thread of the decoded stream data */
 static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3)
 {
@@ -207,7 +191,7 @@
 			stream->in_buf = NULL;
 			k_mutex_unlock(&stream->lc3_decoder_mutex);
 
-			frames_per_block = get_chan_cnt(stream->chan_allocation);
+			frames_per_block = bt_audio_get_chan_count(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 "
@@ -386,7 +370,7 @@
 	/* An SDU can consist of X frame blocks, each with Y frames (one per channel) of size Z in
 	 * them. The minimum SDU size required for this is X * Y * Z.
 	 */
-	chan_alloc_bit_cnt = get_chan_cnt(sink_stream->chan_allocation);
+	chan_alloc_bit_cnt = bt_audio_get_chan_count(sink_stream->chan_allocation);
 	sdu_size_required = chan_alloc_bit_cnt * sink_stream->lc3_octets_per_frame *
 			    sink_stream->lc3_frames_blocks_per_sdu;
 	if (sdu_size_required < sink_stream->stream.qos->sdu) {
@@ -771,7 +755,7 @@
 	} else {
 		/* If the subgroup contains a single channel, then we just grab the first BIS index
 		 */
-		if (get_chan_cnt(chan_allocation) == 1 &&
+		if (bt_audio_get_chan_count(chan_allocation) == 1 &&
 		    chan_allocation == CONFIG_TARGET_BROADCAST_CHANNEL) {
 			uint32_t subgroup_bis_indexes;
 
diff --git a/subsys/bluetooth/audio/audio.c b/subsys/bluetooth/audio/audio.c
index 164a52a..619f52c 100644
--- a/subsys/bluetooth/audio/audio.c
+++ b/subsys/bluetooth/audio/audio.c
@@ -67,6 +67,26 @@
 	return 0;
 }
 
+uint8_t bt_audio_get_chan_count(enum bt_audio_location chan_allocation)
+{
+	if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) {
+		return 1;
+	}
+
+#ifdef POPCOUNT
+	return POPCOUNT(chan_allocation);
+#else
+	uint8_t cnt = 0U;
+
+	while (chan_allocation != 0U) {
+		cnt += chan_allocation & 1U;
+		chan_allocation >>= 1U;
+	}
+
+	return cnt;
+#endif
+}
+
 #if defined(CONFIG_BT_CONN)
 
 static uint8_t bt_audio_security_check(const struct bt_conn *conn)
diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h
index 8d53755..1a73258 100644
--- a/subsys/bluetooth/audio/shell/audio.h
+++ b/subsys/bluetooth/audio/shell/audio.h
@@ -220,22 +220,6 @@
 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
 #endif /* CONFIG_BT_BAP_UNICAST */
 
-static inline uint8_t get_chan_cnt(enum bt_audio_location chan_allocation)
-{
-	uint8_t cnt = 0U;
-
-	if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) {
-		return 1;
-	}
-
-	while (chan_allocation != 0) {
-		cnt += chan_allocation & 1U;
-		chan_allocation >>= 1;
-	}
-
-	return cnt;
-}
-
 static inline void print_qos(const struct shell *sh, const struct bt_audio_codec_qos *qos)
 {
 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST)
diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c
index 4ffa953..b045ecb 100644
--- a/subsys/bluetooth/audio/shell/bap.c
+++ b/subsys/bluetooth/audio/shell/bap.c
@@ -2855,7 +2855,8 @@
 		ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg,
 							     &sh_stream->lc3_chan_allocation);
 		if (ret == 0) {
-			sh_stream->lc3_chan_cnt = get_chan_cnt(sh_stream->lc3_chan_allocation);
+			sh_stream->lc3_chan_cnt =
+				bt_audio_get_chan_count(sh_stream->lc3_chan_allocation);
 		} else {
 			shell_error(ctx_shell, "Could not get channel allocation: %d", ret);
 			sh_stream->lc3_chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;
diff --git a/subsys/bluetooth/audio/shell/bap_usb.c b/subsys/bluetooth/audio/shell/bap_usb.c
index 30afd5a..cd597c6 100644
--- a/subsys/bluetooth/audio/shell/bap_usb.c
+++ b/subsys/bluetooth/audio/shell/bap_usb.c
@@ -214,7 +214,7 @@
 		return -EINVAL;
 	}
 
-	if (get_chan_cnt(chan_allocation) != 1) {
+	if (bt_audio_get_chan_count(chan_allocation) != 1) {
 		LOG_DBG("Invalid channel allocation %d", chan_allocation);
 
 		return -EINVAL;
diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c
index cabd365..04fe1ce 100644
--- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c
+++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c
@@ -66,18 +66,6 @@
 static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U);
 static uint32_t bis_index_bitfield;
 
-static uint8_t count_bits(enum bt_audio_location chan_allocation)
-{
-	uint8_t cnt = 0U;
-
-	while (chan_allocation != 0) {
-		cnt += chan_allocation & 1U;
-		chan_allocation >>= 1;
-	}
-
-	return cnt;
-}
-
 static bool valid_base_subgroup(const struct bt_bap_base_subgroup *subgroup)
 {
 	struct bt_audio_codec_cfg codec_cfg = {0};
@@ -128,7 +116,7 @@
 
 	ret = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation);
 	if (ret == 0) {
-		chan_cnt = count_bits(chan_allocation);
+		chan_cnt = bt_audio_get_chan_count(chan_allocation);
 	} else {
 		printk("Could not get subgroup channel allocation: %d\n", ret);
 		/* Channel allocation is an optional field, and omitting it implicitly means mono */
@@ -444,7 +432,7 @@
 			return;
 		}
 
-		chan_cnt = count_bits(chan_allocation);
+		chan_cnt = bt_audio_get_chan_count(chan_allocation);
 	} else {
 		FAIL("Could not get subgroup channel allocation: %d\n", ret);