Repository: nrfconnect/sdk-nrf
Pull request #22100: applications: nrf5340_audio: Use new audio struct
Author: login: alexsven
Labels: name: doc-required
description: PR must not be merged without tech writer approval.
Created: 2025-04-28T15:37:17Z | Merged: 2025-05-22T09:53:20Z

- Implement new struct in broadcast_sink from end-to-end
- Implement audio struct in usb RX
  - Added audio struct to USB RX all the way up to sw_encode
- Use audio struct in sw_encode
  - Replace PCM data with LC3 data and update meta data
  - Uses audio struct from USB all the way to le_audio_tx
- Added audio_struct to the decode function
- Implement audio_struct in unicast
  - Using the new audio struct in both unicast server and client
- Implement the new audio struct in nrf_auraconfig sample
- OCT-3285

Signed-off-by: Alexander Svensen <alexander.svensen@nordicsemi.no>


Diff:
diff --git a/applications/nrf5340_audio/broadcast_sink/main.c b/applications/nrf5340_audio/broadcast_sink/main.c
index b3fd305ee4aa..6e7ade8f0e98 100644
--- a/applications/nrf5340_audio/broadcast_sink/main.c
+++ b/applications/nrf5340_audio/broadcast_sink/main.c
@@ -563,11 +563,9 @@ uint8_t stream_state_get(void)
 	return strm_state;
 }
 
-void streamctrl_send(void const *const data, size_t size, uint8_t num_ch)
+void streamctrl_send(struct audio_data const *const audio_frame)
 {
-	ARG_UNUSED(data);
-	ARG_UNUSED(size);
-	ARG_UNUSED(num_ch);
+	ARG_UNUSED(audio_frame);
 
 	LOG_WRN("Sending is not possible for broadcast sink");
 }
diff --git a/applications/nrf5340_audio/broadcast_source/main.c b/applications/nrf5340_audio/broadcast_source/main.c
index 35a2598da6e9..1cf0bb5f8031 100644
--- a/applications/nrf5340_audio/broadcast_source/main.c
+++ b/applications/nrf5340_audio/broadcast_source/main.c
@@ -494,15 +494,13 @@ uint8_t stream_state_get(void)
 	return strm_state;
 }
 
-void streamctrl_send(void const *const data, size_t size, uint8_t num_ch)
+void streamctrl_send(struct audio_data const *const audio_frame)
 {
 	int ret;
 	static int prev_ret;
 
-	struct le_audio_encoded_audio enc_audio = {.data = data, .size = size, .num_ch = num_ch};
-
 	if (strm_state == STATE_STREAMING) {
-		ret = broadcast_source_send(0, 0, enc_audio);
+		ret = broadcast_source_send(0, 0, audio_frame);
 
 		if (ret != 0 && ret != prev_ret) {
 			if (ret == -ECANCELED) {
diff --git a/applications/nrf5340_audio/src/audio/audio_datapath.c b/applications/nrf5340_audio/src/audio/audio_datapath.c
index d7ffb3cf3d25..3c0ed8c3a3dd 100644
--- a/applications/nrf5340_audio/src/audio/audio_datapath.c
+++ b/applications/nrf5340_audio/src/audio/audio_datapath.c
@@ -12,6 +12,7 @@
 #include <zephyr/zbus/zbus.h>
 #include <zephyr/kernel.h>
 #include <zephyr/shell/shell.h>
+#include <zephyr/net_buf.h>
 #include <nrfx_clock.h>
 #include <contin_array.h>
 #include <tone.h>
@@ -91,6 +92,8 @@ LOG_MODULE_REGISTER(audio_datapath, CONFIG_AUDIO_DATAPATH_LOG_LEVEL);
 /* How often to print under-run warning */
 #define UNDERRUN_LOG_INTERVAL_BLKS 5000
 
+NET_BUF_POOL_FIXED_DEFINE(pool_i2s_rx, FIFO_NUM_BLKS, BLK_STEREO_SIZE_OCTETS, 8, net_buf_destroy);
+
 enum drift_comp_state {
 	DRIFT_STATE_INIT,   /* Waiting for data to be received */
 	DRIFT_STATE_CALIB,  /* Calibrate and zero out local delay */
@@ -689,51 +692,74 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t
 	}
 
 	/********** I2S RX **********/
-	static uint32_t *rx_buf;
 	static int prev_ret;
+	struct audio_data *rx_audio_block = NULL;
+	struct net_buf *buf_in;
 
 	if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == GATEWAY)) {
-		/* Lock last filled buffer into message queue */
-		if (rx_buf_released != NULL) {
-			ret = data_fifo_block_lock(ctrl_blk.in.fifo, (void **)&rx_buf_released,
-						   BLOCK_SIZE_BYTES);
-
-			ERR_CHK_MSG(ret, "Unable to lock block RX");
+		if (rx_buf_released == NULL) {
+			/* No RX data available */
+			ERR_CHK_MSG(-ENOMEM, "No RX data available");
 		}
 
-		/* Get new empty buffer to send to I2S HW */
-		ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void **)&rx_buf,
-							 K_NO_WAIT);
-		if (ret == 0 && prev_ret == -ENOMEM) {
-			LOG_WRN("I2S RX continuing stream");
-			prev_ret = ret;
+		buf_in = net_buf_alloc(&pool_i2s_rx, K_NO_WAIT);
+		if (buf_in == NULL) {
+			ERR_CHK_MSG(-ENOMEM, "Out of RX buffers for I2S");
 		}
 
+		/* Store RX buffer in net_buf */
+		net_buf_add_mem(buf_in, rx_buf_released, BLK_STEREO_SIZE_OCTETS);
+
+		/* Get first available audio block */
+		ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void *)&rx_audio_block,
+							 K_NO_WAIT);
 		/* If RX FIFO is filled up */
 		if (ret == -ENOMEM) {
-			void *data;
-			size_t size;
+			struct audio_data *stale_i2s_data;
+			size_t stale_i2s_data_size;
 
 			if (ret != prev_ret) {
 				LOG_WRN("I2S RX overrun. Single msg");
 				prev_ret = ret;
 			}
 
-			ret = data_fifo_pointer_last_filled_get(ctrl_blk.in.fifo, &data, &size,
-								K_NO_WAIT);
+			ret = data_fifo_pointer_last_filled_get(ctrl_blk.in.fifo,
+								(void *)&stale_i2s_data,
+								&stale_i2s_data_size, K_NO_WAIT);
 			ERR_CHK(ret);
 
-			data_fifo_block_free(ctrl_blk.in.fifo, data);
+			struct net_buf *buf = stale_i2s_data->data;
+
+			net_buf_unref(buf);
+			data_fifo_block_free(ctrl_blk.in.fifo, stale_i2s_data);
 
-			ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void **)&rx_buf,
-								 K_NO_WAIT);
+			ret = data_fifo_pointer_first_vacant_get(
+				ctrl_blk.in.fifo, (void *)&rx_audio_block, K_NO_WAIT);
+		} else if (ret == 0 && prev_ret == -ENOMEM) {
+			LOG_WRN("I2S RX continuing stream");
+			prev_ret = ret;
 		}
 
-		ERR_CHK_MSG(ret, "RX failed to get block");
+		rx_audio_block->data = buf_in;
+		rx_audio_block->data_size = BLK_STEREO_SIZE_OCTETS;
+
+		/* Add meta data */
+		rx_audio_block->meta.data_coding = PCM;
+		rx_audio_block->meta.data_len_us = 1000;
+		rx_audio_block->meta.sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ;
+		rx_audio_block->meta.bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS;
+		rx_audio_block->meta.carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS;
+		rx_audio_block->meta.locations =
+			BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT;
+		rx_audio_block->meta.bad_data = false;
+
+		ret = data_fifo_block_lock(ctrl_blk.in.fifo, (void *)&rx_audio_block,
+					   sizeof(struct audio_data));
+		ERR_CHK_MSG(ret, "Unable to lock block RX");
 	}
 
 	/*** Data exchange ***/
-	audio_i2s_set_next_buf(tx_buf, rx_buf);
+	audio_i2s_set_next_buf(tx_buf, rx_buf_released);
 
 	/*** Drift compensation ***/
 	if (ctrl_blk.drift_comp.enabled) {
@@ -743,13 +769,13 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t
 
 static void audio_datapath_i2s_start(void)
 {
-	int ret;
-
 	/* Double buffer I2S */
 	uint8_t *tx_buf_one = NULL;
 	uint8_t *tx_buf_two = NULL;
-	uint32_t *rx_buf_one = NULL;
-	uint32_t *rx_buf_two = NULL;
+
+	/* Buffers used for I2S RX. Used interchangeably by I2S. */
+	static uint32_t rx_buf_0[BLK_STEREO_SIZE_OCTETS];
+	static uint32_t rx_buf_1[BLK_STEREO_SIZE_OCTETS];
 
 	/* TX */
 	if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == HEADSET)) {
@@ -762,27 +788,9 @@ static void audio_datapath_i2s_start(void)
 				     .fifo[ctrl_blk.out.cons_blk_idx * BLK_STEREO_NUM_SAMPS];
 	}
 
-	/* RX */
-	if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == GATEWAY)) {
-		uint32_t alloced_cnt;
-		uint32_t locked_cnt;
-
-		ret = data_fifo_num_used_get(ctrl_blk.in.fifo, &alloced_cnt, &locked_cnt);
-		if (alloced_cnt || locked_cnt || ret) {
-			ERR_CHK_MSG(-ENOMEM, "FIFO is not empty!");
-		}
-
-		ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void **)&rx_buf_one,
-							 K_NO_WAIT);
-		ERR_CHK_MSG(ret, "RX failed to get block");
-		ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void **)&rx_buf_two,
-							 K_NO_WAIT);
-		ERR_CHK_MSG(ret, "RX failed to get block");
-	}
-
 	/* Start I2S */
-	audio_i2s_start(tx_buf_one, rx_buf_one);
-	audio_i2s_set_next_buf(tx_buf_two, rx_buf_two);
+	audio_i2s_start(tx_buf_one, rx_buf_0);
+	audio_i2s_set_next_buf(tx_buf_two, rx_buf_1);
 }
 
 static void audio_datapath_i2s_stop(void)
@@ -899,8 +907,7 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
 	*delay_us = ctrl_blk.pres_comp.pres_delay_us;
 }
 
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us)
+void audio_datapath_stream_out(struct audio_data *audio_frame)
 {
 	if (!ctrl_blk.stream_started) {
 		LOG_WRN("Stream not started");
@@ -908,20 +915,24 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 	}
 
 	/*** Check incoming data ***/
+	struct net_buf *audio_buf = audio_frame->data;
 
-	if (!buf) {
+	if (!audio_buf->data) {
 		LOG_ERR("Buffer pointer is NULL");
 	}
 
-	if (sdu_ref_us == ctrl_blk.prev_pres_sdu_ref_us && sdu_ref_us != 0) {
-		LOG_WRN("Duplicate sdu_ref_us (%d) - Dropping audio frame", sdu_ref_us);
+	if (audio_frame->meta.reference_ts_us == ctrl_blk.prev_pres_sdu_ref_us &&
+	    audio_frame->meta.reference_ts_us != 0) {
+		LOG_WRN("Duplicate sdu_ref_us (%d) - Dropping audio frame",
+			audio_frame->meta.reference_ts_us);
 		return;
 	}
 
 	bool sdu_ref_not_consecutive = false;
 
 	if (ctrl_blk.prev_pres_sdu_ref_us) {
-		uint32_t sdu_ref_delta_us = sdu_ref_us - ctrl_blk.prev_pres_sdu_ref_us;
+		uint32_t sdu_ref_delta_us =
+			audio_frame->meta.reference_ts_us - ctrl_blk.prev_pres_sdu_ref_us;
 
 		/* Check if the delta is from two consecutive frames */
 		if (sdu_ref_delta_us <
@@ -935,8 +946,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 					sdu_ref_delta_us);
 
 				/* Estimate sdu_ref_us */
-				sdu_ref_us = ctrl_blk.prev_pres_sdu_ref_us +
-					     CONFIG_AUDIO_FRAME_DURATION_US;
+				audio_frame->meta.reference_ts_us = ctrl_blk.prev_pres_sdu_ref_us +
+								    CONFIG_AUDIO_FRAME_DURATION_US;
 			}
 		} else {
 			LOG_INF("sdu_ref_us not from consecutive frames (diff: %d us)",
@@ -945,11 +956,12 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 		}
 	}
 
-	ctrl_blk.prev_pres_sdu_ref_us = sdu_ref_us;
+	ctrl_blk.prev_pres_sdu_ref_us = audio_frame->meta.reference_ts_us;
 
 	/*** Presentation compensation ***/
 	if (ctrl_blk.pres_comp.enabled) {
-		audio_datapath_presentation_compensation(recv_frame_ts_us, sdu_ref_us,
+		audio_datapath_presentation_compensation(audio_frame->meta.data_rx_ts_us,
+							 audio_frame->meta.reference_ts_us,
 							 sdu_ref_not_consecutive);
 	}
 
@@ -958,7 +970,7 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 	int ret;
 	size_t pcm_size;
 
-	ret = sw_codec_decode(buf, size, bad_frame, &ctrl_blk.decoded_data, &pcm_size);
+	ret = sw_codec_decode(audio_frame, &ctrl_blk.decoded_data, &pcm_size);
 	if (ret) {
 		LOG_WRN("SW codec decode error: %d", ret);
 	}
@@ -1000,7 +1012,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 		}
 
 		/* Record producer block start reference */
-		ctrl_blk.out.prod_blk_ts[out_blk_idx] = recv_frame_ts_us + (i * BLK_PERIOD_US);
+		ctrl_blk.out.prod_blk_ts[out_blk_idx] =
+			audio_frame->meta.data_rx_ts_us + (i * BLK_PERIOD_US);
 
 		out_blk_idx = NEXT_IDX(out_blk_idx);
 	}
diff --git a/applications/nrf5340_audio/src/audio/audio_datapath.h b/applications/nrf5340_audio/src/audio/audio_datapath.h
index 36ad0f552880..46f4dc7db686 100644
--- a/applications/nrf5340_audio/src/audio/audio_datapath.h
+++ b/applications/nrf5340_audio/src/audio/audio_datapath.h
@@ -13,6 +13,7 @@
 #include <data_fifo.h>
 
 #include "sw_codec_select.h"
+#include "audio_defines.h"
 
 /**
  * @brief Mixes a tone into the I2S TX stream
@@ -53,14 +54,9 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us);
  *       and processed before being outputted over I2S. The audio is synchronized
  *       using sdu_ref_us
  *
- * @param buf Pointer to audio data frame
- * @param size Size of audio data frame in bytes
- * @param sdu_ref_us ISO timestamp reference from BLE controller
- * @param bad_frame Indicating if the audio frame is bad or not
- * @param recv_frame_ts_us Timestamp of when audio frame was received
+ * @param audio_frame Pointer to the audio data frame to be processed
  */
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us);
+void audio_datapath_stream_out(struct audio_data *audio_frame);
 
 /**
  * @brief Start the audio datapath module
diff --git a/applications/nrf5340_audio/src/audio/audio_system.c b/applications/nrf5340_audio/src/audio/audio_system.c
index fd04013641a3..bf040dadfac3 100644
--- a/applications/nrf5340_audio/src/audio/audio_system.c
+++ b/applications/nrf5340_audio/src/audio/audio_system.c
@@ -8,6 +8,7 @@
 
 #include <zephyr/kernel.h>
 #include <zephyr/shell/shell.h>
+#include <zephyr/net_buf.h>
 #include <data_fifo.h>
 #include <contin_array.h>
 #include <pcm_stream_channel_modifier.h>
@@ -33,7 +34,8 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
 K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
 
 DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
-DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
+DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(fifo_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, 0, NULL);
 
 static K_SEM_DEFINE(sem_encoder_start, 0, 1);
 
@@ -115,18 +117,22 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
 		/* Get PCM data from I2S */
 		/* Since one audio frame is divided into a number of
@@ -134,16 +140,45 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 		 * blocks before copying it to a continuous area of memory
 		 * before sending it to the encoder
 		 */
-		for (int i = 0; i < CONFIG_FIFO_FRAME_SPLIT_NUM; i++) {
-			ret = data_fifo_pointer_last_filled_get(&fifo_rx, &tmp_pcm_raw_data[i],
+		struct audio_data *audio_block = NULL;
+
+		ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void *)&audio_block,
+							&pcm_block_size, K_FOREVER);
+		ERR_CHK(ret);
+
+		struct net_buf *block_buf = audio_block->data;
+
+		/* Copy metadata from the first block */
+		memcpy(&audio_frame, audio_block, sizeof(struct audio_data));
+
+		/* Extract the data from the block */
+		net_buf_add_mem(frame_buf, block_buf->data, block_buf->len);
+
+		/* Free the block */
+		net_buf_unref(block_buf);
+		data_fifo_block_free(&fifo_rx, audio_block);
+
+		/* Loop until we have a full frame */
+		while (audio_frame.meta.data_len_us < CONFIG_AUDIO_FRAME_DURATION_US) {
+			ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void *)&audio_block,
 								&pcm_block_size, K_FOREVER);
 			ERR_CHK(ret);
-			memcpy(pcm_raw_data + (i * BLOCK_SIZE_BYTES), tmp_pcm_raw_data[i],
-			       pcm_block_size);
 
-			data_fifo_block_free(&fifo_rx, tmp_pcm_raw_data[i]);
+			block_buf = audio_block->data;
+
+			/* Extract the data from the block */
+			net_buf_add_mem(frame_buf, block_buf->data, block_buf->len);
+			audio_frame.meta.data_len_us += audio_block->meta.data_len_us;
+
+			/* Free the block */
+			net_buf_unref(block_buf);
+			data_fifo_block_free(&fifo_rx, audio_block);
 		}
 
+		/* Update metadata to reflect the full frame */
+		audio_frame.data = frame_buf;
+		audio_frame.data_size = frame_buf->len;
+
 		if (sw_codec_cfg.encoder.enabled) {
 			if (test_tone_size) {
 				/* Test tone takes over audio stream */
@@ -160,9 +195,7 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 				ERR_CHK(ret);
 			}
 
-			ret = sw_codec_encode(pcm_raw_data, FRAME_SIZE_BYTES, &encoded_data,
-					      &encoded_data_size);
-
+			ret = sw_codec_encode(&audio_frame);
 			ERR_CHK_MSG(ret, "Encode failed");
 		}
 
@@ -179,8 +212,8 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 		}
 
 		if (sw_codec_cfg.encoder.enabled) {
-			streamctrl_send(encoded_data, encoded_data_size,
-					sw_codec_cfg.encoder.num_ch);
+			streamctrl_send(&audio_frame);
+			net_buf_unref(frame_buf);
 		}
 		STACK_USAGE_PRINT("encoder_thread", &encoder_thread_data);
 	}
@@ -282,7 +315,7 @@ int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bi
 }
 
 /* This function is only used on gateway using USB as audio source and bidirectional stream */
-int audio_system_decode(void const *const encoded_data, size_t encoded_data_size, bool bad_frame)
+int audio_system_decode(struct audio_data *audio_frame)
 {
 	int ret;
 	uint32_t blocks_alloced_num;
@@ -332,8 +365,7 @@ int audio_system_decode(void const *const encoded_data, size_t encoded_data_size
 		}
 	}
 
-	ret = sw_codec_decode(encoded_data, encoded_data_size, bad_frame, &pcm_raw_data,
-			      &pcm_block_size);
+	ret = sw_codec_decode(audio_frame, &pcm_raw_data, &pcm_block_size);
 	if (ret) {
 		LOG_ERR("Failed to decode");
 		return ret;
diff --git a/applications/nrf5340_audio/src/audio/audio_system.h b/applications/nrf5340_audio/src/audio/audio_system.h
index ba6bebf516ee..f8646b7a22d4 100644
--- a/applications/nrf5340_audio/src/audio/audio_system.h
+++ b/applications/nrf5340_audio/src/audio/audio_system.h
@@ -11,6 +11,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "audio_defines.h"
+
 #define VALUE_NOT_SET 0
 
 /**
@@ -66,13 +68,11 @@ int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bi
 /**
  * @brief	Decode data and then add it to TX FIFO buffer.
  *
- * @param[in]	encoded_data		Pointer to encoded data.
- * @param[in]	encoded_data_size	Size of encoded data.
- * @param[in]	bad_frame		Indication on missed or incomplete frame.
+ * @param[in]	audio_frame	Pointer to the audio data.
  *
  * @return	0 on success, error otherwise.
  */
-int audio_system_decode(void const *const encoded_data, size_t encoded_data_size, bool bad_frame);
+int audio_system_decode(struct audio_data *audio_frame);
 
 /**
  * @brief	Initialize and start both HW and SW audio codec.
diff --git a/applications/nrf5340_audio/src/audio/le_audio_rx.c b/applications/nrf5340_audio/src/audio/le_audio_rx.c
index 8c7c93701571..f326008e82bd 100644
--- a/applications/nrf5340_audio/src/audio/le_audio_rx.c
+++ b/applications/nrf5340_audio/src/audio/le_audio_rx.c
@@ -4,30 +4,25 @@
  * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
  */
 
+#include "le_audio_rx.h"
+
 #include <zephyr/kernel.h>
 #include <nrfx_clock.h>
+#include <zephyr/net_buf.h>
 
 #include "streamctrl.h"
 #include "audio_datapath.h"
 #include "macros_common.h"
 #include "audio_system.h"
 #include "audio_sync_timer.h"
+#include "audio_defines.h"
 
 #include <zephyr/logging/log.h>
 LOG_MODULE_REGISTER(le_audio_rx, CONFIG_LE_AUDIO_RX_LOG_LEVEL);
 
-struct ble_iso_data {
-	uint8_t data[CONFIG_BT_ISO_RX_MTU];
-	size_t data_size;
-	bool bad_frame;
-	uint32_t sdu_ref;
-	uint32_t recv_frame_ts;
-} __packed;
-
 struct rx_stats {
 	uint32_t recv_cnt;
 	uint32_t bad_frame_cnt;
-	uint32_t data_size_mismatch_cnt;
 };
 
 static bool initialized;
@@ -35,16 +30,16 @@ static struct k_thread audio_datapath_thread_data;
 static k_tid_t audio_datapath_thread_id;
 K_THREAD_STACK_DEFINE(audio_datapath_thread_stack, CONFIG_AUDIO_DATAPATH_STACK_SIZE);
 
-DATA_FIFO_DEFINE(ble_fifo_rx, CONFIG_BUF_BLE_RX_PACKET_NUM, WB_UP(sizeof(struct ble_iso_data)));
+DATA_FIFO_DEFINE(ble_fifo_rx, CONFIG_BUF_BLE_RX_PACKET_NUM, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(ble_rx_pool, CONFIG_BUF_BLE_RX_PACKET_NUM, CONFIG_BT_ISO_RX_MTU, 0, NULL);
 
 /* Callback for handling ISO RX */
-void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, bool bad_frame,
-			      uint32_t sdu_ref, enum audio_channel channel_index,
-			      size_t desired_data_size)
+void le_audio_rx_data_handler(struct audio_data *audio_frame, uint8_t channel_index)
 {
 	int ret;
 	uint32_t blocks_alloced_num, blocks_locked_num;
-	struct ble_iso_data *iso_received = NULL;
+	struct audio_data *audio_frame_received = NULL;
+	struct net_buf *audio_buf;
 	static struct rx_stats rx_stats[AUDIO_CH_NUM];
 	static uint32_t num_overruns;
 	static uint32_t num_thrown;
@@ -54,27 +49,18 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 	}
 
 	/* Capture timestamp of when audio frame is received */
-	uint32_t recv_frame_ts = audio_sync_timer_capture();
+	audio_frame->meta.data_rx_ts_us = audio_sync_timer_capture();
 
 	rx_stats[channel_index].recv_cnt++;
 
-	if (data_size != desired_data_size) {
-		/* A valid frame should always be equal to desired_data_size, set bad_frame
-		 * if that is not the case
-		 */
-		bad_frame = true;
-		rx_stats[channel_index].data_size_mismatch_cnt++;
-	}
-
-	if (bad_frame) {
+	if (audio_frame->meta.bad_data) {
 		rx_stats[channel_index].bad_frame_cnt++;
 	}
 
 	if ((rx_stats[channel_index].recv_cnt % 100) == 0 && rx_stats[channel_index].recv_cnt) {
 		/* NOTE: The string below is used by the Nordic CI system */
-		LOG_DBG("ISO RX SDUs: Ch: %d Total: %d Bad: %d Size mismatch %d", channel_index,
-			rx_stats[channel_index].recv_cnt, rx_stats[channel_index].bad_frame_cnt,
-			rx_stats[channel_index].data_size_mismatch_cnt);
+		LOG_DBG("ISO RX SDUs: Ch: %d Total: %d Bad: %d", channel_index,
+			rx_stats[channel_index].recv_cnt, rx_stats[channel_index].bad_frame_cnt);
 	}
 
 	if (stream_state_get() != STATE_STREAMING) {
@@ -87,8 +73,8 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 		return;
 	}
 
-	if (channel_index != AUDIO_CH_L && (CONFIG_AUDIO_DEV == GATEWAY)) {
-		/* Only left channel RX data in use on gateway */
+	if (channel_index == 0 && (CONFIG_AUDIO_DEV == GATEWAY)) {
+		/* Only the first device will be used as mic input on gateway */
 		return;
 	}
 
@@ -97,8 +83,7 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 
 	if (blocks_alloced_num >= CONFIG_BUF_BLE_RX_PACKET_NUM) {
 		/* FIFO buffer is full, swap out oldest frame for a new one */
-
-		void *stale_data;
+		struct audio_data *stale_audio_frame;
 		size_t stale_size;
 		num_overruns++;
 
@@ -106,30 +91,36 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 			LOG_WRN("BLE ISO RX overrun: Num: %d", num_overruns);
 		}
 
-		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, &stale_data, &stale_size,
-							K_NO_WAIT);
+		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&stale_audio_frame,
+							&stale_size, K_NO_WAIT);
 		ERR_CHK(ret);
 
-		data_fifo_block_free(&ble_fifo_rx, stale_data);
+		struct net_buf *stale_buf = stale_audio_frame->data;
+
+		net_buf_unref(stale_buf);
+		data_fifo_block_free(&ble_fifo_rx, stale_audio_frame);
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(&ble_fifo_rx, (void *)&iso_received, K_NO_WAIT);
+	ret = data_fifo_pointer_first_vacant_get(&ble_fifo_rx, (void *)&audio_frame_received,
+						 K_NO_WAIT);
+
+	memcpy(audio_frame_received, audio_frame, sizeof(struct audio_data));
 	ERR_CHK_MSG(ret, "Unable to get FIFO pointer");
 
-	if (data_size > ARRAY_SIZE(iso_received->data)) {
-		ERR_CHK_MSG(-ENOMEM, "Data size too large for buffer");
+	audio_buf = net_buf_alloc(&ble_rx_pool, K_NO_WAIT);
+	if (audio_buf == NULL) {
+		LOG_WRN("Out of RX buffers");
 		return;
 	}
 
-	memcpy(iso_received->data, p_data, data_size);
+	if (audio_frame->data_size && !audio_frame->meta.bad_data) {
+		net_buf_add_mem(audio_buf, audio_frame->data, audio_frame->data_size);
+	}
 
-	iso_received->bad_frame = bad_frame;
-	iso_received->data_size = data_size;
-	iso_received->sdu_ref = sdu_ref;
-	iso_received->recv_frame_ts = recv_frame_ts;
+	audio_frame_received->data = audio_buf;
 
-	ret = data_fifo_block_lock(&ble_fifo_rx, (void *)&iso_received,
-				   sizeof(struct ble_iso_data));
+	ret = data_fifo_block_lock(&ble_fifo_rx, (void *)&audio_frame_received,
+				   sizeof(struct audio_data));
 	ERR_CHK_MSG(ret, "Failed to lock block");
 }
 
@@ -139,24 +130,25 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 static void audio_datapath_thread(void *dummy1, void *dummy2, void *dummy3)
 {
 	int ret;
-	struct ble_iso_data *iso_received = NULL;
-	size_t iso_received_size;
+	struct audio_data *audio_frame = NULL;
+	size_t audio_frame_recv_size;
 
 	while (1) {
-		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&iso_received,
-							&iso_received_size, K_FOREVER);
+		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&audio_frame,
+							&audio_frame_recv_size, K_FOREVER);
 		ERR_CHK(ret);
 
 		if (IS_ENABLED(CONFIG_AUDIO_SOURCE_USB) && (CONFIG_AUDIO_DEV == GATEWAY)) {
-			ret = audio_system_decode(iso_received->data, iso_received->data_size,
-						  iso_received->bad_frame);
+			ret = audio_system_decode(audio_frame);
 			ERR_CHK(ret);
 		} else {
-			audio_datapath_stream_out(iso_received->data, iso_received->data_size,
-						  iso_received->sdu_ref, iso_received->bad_frame,
-						  iso_received->recv_frame_ts);
+			audio_datapath_stream_out(audio_frame);
 		}
-		data_fifo_block_free(&ble_fifo_rx, (void *)iso_received);
+
+		struct net_buf *audio_buf = audio_frame->data;
+
+		net_buf_unref(audio_buf);
+		data_fifo_block_free(&ble_fifo_rx, (void *)audio_frame);
 
 		STACK_USAGE_PRINT("audio_datapath_thread", &audio_datapath_thread_data);
 	}
diff --git a/applications/nrf5340_audio/src/audio/le_audio_rx.h b/applications/nrf5340_audio/src/audio/le_audio_rx.h
index b50e10c7c82c..91730738478f 100644
--- a/applications/nrf5340_audio/src/audio/le_audio_rx.h
+++ b/applications/nrf5340_audio/src/audio/le_audio_rx.h
@@ -7,19 +7,16 @@
 #ifndef _LE_AUDIO_RX_H_
 #define _LE_AUDIO_RX_H_
 
+#include <zephyr/bluetooth/audio/audio.h>
+#include <audio_defines.h>
+
 /**
  * @brief Data handler when ISO data has been received.
  *
- * @param[in] p_data		Pointer to the received data.
- * @param[in] data_size		Size of the received data.
- * @param[in] bad_frame		Bad frame flag. (I.e. set for missed ISO data).
- * @param[in] sdu_ref		SDU reference timestamp.
+ * @param[in] audio_frame	Pointer to the received data.
  * @param[in] channel_index	Which channel is received.
- * @param[in] desired_data_size	The expected data size.
  */
-void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, bool bad_frame,
-			      uint32_t sdu_ref, enum audio_channel channel_index,
-			      size_t desired_data_size);
+void le_audio_rx_data_handler(struct audio_data *audio_frame, uint8_t channel_index);
 
 /**
  * @brief Initialize the receive audio path.
diff --git a/applications/nrf5340_audio/src/audio/streamctrl.h b/applications/nrf5340_audio/src/audio/streamctrl.h
index d96b7c91f4a5..12676c8354f2 100644
--- a/applications/nrf5340_audio/src/audio/streamctrl.h
+++ b/applications/nrf5340_audio/src/audio/streamctrl.h
@@ -9,6 +9,7 @@
 
 #include <stddef.h>
 #include <zephyr/kernel.h>
+#include <audio_defines.h>
 
 /* State machine states for peer or stream. */
 enum stream_state {
@@ -26,10 +27,8 @@ uint8_t stream_state_get(void);
 /**
  * @brief Send audio data over the stream.
  *
- * @param data		Data to send.
- * @param size		Size of data.
- * @param num_ch	Number of audio channels.
+ * @param audio_frame		Pointer to the audio data to send.
  */
-void streamctrl_send(void const *const data, size_t size, uint8_t num_ch);
+void streamctrl_send(struct audio_data const *const audio_frame);
 
 #endif /* _STREAMCTRL_H_ */
diff --git a/applications/nrf5340_audio/src/audio/sw_codec_select.c b/applications/nrf5340_audio/src/audio/sw_codec_select.c
index 5b9387189864..145c489b510b 100644
--- a/applications/nrf5340_audio/src/audio/sw_codec_select.c
+++ b/applications/nrf5340_audio/src/audio/sw_codec_select.c
@@ -83,20 +83,22 @@ bool sw_codec_is_initialized(void)
 	return m_config.initialized;
 }
 
-int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, size_t *encoded_size)
+int sw_codec_encode(struct audio_data *audio_frame)
 {
 	int ret;
 
 	/* Temp storage for split stereo PCM signal */
 	char pcm_data_mono_system_sample_rate[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0};
 	/* Make sure we have enough space for two frames (stereo) */
-	static uint8_t m_encoded_data[ENC_MAX_FRAME_SIZE * AUDIO_CH_NUM];
+	uint8_t m_encoded_data[ENC_MAX_FRAME_SIZE * AUDIO_CH_NUM];
 
 	char pcm_data_mono_converted_buf[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0};
 
 	size_t pcm_block_size_mono_system_sample_rate;
 	size_t pcm_block_size_mono;
 
+	struct net_buf *audio_buf = audio_frame->data;
+
 	if (!m_config.encoder.enabled) {
 		LOG_ERR("Encoder has not been initialized");
 		return -ENXIO;
@@ -111,7 +113,8 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 		/* Since LC3 is a single channel codec, we must split the
 		 * stereo PCM stream
 		 */
-		ret = pscm_two_channel_split(pcm_data, pcm_size, CONFIG_AUDIO_BIT_DEPTH_BITS,
+		ret = pscm_two_channel_split(audio_buf->data, audio_buf->len,
+					     CONFIG_AUDIO_BIT_DEPTH_BITS,
 					     pcm_data_mono_system_sample_rate[AUDIO_CH_L],
 					     pcm_data_mono_system_sample_rate[AUDIO_CH_R],
 					     &pcm_block_size_mono_system_sample_rate);
@@ -142,6 +145,7 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			if (ret) {
 				return ret;
 			}
+			audio_frame->meta.locations = BT_AUDIO_LOCATION_FRONT_LEFT;
 			break;
 		}
 		case SW_CODEC_STEREO: {
@@ -170,9 +174,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
+		audio_frame->data_size = encoded_bytes_written;
 
+		net_buf_remove_mem(audio_buf, audio_buf->len);
+		net_buf_add_mem(audio_buf, m_encoded_data, encoded_bytes_written);
 #endif /* (CONFIG_SW_CODEC_LC3) */
 		break;
 	}
@@ -184,8 +190,8 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 	return 0;
 }
 
-int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool bad_frame,
-		    void **decoded_data, size_t *decoded_size)
+int sw_codec_decode(struct audio_data const *const audio_frame, void **decoded_data,
+		    size_t *decoded_size)
 {
 	if (!m_config.decoder.enabled) {
 		LOG_ERR("Decoder has not been initialized");
@@ -207,17 +213,19 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool
 	case SW_CODEC_LC3: {
 #if (CONFIG_SW_CODEC_LC3)
 		char *pcm_in_data_ptrs[m_config.decoder.channel_mode];
+		struct net_buf *audio_buf = audio_frame->data;
 
 		switch (m_config.decoder.channel_mode) {
 		case SW_CODEC_MONO: {
-			if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
+			if (audio_frame->meta.bad_data &&
+			    IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
 				memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO);
 				decoded_data_size = PCM_NUM_BYTES_MONO;
 			} else {
 				ret = sw_codec_lc3_dec_run(
-					encoded_data, encoded_size, LC3_PCM_NUM_BYTES_MONO, 0,
+					audio_buf->data, audio_buf->len, LC3_PCM_NUM_BYTES_MONO, 0,
 					decoded_data_mono[AUDIO_CH_L],
-					(uint16_t *)&decoded_data_size, bad_frame);
+					(uint16_t *)&decoded_data_size, audio_frame->meta.bad_data);
 				if (ret) {
 					return ret;
 				}
@@ -248,26 +256,28 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool
 			break;
 		}
 		case SW_CODEC_STEREO: {
-			if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
+			if (audio_frame->meta.bad_data &&
+			    IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
 				memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO);
 				memset(decoded_data_mono[AUDIO_CH_R], 0, PCM_NUM_BYTES_MONO);
 				decoded_data_size = PCM_NUM_BYTES_MONO;
 			} else {
 				/* Decode left channel */
-				ret = sw_codec_lc3_dec_run(
-					encoded_data, encoded_size / 2, LC3_PCM_NUM_BYTES_MONO,
-					AUDIO_CH_L, decoded_data_mono[AUDIO_CH_L],
-					(uint16_t *)&decoded_data_size, bad_frame);
+				ret = sw_codec_lc3_dec_run(audio_buf->data, (audio_buf->len / 2),
+							   LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_L,
+							   decoded_data_mono[AUDIO_CH_L],
+							   (uint16_t *)&decoded_data_size,
+							   audio_frame->meta.bad_data);
 				if (ret) {
 					return ret;
 				}
 
 				/* Decode right channel */
 				ret = sw_codec_lc3_dec_run(
-					(encoded_data + (encoded_size / 2)), encoded_size / 2,
-					LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_R,
+					(audio_buf->data + (audio_buf->len / 2)),
+					(audio_buf->len / 2), LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_R,
 					decoded_data_mono[AUDIO_CH_R],
-					(uint16_t *)&decoded_data_size, bad_frame);
+					(uint16_t *)&decoded_data_size, audio_frame->meta.bad_data);
 				if (ret) {
 					return ret;
 				}
diff --git a/applications/nrf5340_audio/src/audio/sw_codec_select.h b/applications/nrf5340_audio/src/audio/sw_codec_select.h
index 3771fa79ae21..558d016f1701 100644
--- a/applications/nrf5340_audio/src/audio/sw_codec_select.h
+++ b/applications/nrf5340_audio/src/audio/sw_codec_select.h
@@ -83,28 +83,22 @@ bool sw_codec_is_initialized(void);
  * @note	Takes in stereo PCM stream, will encode either one or two
  *		channels, based on channel_mode set during init.
  *
- * @param[in]	pcm_data	Pointer to PCM data.
- * @param[in]	pcm_size	Size of PCM data.
- * @param[out]	encoded_data	Pointer to buffer to store encoded data.
- * @param[out]	encoded_size	Size of encoded data.
+ * @param[in]	audio_frame	Pointer to audio data.
  *
  * @return	0 if success, error codes depends on sw_codec selected.
  */
-int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, size_t *encoded_size);
+int sw_codec_encode(struct audio_data *audio_frame);
 
 /**
  * @brief	Decode encoded data and output PCM data.
  *
- * @param[in]	encoded_data	Pointer to encoded data.
- * @param[in]	encoded_size	Size of encoded data.
- * @param[in]	bad_frame	Flag to indicate a missing/bad frame (only LC3).
+ * @param[in]	audio_frame	Pointer to audio data.
  * @param[out]	pcm_data	Pointer to buffer to store decoded PCM data.
  * @param[out]	pcm_size	Size of decoded data.
  *
  * @return	0 if success, error codes depends on sw_codec selected.
  */
-int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool bad_frame,
-		    void **pcm_data, size_t *pcm_size);
+int sw_codec_decode(struct audio_data const *const audio_frame, void **pcm_data, size_t *pcm_size);
 
 /**
  * @brief	Uninitialize the software codec and free the allocated space.
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_sink.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_sink.c
index 312e2c706f63..0c93aef6876a 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_sink.c
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_sink.c
@@ -21,6 +21,7 @@
 #include "macros_common.h"
 #include "zbus_common.h"
 #include "channel_assignment.h"
+#include "audio_defines.h"
 
 #include <zephyr/logging/log.h>
 LOG_MODULE_REGISTER(broadcast_sink, CONFIG_BROADCAST_SINK_LOG_LEVEL);
@@ -331,19 +332,21 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
 			   struct net_buf *buf)
 {
-	bool bad_frame = false;
+	int ret;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	ret = le_audio_frame_create(&audio_frame, stream, info, buf);
+	if (ret) {
+		LOG_ERR("Failed to create RX frame: %d", ret);
+		return;
 	}
 
-	receive_cb(buf->data, buf->len, bad_frame, info->ts, active_stream_index,
-		   active_stream.codec->octets_per_sdu);
+	receive_cb(&audio_frame, active_stream_index);
 }
 
 static struct bt_bap_stream_ops stream_ops = {
@@ -424,6 +427,9 @@ static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *
 		sync_stream_cnt = bis_num;
 		for (int i = 0; i < bis_num; i++) {
 			get_codec_info(&codec_cfg, &audio_codec_info[i]);
+			audio_codec_info[i].id = codec_id.id;
+			audio_codec_info[i].cid = codec_id.cid;
+			audio_codec_info[i].vid = codec_id.vid;
 		}
 
 		ret = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, NULL);
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.c
index 7de33faa55ee..6a97bba465fe 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.c
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.c
@@ -620,7 +620,7 @@ int broadcast_source_id_get(uint8_t big_index, uint32_t *broadcast_id)
 }
 
 int broadcast_source_send(uint8_t big_index, uint8_t subgroup_index,
-			  struct le_audio_encoded_audio enc_audio)
+			  struct audio_data const *const audio_frame)
 {
 	int ret;
 	uint8_t num_active_streams = 0;
@@ -664,7 +664,7 @@ int broadcast_source_send(uint8_t big_index, uint8_t subgroup_index,
 		return -ECANCELED;
 	}
 
-	ret = bt_le_audio_tx_send(tx, num_active_streams, enc_audio);
+	ret = bt_le_audio_tx_send(tx, num_active_streams, audio_frame);
 	if (ret) {
 		return ret;
 	}
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.h
index d13a04fc11e9..458c4b58c92a 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.h
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.h
@@ -224,12 +224,12 @@ int broadcast_source_id_get(uint8_t big_index, uint32_t *broadcast_id);
  *
  * @param[in]	big_index	Index of the Broadcast Isochronous Group (BIG) to broadcast.
  * @param[in]	subgroup_index	Index of the subgroup to broadcast.
- * @param[in]	enc_audio	Encoded audio struct.
+ * @param[in]	audio_frame	Pointer to the audio to send.
  *
  * @return	0 for success, error otherwise.
  */
 int broadcast_source_send(uint8_t big_index, uint8_t subgroup_index,
-			  struct le_audio_encoded_audio enc_audio);
+			  struct audio_data const *const audio_frame);
 
 /**
  * @brief	Disable the LE Audio broadcast (BIS) source.
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
index 41608e608493..3097cb278b07 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
@@ -11,6 +11,7 @@
 #include <zephyr/zbus/zbus.h>
 #include <../subsys/bluetooth/audio/bap_stream.h>
 #include <bluetooth/hci_vs_sdc.h>
+#include <audio_defines.h>
 
 #include "zbus_common.h"
 #include "audio_sync_timer.h"
@@ -188,7 +189,7 @@ static int iso_conn_handle_set(struct bt_bap_stream *bap_stream, uint16_t *iso_c
 }
 
 int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
-			struct le_audio_encoded_audio enc_audio)
+			struct audio_data const *const audio_frame)
 {
 	int ret;
 	size_t data_size_pr_stream = 0;
@@ -201,7 +202,16 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		return -EINVAL;
 	}
 
-	data_size_pr_stream = enc_audio.size / enc_audio.num_ch;
+	/* Get number of channels in the audio frame */
+	uint8_t num_ch = audio_data_num_ch_get(audio_frame);
+
+	if (num_ch == 0 || (audio_frame->data_size % num_ch != 0)) {
+		LOG_ERR("Invalid number (%d) of channels in audio frame (%d)", num_ch,
+			audio_frame->data_size);
+		return -EINVAL;
+	}
+
+	data_size_pr_stream = audio_frame->data_size / num_ch;
 
 	/* When sending ISO data, we always send ts = 0 to the first active transmitting channel.
 	 * The controller will populate with a ts which is fetched using bt_iso_chan_get_tx_sync.
@@ -232,7 +242,7 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 			continue;
 		}
 
-		if (tx[i].audio_channel > enc_audio.num_ch) {
+		if (tx[i].audio_channel > num_ch) {
 			LOG_WRN("Unsupported audio_channel: %d", tx[i].audio_channel);
 			continue;
 		}
@@ -246,7 +256,8 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 
 		if (data_size_pr_stream != LE_AUDIO_SDU_SIZE_OCTETS(bitrate)) {
-			LOG_ERR("The encoded data size does not match the SDU size");
+			LOG_ERR("The encoded data size (%zu) does not match the SDU size (%d)",
+				data_size_pr_stream, LE_AUDIO_SDU_SIZE_OCTETS(bitrate));
 			return -EINVAL;
 		}
 
@@ -257,13 +268,14 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 		common_interval = tx[i].cap_stream->bap_stream.qos->interval;
 
+		struct net_buf *audio_buf = audio_frame->data;
 		/* Check if same audio is sent to all channels */
-		if (enc_audio.num_ch == 1) {
-			ret = iso_stream_send(enc_audio.data, data_size_pr_stream, tx[i].cap_stream,
-					      tx_info, common_tx_sync_ts_us);
+		if (num_ch == 1) {
+			ret = iso_stream_send(audio_buf->data, data_size_pr_stream,
+					      tx[i].cap_stream, tx_info, common_tx_sync_ts_us);
 		} else {
 			ret = iso_stream_send(
-				&enc_audio.data[(data_size_pr_stream * tx[i].audio_channel)],
+				&audio_buf->data[(data_size_pr_stream * tx[i].audio_channel)],
 				data_size_pr_stream, tx[i].cap_stream, tx_info,
 				common_tx_sync_ts_us);
 		}
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.h
index 51de67a04f6b..a120d817de6a 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.h
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.h
@@ -27,12 +27,12 @@ struct le_audio_tx_info {
  *
  * @param[in]	tx		Pointer to an array of le_audio_tx_info elements.
  * @param[in]	num_tx		Number of elements in @p tx.
- * @param[in]	enc_audio	Encoded audio data.
+ * @param[in]	audio_frame	Pointer to the encoded audio data.
  *
  * @return	0 if successful, error otherwise.
  */
 int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
-			struct le_audio_encoded_audio enc_audio);
+			struct audio_data const *const audio_frame);
 
 /**
  * @brief	Initializes a stream. Must be called when a TX stream is started.
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c
index 50a8d5edda35..009d05ea5619 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c
@@ -12,6 +12,41 @@
 #include <zephyr/logging/log.h>
 LOG_MODULE_REGISTER(le_audio, CONFIG_BLE_LOG_LEVEL);
 
+int le_audio_frame_create(struct audio_data *audio_frame, const struct bt_bap_stream *stream,
+			  const struct bt_iso_recv_info *info, const struct net_buf *buf)
+{
+	int ret;
+
+	/* Populate the audio frame structure */
+	audio_frame->data = buf->data;
+	audio_frame->data_size = buf->len;
+	audio_frame->meta.bad_data = false;
+	audio_frame->meta.reference_ts_us = info->ts;
+	le_audio_freq_hz_get(stream->codec_cfg, &audio_frame->meta.sample_rate_hz);
+	le_audio_duration_us_get(stream->codec_cfg, &audio_frame->meta.data_len_us);
+
+	ret = bt_audio_codec_cfg_get_chan_allocation(stream->codec_cfg,
+						     &audio_frame->meta.locations, true);
+	if (ret < 0) {
+		LOG_ERR("Failed to get channel allocation: %d", ret);
+		return ret;
+	}
+
+	if (stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
+		audio_frame->meta.data_coding = LC3;
+	} else {
+		LOG_ERR("Unsupported codec ID: %d", stream->codec_cfg->id);
+		return -EINVAL;
+	}
+
+	if (!(info->flags & BT_ISO_FLAGS_VALID) ||
+	    buf->len != bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg)) {
+		audio_frame->meta.bad_data = true;
+	}
+
+	return 0;
+}
+
 int le_audio_ep_state_get(struct bt_bap_ep *ep, uint8_t *state)
 {
 	int ret;
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h
index d578d5bca598..e1252c9cbf2c 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h
@@ -44,27 +44,10 @@
 /**
  * @brief Callback for receiving Bluetooth LE Audio data.
  *
- * @param	data		Pointer to received data.
- * @param	size		Size of received data.
- * @param	bad_frame	Indicating if the frame is a bad frame or not.
- * @param	sdu_ref		ISO timestamp.
+ * @param	audio_frame	Pointer to audio data struct.
  * @param	channel_index	Audio channel index.
- * @param	desired_size	The expected data size.
  */
-typedef void (*le_audio_receive_cb)(const uint8_t *const data, size_t size, bool bad_frame,
-				    uint32_t sdu_ref, enum audio_channel channel_index,
-				    size_t desired_size);
-
-/**
- * @brief	Encoded audio data and information.
- *
- * @note	Container for SW codec (typically LC3) compressed audio data.
- */
-struct le_audio_encoded_audio {
-	uint8_t const *const data;
-	size_t size;
-	uint8_t num_ch;
-};
+typedef void (*le_audio_receive_cb)(struct audio_data *audio_frame, uint8_t channel_index);
 
 struct stream_index {
 	uint8_t lvl1; /* BIG / CIG */
@@ -72,6 +55,19 @@ struct stream_index {
 	uint8_t lvl3; /* BIS / CIS */
 };
 
+/**
+ * @brief Function to handle the audio frame.
+ *
+ * @param[in] audio_frame	Pointer to the audio frame.
+ * @param[in] stream		Pointer to the stream.
+ * @param[in] info		Pointer to the ISO information.
+ * @param[in] buf		Pointer to the buffer.
+ *
+ * @return 0 if successful, error otherwise.
+ */
+int le_audio_frame_create(struct audio_data *audio_frame, const struct bt_bap_stream *stream,
+			  const struct bt_iso_recv_info *info, const struct net_buf *buf);
+
 /**
  * @brief	Get the current state of an endpoint.
  *
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c
index 29adae3f81d2..f1d7b56c27a7 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c
@@ -1329,26 +1329,28 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec
 			   struct net_buf *buf)
 {
 	int ret;
-	bool bad_frame = false;
-	struct stream_index idx;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	ret = le_audio_frame_create(&audio_frame, stream, info, buf);
+	if (ret) {
+		LOG_ERR("Failed to create RX frame: %d", ret);
+		return;
 	}
 
+	struct stream_index idx;
+
 	ret = device_index_get(stream->conn, &idx);
 	if (ret) {
 		LOG_ERR("Device index not found");
 		return;
 	}
 
-	receive_cb(buf->data, buf->len, bad_frame, info->ts, idx.lvl3,
-		   bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg));
+	receive_cb(&audio_frame, idx.lvl3);
 }
 #endif /* (CONFIG_BT_AUDIO_RX) */
 
@@ -1748,7 +1750,7 @@ int unicast_client_stop(uint8_t cig_index)
 	return 0;
 }
 
-int unicast_client_send(uint8_t cig_index, struct le_audio_encoded_audio enc_audio)
+int unicast_client_send(uint8_t cig_index, struct audio_data const *const audio_frame)
 {
 #if (CONFIG_BT_AUDIO_TX)
 	int ret;
@@ -1793,7 +1795,7 @@ int unicast_client_send(uint8_t cig_index, struct le_audio_encoded_audio enc_aud
 		return -ECANCELED;
 	}
 
-	ret = bt_le_audio_tx_send(tx, num_active_streams, enc_audio);
+	ret = bt_le_audio_tx_send(tx, num_active_streams, audio_frame);
 	if (ret) {
 		return ret;
 	}
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h
index 834d19cd4d65..2aa3235b9baf 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h
@@ -114,11 +114,11 @@ int unicast_client_stop(uint8_t cig_index);
  * @brief	Send encoded audio using the Bluetooth LE Audio unicast.
  *
  * @param[in]	cig_index	Index of the Connected Isochronous Group (CIG) to send to.
- * @param[in]	enc_audio	Encoded audio struct.
+ * @param[in]	audio_frame	Pointer to the audio to send.
  *
  * @return	0 for success, error otherwise.
  */
-int unicast_client_send(uint8_t cig_index, struct le_audio_encoded_audio enc_audio);
+int unicast_client_send(uint8_t cig_index, struct audio_data const *const audio_frame);
 
 /**
  * @brief       Disable the Bluetooth LE Audio unicast (CIS) client.
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
index e5f8a6c17b0b..407f23667826 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
@@ -337,19 +337,21 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = {
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
 			   struct net_buf *buf)
 {
-	bool bad_frame = false;
+	int ret;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	ret = le_audio_frame_create(&audio_frame, stream, info, buf);
+	if (ret) {
+		LOG_ERR("Failed to create RX frame: %d", ret);
+		return;
 	}
 
-	receive_cb(buf->data, buf->len, bad_frame, info->ts, 0,
-		   bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg));
+	receive_cb(&audio_frame, 0);
 }
 #endif /* (CONFIG_BT_AUDIO_RX) */
 
@@ -601,7 +603,7 @@ int unicast_server_adv_populate(struct bt_data *adv_buf, uint8_t adv_buf_vacant)
 	return adv_buf_cnt;
 }
 
-int unicast_server_send(struct le_audio_encoded_audio enc_audio)
+int unicast_server_send(struct audio_data const *const audio_frame)
 {
 #if (CONFIG_BT_AUDIO_TX)
 	int ret;
@@ -629,7 +631,7 @@ int unicast_server_send(struct le_audio_encoded_audio enc_audio)
 		num_active_streams++;
 	}
 
-	ret = bt_le_audio_tx_send(tx, num_active_streams, enc_audio);
+	ret = bt_le_audio_tx_send(tx, num_active_streams, audio_frame);
 	if (ret) {
 		return ret;
 	}
diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h
index a6f633c5bc4e..7f1378ebcfd7 100644
--- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h
+++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h
@@ -54,11 +54,11 @@ int unicast_server_adv_populate(struct bt_data *adv_buf, uint8_t adv_buf_vacant)
 /**
  * @brief	Send data from the LE Audio unicast (CIS) server, if configured as a source.
  *
- * @param[in]	enc_audio	Encoded audio struct.
+ * @param[in]	audio_frame	Pointer to the audio data.
  *
  * @return	0 for success, error otherwise.
  */
-int unicast_server_send(struct le_audio_encoded_audio enc_audio);
+int unicast_server_send(struct audio_data const *const audio_frame);
 
 /**
  * @brief	Disable the Bluetooth LE Audio unicast (CIS) server.
diff --git a/applications/nrf5340_audio/src/modules/audio_usb.c b/applications/nrf5340_audio/src/modules/audio_usb.c
index 2b8b330f23dd..4722be6fc2df 100644
--- a/applications/nrf5340_audio/src/modules/audio_usb.c
+++ b/applications/nrf5340_audio/src/modules/audio_usb.c
@@ -10,6 +10,7 @@
 #include <zephyr/usb/usb_device.h>
 #include <zephyr/usb/class/usb_audio.h>
 #include <data_fifo.h>
+#include <audio_defines.h>
 
 #include "macros_common.h"
 
@@ -24,6 +25,8 @@ static struct data_fifo *fifo_rx;
 
 NET_BUF_POOL_FIXED_DEFINE(pool_out, CONFIG_FIFO_FRAME_SPLIT_NUM, USB_FRAME_SIZE_STEREO, 8,
 			  net_buf_destroy);
+NET_BUF_POOL_FIXED_DEFINE(pool_in, CONFIG_FIFO_FRAME_SPLIT_NUM, USB_FRAME_SIZE_STEREO, 8,
+			  net_buf_destroy);
 
 static uint32_t rx_num_overruns;
 static bool rx_first_data;
@@ -42,9 +45,9 @@ static void data_write(const struct device *dev)
 
 	void *data_out;
 	size_t data_out_size;
-	struct net_buf *buf_out;
+	struct net_buf *audio_buf_out;
 
-	buf_out = net_buf_alloc(&pool_out, K_NO_WAIT);
+	audio_buf_out = net_buf_alloc(&pool_out, K_NO_WAIT);
 
 	ret = data_fifo_pointer_last_filled_get(fifo_tx, &data_out, &data_out_size, K_NO_WAIT);
 	if (ret) {
@@ -52,19 +55,20 @@ static void data_write(const struct device *dev)
 		if ((tx_num_underruns % 100) == 1) {
 			LOG_WRN("USB TX underrun. Num: %d", tx_num_underruns);
 		}
-		net_buf_unref(buf_out);
+		net_buf_unref(audio_buf_out);
 
 		return;
 	}
 
-	memcpy(buf_out->data, data_out, data_out_size);
+	memcpy(audio_buf_out->data, data_out, data_out_size);
 	data_fifo_block_free(fifo_tx, data_out);
 
 	if (data_out_size == usb_audio_get_in_frame_size(dev)) {
-		ret = usb_audio_send(dev, buf_out, data_out_size);
+		ret = usb_audio_send(dev, audio_buf_out, data_out_size);
 		if (ret) {
 			LOG_WRN("USB TX failed, ret: %d", ret);
-			net_buf_unref(buf_out);
+			net_buf_unref(audio_buf_out);
+			return;
 		}
 
 	} else {
@@ -81,7 +85,8 @@ static void data_write(const struct device *dev)
 static void data_received(const struct device *dev, struct net_buf *buffer, size_t size)
 {
 	int ret;
-	void *data_in;
+	struct audio_data *audio_block = NULL;
+	struct net_buf *audio_buf_in;
 
 	if (fifo_rx == NULL) {
 		/* Throwing away data */
@@ -101,34 +106,57 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size
 		return;
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+	audio_buf_in = net_buf_alloc(&pool_in, K_NO_WAIT);
+	if (audio_buf_in == NULL) {
+		LOG_WRN("Out of RX buffers");
+		net_buf_unref(buffer);
+		return;
+	}
+
+	/* Copy data to RX FIFO */
+	net_buf_add_mem(audio_buf_in, buffer->data, size);
+	net_buf_unref(buffer);
 
-	/* RX FIFO can fill up due to retransmissions or disconnect */
+	ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
+
+	/* RX FIFO can fill up due to re-transmissions or disconnect */
 	if (ret == -ENOMEM) {
-		void *temp;
-		size_t temp_size;
+		struct audio_data *stale_usb_data;
+		size_t stale_size;
 
 		rx_num_overruns++;
 		if ((rx_num_overruns % 100) == 1) {
 			LOG_WRN("USB RX overrun. Num: %d", rx_num_overruns);
 		}
 
-		ret = data_fifo_pointer_last_filled_get(fifo_rx, &temp, &temp_size, K_NO_WAIT);
+		ret = data_fifo_pointer_last_filled_get(fifo_rx, (void *)&stale_usb_data,
+							&stale_size, K_NO_WAIT);
 		ERR_CHK(ret);
 
-		data_fifo_block_free(fifo_rx, temp);
+		struct net_buf *buf = stale_usb_data->data;
+
+		net_buf_unref(buf);
+		data_fifo_block_free(fifo_rx, stale_usb_data);
 
-		ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+		ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
 	}
 
 	ERR_CHK_MSG(ret, "RX failed to get block");
 
-	memcpy(data_in, buffer->data, size);
+	audio_block->data = audio_buf_in;
+	audio_block->data_size = size;
 
-	ret = data_fifo_block_lock(fifo_rx, &data_in, size);
-	ERR_CHK_MSG(ret, "Failed to lock block");
+	/* Add meta data */
+	audio_block->meta.data_coding = PCM;
+	audio_block->meta.data_len_us = 1000;
+	audio_block->meta.sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ;
+	audio_block->meta.bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS;
+	audio_block->meta.carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS;
+	audio_block->meta.locations = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT;
+	audio_block->meta.bad_data = false;
 
-	net_buf_unref(buffer);
+	ret = data_fifo_block_lock(fifo_rx, (void *)&audio_block, sizeof(struct audio_data));
+	ERR_CHK_MSG(ret, "Failed to lock block");
 
 	if (!rx_first_data) {
 		LOG_INF("USB RX first data received.");
diff --git a/applications/nrf5340_audio/unicast_client/main.c b/applications/nrf5340_audio/unicast_client/main.c
index e5564575e1a0..46826b0936fe 100644
--- a/applications/nrf5340_audio/unicast_client/main.c
+++ b/applications/nrf5340_audio/unicast_client/main.c
@@ -530,15 +530,13 @@ uint8_t stream_state_get(void)
 	return strm_state;
 }
 
-void streamctrl_send(void const *const data, size_t size, uint8_t num_ch)
+void streamctrl_send(struct audio_data const *const audio_frame)
 {
 	int ret;
 	static int prev_ret;
 
-	struct le_audio_encoded_audio enc_audio = {.data = data, .size = size, .num_ch = num_ch};
-
 	if (strm_state == STATE_STREAMING) {
-		ret = unicast_client_send(0, enc_audio);
+		ret = unicast_client_send(0, audio_frame);
 
 		if (ret != 0 && ret != prev_ret) {
 			if (ret == -ECANCELED) {
diff --git a/applications/nrf5340_audio/unicast_server/main.c b/applications/nrf5340_audio/unicast_server/main.c
index e122a390b501..6907d982d5a7 100644
--- a/applications/nrf5340_audio/unicast_server/main.c
+++ b/applications/nrf5340_audio/unicast_server/main.c
@@ -506,15 +506,13 @@ uint8_t stream_state_get(void)
 	return strm_state;
 }
 
-void streamctrl_send(void const *const data, size_t size, uint8_t num_ch)
+void streamctrl_send(struct audio_data const *const audio_frame)
 {
 	int ret;
 	static int prev_ret;
 
-	struct le_audio_encoded_audio enc_audio = {.data = data, .size = size, .num_ch = num_ch};
-
 	if (strm_state == STATE_STREAMING) {
-		ret = unicast_server_send(enc_audio);
+		ret = unicast_server_send(audio_frame);
 
 		if (ret != 0 && ret != prev_ret) {
 			if (ret == -ECANCELED) {
diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst
index 8184b1634a1b..f80c754e502a 100644
--- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst
+++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst
@@ -208,6 +208,8 @@ nRF5340 Audio
 
   * The application to use the ``NFC.TAGHEADER0`` value from FICR as the broadcast ID instead of using a random ID.
   * The application to change from Newlib to Picolib to align with |NCS| and Zephyr.
+  * The application to use an audio struct that contains meta data about the audio stream.
+
 
 nRF Desktop
 -----------
diff --git a/include/audio_defines.h b/include/audio_defines.h
index 2e554611a850..f40cf39c885c 100644
--- a/include/audio_defines.h
+++ b/include/audio_defines.h
@@ -13,6 +13,7 @@
 
 #include <zephyr/types.h>
 #include <stdbool.h>
+#include <zephyr/bluetooth/audio/audio.h>
 
 /**
  * @brief Audio channel assignment values
@@ -102,4 +103,23 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
+{
+	if (audio_frame == NULL) {
+		return 0;
+	}
+
+	return bt_audio_get_chan_count(audio_frame->meta.locations);
+}
+
 #endif /* _AUDIO_DEFINES_H_ */
diff --git a/lib/data_fifo/data_fifo.c b/lib/data_fifo/data_fifo.c
index c0ef1cec683e..5cd18ee8680d 100644
--- a/lib/data_fifo/data_fifo.c
+++ b/lib/data_fifo/data_fifo.c
@@ -59,7 +59,7 @@ int data_fifo_block_lock(struct data_fifo *data_fifo, void **data, size_t size)
 	int ret;
 
 	if (size > data_fifo->block_size_max) {
-		LOG_ERR("Size %zu too big", size);
+		LOG_ERR("Size %zu too big, max: %zu", size, data_fifo->block_size_max);
 		return -ENOMEM;
 	} else if (size == 0) {
 		LOG_ERR("Size is zero");
diff --git a/samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c b/samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
index c4da0ea7d3ab..3828f9b88651 100644
--- a/samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
+++ b/samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
@@ -13,6 +13,7 @@
 #include <zephyr/sys/byteorder.h>
 #include <zephyr/shell/shell.h>
 #include <nrfx_clock.h>
+#include <audio_defines.h>
 
 #include "presets.h"
 #include "broadcast_source.h"
@@ -41,6 +42,7 @@ static bool sd_card_present = true;
 static struct k_thread le_audio_msg_sub_thread_data;
 static k_tid_t le_audio_msg_sub_thread_id;
 K_THREAD_STACK_DEFINE(le_audio_msg_sub_thread_stack, CONFIG_LE_AUDIO_MSG_SUB_STACK_SIZE);
+NET_BUF_POOL_FIXED_DEFINE(ble_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, CONFIG_BT_ISO_TX_MTU, 0, NULL);
 
 static void lecture_set(const struct shell *shell);
 static int big_enable(const struct shell *shell, uint8_t big_index);
@@ -213,27 +215,45 @@ static void subgroup_send(struct stream_index stream_idx)
 {
 	int ret;
 	static int prev_ret;
+	struct audio_data audio_frame = {0};
 
 	uint8_t num_bis = subgroups[stream_idx.lvl1][stream_idx.lvl2].num_bises;
 	size_t frame_size = lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_size;
-	uint8_t frame_buffer[num_bis][frame_size];
+	struct net_buf *audio_buf = net_buf_alloc(&ble_tx_pool, K_NO_WAIT);
+
+	if (audio_buf == NULL) {
+		LOG_ERR("Out of RX buffers");
+		return;
+	}
 
 	for (int i = 0; i < num_bis; i++) {
 		uint8_t *frame_ptr =
 			lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_ptrs[i];
 
-		if (frame_ptr == NULL) {
-			memset(frame_buffer[i], 0, frame_size);
-		} else {
-			memcpy(frame_buffer[i], frame_ptr, frame_size);
-		}
+		net_buf_add_mem(audio_buf, frame_ptr, frame_size);
+
+		audio_frame.meta.locations |=
+			(uint32_t)subgroups[stream_idx.lvl1][stream_idx.lvl2].location[i];
 	}
 
-	struct le_audio_encoded_audio enc_audio = {
-		.data = (uint8_t *)frame_buffer, .size = frame_size * num_bis, .num_ch = num_bis};
+	audio_frame.data = audio_buf;
+	audio_frame.data_size = frame_size * num_bis;
+	audio_frame.meta.data_coding = LC3;
+
+	struct bt_audio_codec_cfg *codec_cfg =
+		&subgroups[stream_idx.lvl1][stream_idx.lvl2].group_lc3_preset.codec_cfg;
 
-	ret = broadcast_source_send(stream_idx.lvl1, stream_idx.lvl2, enc_audio);
+	ret = le_audio_freq_hz_get(codec_cfg, &audio_frame.meta.sample_rate_hz);
+	if (ret) {
+		LOG_ERR("Failed to get frequency: %d", ret);
+	}
 
+	ret = le_audio_duration_us_get(codec_cfg, &audio_frame.meta.data_len_us);
+	if (ret) {
+		LOG_ERR("Failed to get frame duration: %d", ret);
+	}
+
+	ret = broadcast_source_send(stream_idx.lvl1, stream_idx.lvl2, &audio_frame);
 	if (ret != 0 && ret != prev_ret) {
 		if (ret == -ECANCELED) {
 			LOG_WRN("Sending cancelled");
@@ -242,6 +262,8 @@ static void subgroup_send(struct stream_index stream_idx)
 		}
 	}
 
+	net_buf_unref(audio_buf);
+
 	prev_ret = ret;
 }
 


Reviews:
user: login: rick1082
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T02:51:34Z
user: login: koffes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T10:57:23Z
user: login: koffes
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T10:34:01Z
user: login: koffes
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T11:20:10Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T05:52:19Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T05:53:05Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T05:53:26Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T12:16:00Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T12:16:19Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T12:16:26Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T12:16:34Z
user: login: umapraseeda
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T13:59:04Z
user: login: koffes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T12:15:02Z
user: login: koffes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T12:16:51Z
user: login: gWacey
body: Nice, I am liking the simpler API interface with this, as I hoped!
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T15:07:39Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T05:54:37Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T05:55:53Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T05:57:38Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T06:10:32Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T06:16:12Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T06:21:15Z
user: login: koffes
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T07:40:23Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T08:38:33Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T08:45:12Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T08:47:16Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T08:47:29Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T08:48:47Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T11:34:34Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T12:02:08Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T12:06:28Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T12:20:45Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T12:22:29Z
user: login: koffes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T06:31:33Z
user: login: koffes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T06:33:50Z
user: login: koffes
body: Two minor nits we can discuss.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T06:34:59Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T06:48:30Z
user: login: Thalley
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-05-21T07:52:52Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T08:38:49Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:18:47Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:21:17Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:23:26Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:27:43Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:29:43Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:33:28Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:35:08Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:39:28Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T13:24:20Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T13:25:50Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T13:30:24Z
user: login: Thalley
state: APPROVED
author_association: NONE
submitted_at: 2025-05-21T13:41:49Z
user: login: alexsven
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T06:48:20Z
user: login: koffes
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T09:40:41Z
user: login: gWacey
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T09:44:28Z
user: login: nordicjm
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T09:53:12Z

Review comments:
diff_hunk: @@ -331,19 +332,30 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
 			   struct net_buf *buf)
 {
-	bool bad_frame = false;
+	struct audio_data audio_frame;
+
+	/* Populate the audio frame structure */
+	audio_frame.data = buf->data;
+	audio_frame.data_size = buf->len;
+	audio_frame.meta.bad_data = false;
+	audio_frame.meta.reference_ts_us = info->ts;
path: applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_sink.c
user: login: rick1082
body: Picky: maybe we could rename the "reference_ts_us" to "ref_ts_us"
created_at: 2025-04-29T02:49:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -139,24 +129,25 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 static void audio_datapath_thread(void *dummy1, void *dummy2, void *dummy3)
 {
 	int ret;
-	struct ble_iso_data *iso_received = NULL;
-	size_t iso_received_size;
+	struct audio_data *audio_frame = NULL;
+	size_t audio_frame_received_size;
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: rick1082
body: Picky: maybe we could rename "audio_frame_received_size" to "audio_frame_recv_size"
created_at: 2025-04-29T02:50:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -898,29 +899,32 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
 	*delay_us = ctrl_blk.pres_comp.pres_delay_us;
 }
 
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: koffes
body: Looks great
created_at: 2025-04-29T10:57:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -898,29 +899,32 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
 	*delay_us = ctrl_blk.pres_comp.pres_delay_us;
 }
 
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us)
+void audio_datapath_stream_out(struct audio_data *audio_frame)
 {
 	if (!ctrl_blk.stream_started) {
 		LOG_WRN("Stream not started");
 		return;
 	}
 
 	/*** Check incoming data ***/
+	struct net_buf *buf = audio_frame->data;
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: koffes
body: Since this is audio data, suggest we specify a bit more than `buf`.
What about "audio_buf", "net_buf_audio", "net_buf_frame" ?
created_at: 2025-05-02T10:30:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +962,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 	int ret;
 	size_t pcm_size;
 
-	ret = sw_codec_decode(buf, size, bad_frame, &ctrl_blk.decoded_data, &pcm_size);
+	ret = sw_codec_decode(buf->data, buf->len, audio_frame->meta.bad_data,
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: koffes
body: You may have "saved this for later", I think `sw_codec_decode` should just take `(struct audio_data *audio_frame)`
created_at: 2025-05-02T10:32:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,7 +34,8 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
 K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
 
 DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
-DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
+DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(fifo_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, 0, NULL);
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: koffes
body: I need to read this line again after having a first pass.
created_at: 2025-05-02T10:33:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,7 +359,9 @@ int audio_system_decode(void const *const encoded_data, size_t encoded_data_size
 		}
 	}
 
-	ret = sw_codec_decode(encoded_data, encoded_data_size, bad_frame, &pcm_raw_data,
+	struct net_buf *buf = audio_frame->data;
+
+	ret = sw_codec_decode(buf->data, buf->len, audio_frame->meta.bad_data, &pcm_raw_data,
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: koffes
body: Same comment as earlier.
created_at: 2025-05-02T10:51:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,7 +74,7 @@ int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bi
  *
  * @return	0 on success, error otherwise.
  */
-int audio_system_decode(void const *const encoded_data, size_t encoded_data_size, bool bad_frame);
+int audio_system_decode(struct audio_data *audio_frame);
path: applications/nrf5340_audio/src/audio/audio_system.h
user: login: koffes
body: For later: Parameter doc update needed.
created_at: 2025-05-02T10:52:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -54,27 +48,18 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 	}
 
 	/* Capture timestamp of when audio frame is received */
-	uint32_t recv_frame_ts = audio_sync_timer_capture();
+	audio_frame->meta.data_rx_ts_us = audio_sync_timer_capture();
 
 	rx_stats[channel_index].recv_cnt++;
 
-	if (data_size != desired_data_size) {
-		/* A valid frame should always be equal to desired_data_size, set bad_frame
-		 * if that is not the case
-		 */
-		bad_frame = true;
-		rx_stats[channel_index].data_size_mismatch_cnt++;
-	}
-
-	if (bad_frame) {
+	if (audio_frame->meta.bad_data) {
 		rx_stats[channel_index].bad_frame_cnt++;
 	}
 
 	if ((rx_stats[channel_index].recv_cnt % 100) == 0 && rx_stats[channel_index].recv_cnt) {
 		/* NOTE: The string below is used by the Nordic CI system */
-		LOG_DBG("ISO RX SDUs: Ch: %d Total: %d Bad: %d Size mismatch %d", channel_index,
-			rx_stats[channel_index].recv_cnt, rx_stats[channel_index].bad_frame_cnt,
-			rx_stats[channel_index].data_size_mismatch_cnt);
+		LOG_DBG("ISO RX SDUs: Ch: %d Total: %d Bad: %d", channel_index,
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: koffes
body: See we are lacking a variable here. Discuss.
created_at: 2025-05-02T10:54:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -44,16 +44,10 @@
 /**
  * @brief Callback for receiving Bluetooth LE Audio data.
  *
- * @param	data		Pointer to received data.
- * @param	size		Size of received data.
- * @param	bad_frame	Indicating if the frame is a bad frame or not.
- * @param	sdu_ref		ISO timestamp.
+ * @param	audio_frame	Pointer to audio data struct.
  * @param	channel_index	Audio channel index.
- * @param	desired_size	The expected data size.
  */
-typedef void (*le_audio_receive_cb)(const uint8_t *const data, size_t size, bool bad_frame,
-				    uint32_t sdu_ref, enum audio_channel channel_index,
-				    size_t desired_size);
+typedef void (*le_audio_receive_cb)(struct audio_data *audio_frame, uint8_t channel_index);
path: applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h
user: login: koffes
body: The channel index is already baked into the audio frame.
created_at: 2025-05-02T11:18:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -81,7 +84,8 @@ static void data_write(const struct device *dev)
 static void data_received(const struct device *dev, struct net_buf *buffer, size_t size)
 {
 	int ret;
-	void *data_in;
+	struct audio_data *audio_block = NULL;
+	struct net_buf *buf_in;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: koffes
body: Discuss: As a rule of thumb, all bufs which contain audio should IMO have the word "audio" in them.
created_at: 2025-05-02T11:19:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -44,16 +44,10 @@
 /**
  * @brief Callback for receiving Bluetooth LE Audio data.
  *
- * @param	data		Pointer to received data.
- * @param	size		Size of received data.
- * @param	bad_frame	Indicating if the frame is a bad frame or not.
- * @param	sdu_ref		ISO timestamp.
+ * @param	audio_frame	Pointer to audio data struct.
  * @param	channel_index	Audio channel index.
- * @param	desired_size	The expected data size.
  */
-typedef void (*le_audio_receive_cb)(const uint8_t *const data, size_t size, bool bad_frame,
-				    uint32_t sdu_ref, enum audio_channel channel_index,
-				    size_t desired_size);
+typedef void (*le_audio_receive_cb)(struct audio_data *audio_frame, uint8_t channel_index);
path: applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h
user: login: alexsven
body: It's not the same. What is in the audio frame is the channel_location. In the channel location, left==1, in the channel_index left==0.
created_at: 2025-05-05T05:52:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -54,27 +48,18 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 	}
 
 	/* Capture timestamp of when audio frame is received */
-	uint32_t recv_frame_ts = audio_sync_timer_capture();
+	audio_frame->meta.data_rx_ts_us = audio_sync_timer_capture();
 
 	rx_stats[channel_index].recv_cnt++;
 
-	if (data_size != desired_data_size) {
-		/* A valid frame should always be equal to desired_data_size, set bad_frame
-		 * if that is not the case
-		 */
-		bad_frame = true;
-		rx_stats[channel_index].data_size_mismatch_cnt++;
-	}
-
-	if (bad_frame) {
+	if (audio_frame->meta.bad_data) {
 		rx_stats[channel_index].bad_frame_cnt++;
 	}
 
 	if ((rx_stats[channel_index].recv_cnt % 100) == 0 && rx_stats[channel_index].recv_cnt) {
 		/* NOTE: The string below is used by the Nordic CI system */
-		LOG_DBG("ISO RX SDUs: Ch: %d Total: %d Bad: %d Size mismatch %d", channel_index,
-			rx_stats[channel_index].recv_cnt, rx_stats[channel_index].bad_frame_cnt,
-			rx_stats[channel_index].data_size_mismatch_cnt);
+		LOG_DBG("ISO RX SDUs: Ch: %d Total: %d Bad: %d", channel_index,
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: alexsven
body: Size is no longer sent to this module, but checked in the previous stage.
created_at: 2025-05-05T05:53:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +962,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 	int ret;
 	size_t pcm_size;
 
-	ret = sw_codec_decode(buf, size, bad_frame, &ctrl_blk.decoded_data, &pcm_size);
+	ret = sw_codec_decode(buf->data, buf->len, audio_frame->meta.bad_data,
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: alexsven
body: Correct, it was saved
created_at: 2025-05-05T05:53:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -898,29 +899,32 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
 	*delay_us = ctrl_blk.pres_comp.pres_delay_us;
 }
 
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us)
+void audio_datapath_stream_out(struct audio_data *audio_frame)
 {
 	if (!ctrl_blk.stream_started) {
 		LOG_WRN("Stream not started");
 		return;
 	}
 
 	/*** Check incoming data ***/
+	struct net_buf *buf = audio_frame->data;
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: alexsven
body: audio_buf used
created_at: 2025-05-12T12:16:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,7 +359,9 @@ int audio_system_decode(void const *const encoded_data, size_t encoded_data_size
 		}
 	}
 
-	ret = sw_codec_decode(encoded_data, encoded_data_size, bad_frame, &pcm_raw_data,
+	struct net_buf *buf = audio_frame->data;
+
+	ret = sw_codec_decode(buf->data, buf->len, audio_frame->meta.bad_data, &pcm_raw_data,
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: alexsven
body: Done
created_at: 2025-05-12T12:16:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,7 +74,7 @@ int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bi
  *
  * @return	0 on success, error otherwise.
  */
-int audio_system_decode(void const *const encoded_data, size_t encoded_data_size, bool bad_frame);
+int audio_system_decode(struct audio_data *audio_frame);
path: applications/nrf5340_audio/src/audio/audio_system.h
user: login: alexsven
body: Done
created_at: 2025-05-12T12:16:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -81,7 +84,8 @@ static void data_write(const struct device *dev)
 static void data_received(const struct device *dev, struct net_buf *buffer, size_t size)
 {
 	int ret;
-	void *data_in;
+	struct audio_data *audio_block = NULL;
+	struct net_buf *buf_in;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: alexsven
body: Done
created_at: 2025-05-12T12:16:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,7 +34,8 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
 K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
 
 DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
-DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
+DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(fifo_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, 0, NULL);
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: koffes
body: Should audio_tx be updated as well?
created_at: 2025-05-14T12:15:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -81,7 +84,8 @@ static void data_write(const struct device *dev)
 static void data_received(const struct device *dev, struct net_buf *buffer, size_t size)
 {
 	int ret;
-	void *data_in;
+	struct audio_data *audio_block = NULL;
+	struct net_buf *buf_in;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: koffes
body: This is still the same.
created_at: 2025-05-14T12:16:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -999,7 +1004,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 		}
 
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: gWacey
body: Maybe have an error state here if the bit depth is not one of the above.
Actually do we need this if..else if..?
It could be something like:

uint32_t audio_data_offset = out_blk_idx * BLK_STEREO_NUM_SAMPS * (audio_frame_out->meta.carried_bits_per_sample / BITS_PER_OCTET);

memcpy((&(*uint8_t)ctrl_blk.out.fifo[audio_data_offset ],  &(uint8_t *)audio_frame_out->data)[audio_data_offset ], BLK_STEREO_SIZE_OCTETS);

This may effect later code!
created_at: 2025-05-14T14:01:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +962,7 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 	int ret;
 	size_t pcm_size;
 
-	ret = sw_codec_decode(buf, size, bad_frame, &ctrl_blk.decoded_data, &pcm_size);
+	ret = sw_codec_decode(audio_frame, &ctrl_blk.decoded_data, &pcm_size);
 	if (ret) {
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: gWacey
body: Could do this as audio_frame_in to audio_frame_out and lower down copy the audio_frame_out to the ctrl.out.fifo?
This would allow the meta data for the resulting PCM to return to this function.
created_at: 2025-05-14T14:05:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -83,20 +83,22 @@ bool sw_codec_is_initialized(void)
 	return m_config.initialized;
 }
 
-int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, size_t *encoded_size)
+int sw_codec_encode(struct audio_data *audio_frame)
 {
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: gWacey
body: I think I may have a simpler way to do this that is independent of the number of channels.
Can we discuss in meet the meeting?
created_at: 2025-05-14T14:40:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -184,8 +189,7 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 	return 0;
 }
 
-int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool bad_frame,
-		    void **decoded_data, size_t *decoded_size)
+int sw_codec_decode(struct audio_data *audio_frame, void **decoded_data, size_t *decoded_size)
 {
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: gWacey
body: I think I may have a simpler way to do this that is independent of the number of channels.
Can we discuss in meet the meeting?
created_at: 2025-05-14T14:40:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: gWacey
body: I like the net_buf approach, may need to update the audio module to use it!
created_at: 2025-05-14T14:43:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -139,24 +131,25 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 static void audio_datapath_thread(void *dummy1, void *dummy2, void *dummy3)
 {
 	int ret;
-	struct ble_iso_data *iso_received = NULL;
-	size_t iso_received_size;
+	struct audio_data *audio_frame = NULL;
+	size_t audio_frame_recv_size;
 
 	while (1) {
-		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&iso_received,
-							&iso_received_size, K_FOREVER);
+		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&audio_frame,
+							&audio_frame_recv_size, K_FOREVER);
 		ERR_CHK(ret);
 
 		if (IS_ENABLED(CONFIG_AUDIO_SOURCE_USB) && (CONFIG_AUDIO_DEV == GATEWAY)) {
-			ret = audio_system_decode(iso_received->data, iso_received->data_size,
-						  iso_received->bad_frame);
+			ret = audio_system_decode(audio_frame);
 			ERR_CHK(ret);
 		} else {
-			audio_datapath_stream_out(iso_received->data, iso_received->data_size,
-						  iso_received->sdu_ref, iso_received->bad_frame,
-						  iso_received->recv_frame_ts);
+			audio_datapath_stream_out(audio_frame);
 		}
-		data_fifo_block_free(&ble_fifo_rx, (void *)iso_received);
+
+		struct net_buf *audio_buf = audio_frame->data;
+
+		net_buf_unref(audio_buf);
+		data_fifo_block_free(&ble_fifo_rx, (void *)audio_frame);
 
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: gWacey
body: Nice.
created_at: 2025-05-14T14:45:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1329,16 +1329,27 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec
 			   struct net_buf *buf)
 {
 	int ret;
-	bool bad_frame = false;
-	struct stream_index idx;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	/* Populate the audio frame structure */
+	audio_frame.data = buf->data;
+	audio_frame.data_size = buf->len;
+	audio_frame.meta.bad_data = false;
+	audio_frame.meta.reference_ts_us = info->ts;
+	le_audio_freq_hz_get(stream->codec_cfg, &audio_frame.meta.sample_rate_hz);
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c
user: login: gWacey
body: Would be nice to populate the remaining fields in the meta structure. These too can be used deeper into the system. Will any of the meta data structure change without a QOS update?
If not then could tore this once we know it and memcpy() in here. 
created_at: 2025-05-14T14:53:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -337,19 +337,35 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = {
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
 			   struct net_buf *buf)
 {
-	bool bad_frame = false;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	/* Populate the audio frame structure */
+	audio_frame.data = buf->data;
+	audio_frame.data_size = buf->len;
+	audio_frame.meta.bad_data = false;
+	audio_frame.meta.reference_ts_us = info->ts;
+	le_audio_freq_hz_get(stream->codec_cfg, &audio_frame.meta.sample_rate_hz);
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
user: login: gWacey
body: Again would be nice to fill all fields of the meta data structure. 
See above.
created_at: 2025-05-14T14:55:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,34 +105,57 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size
 		return;
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+	buf_in = net_buf_alloc(&pool_in, K_NO_WAIT);
+	if (buf_in == NULL) {
+		LOG_WRN("Out of RX buffers");
+		net_buf_unref(buffer);
+		return;
+	}
+
+	/* Copy data to RX FIFO */
+	net_buf_add_mem(buf_in, buffer->data, size);
+	net_buf_unref(buffer);
 
-	/* RX FIFO can fill up due to retransmissions or disconnect */
+	ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
+
+	/* RX FIFO can fill up due to re-transmissions or disconnect */
 	if (ret == -ENOMEM) {
-		void *temp;
+		struct audio_data *temp;
 		size_t temp_size;
 
 		rx_num_overruns++;
 		if ((rx_num_overruns % 100) == 1) {
 			LOG_WRN("USB RX overrun. Num: %d", rx_num_overruns);
 		}
 
-		ret = data_fifo_pointer_last_filled_get(fifo_rx, &temp, &temp_size, K_NO_WAIT);
+		ret = data_fifo_pointer_last_filled_get(fifo_rx, (void *)&temp, &temp_size,
+							K_NO_WAIT);
 		ERR_CHK(ret);
 
+		struct net_buf *buf = temp->data;
+
+		net_buf_unref(buf);
 		data_fifo_block_free(fifo_rx, temp);
 
-		ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+		ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
 	}
 
 	ERR_CHK_MSG(ret, "RX failed to get block");
 
-	memcpy(data_in, buffer->data, size);
+	audio_block->data = buf_in;
+	audio_block->data_size = size;
 
-	ret = data_fifo_block_lock(fifo_rx, &data_in, size);
-	ERR_CHK_MSG(ret, "Failed to lock block");
+	/* Add meta data */
+	audio_block->meta.data_coding = PCM;
+	audio_block->meta.data_len_us = 1000;
+	audio_block->meta.sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ;
+	audio_block->meta.bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS;
+	audio_block->meta.carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS;
+	audio_block->meta.locations = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT;
+	audio_block->meta.bad_data = false;
 
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: gWacey
body: Nice.
created_at: 2025-05-14T14:55:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -102,4 +103,31 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
+{
+	uint32_t mask = audio_frame->meta.locations;
path: include/audio_defines.h
user: login: gWacey
body: Can you test that audio_frame is not NULL?
created_at: 2025-05-14T14:57:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -102,4 +103,31 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
+{
+	uint32_t mask = audio_frame->meta.locations;
+	uint32_t count = 0;
+
+	if (mask == 0) {
+		return 1;
+	}
+
+	while (mask) {
+		count += mask & 1;
+		mask >>= 1;
+	}
+
+	return count;
+}
+
path: include/audio_defines.h
user: login: gWacey
body: Nice we did it exactly the same, I have this function in the audio_module.c
created_at: 2025-05-14T14:58:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -212,27 +214,40 @@ static void subgroup_send(struct stream_index stream_idx)
 {
 	int ret;
 	static int prev_ret;
+	struct audio_data audio_frame = {0};
 
path: samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
user: login: gWacey
body: Why clear the structure?
No assumptions about the values in the structure are made. All elements used in the module processing the data need to be filled correctly, with those unuse as don't care. This also in the majority of cases cause a failure for data unset. The user will then have to decide if it is really used or the data has ended up in the wrong place.
created_at: 2025-05-14T15:05:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -999,7 +1004,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 		}
 
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: alexsven
body: I didn't use the meta data in any function like that yet, on purpose. I didn't want to change too much in one go. I'm sure there are loads of optimizations we can do now with the new struct, but that should probably be done later.
created_at: 2025-05-15T05:54:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -957,7 +962,7 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref
 	int ret;
 	size_t pcm_size;
 
-	ret = sw_codec_decode(buf, size, bad_frame, &ctrl_blk.decoded_data, &pcm_size);
+	ret = sw_codec_decode(audio_frame, &ctrl_blk.decoded_data, &pcm_size);
 	if (ret) {
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: alexsven
body: I left audio_datapath alone, as this will be rewritten later. The ctrl_blk struct contains more than what is covered by the audio struct
created_at: 2025-05-15T05:55:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: alexsven
body: Yes, let's discuss in the meeting.
created_at: 2025-05-15T05:57:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -102,4 +103,31 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
+{
+	uint32_t mask = audio_frame->meta.locations;
+	uint32_t count = 0;
+
+	if (mask == 0) {
+		return 1;
+	}
+
+	while (mask) {
+		count += mask & 1;
+		mask >>= 1;
+	}
+
+	return count;
+}
+
path: include/audio_defines.h
user: login: alexsven
body: Sorry I didn't look at audio_module.c. But the function in audio_module.c is slighlty less optimal though, it will do the same operation `AUDIO_MODULE_LOCATIONS_NUM(32)` times regardless of the mask, while this function will only do it equal to the index of the highest bit set ;) Also mask == 0 is valid for mono, so 1 channel should be returned in that case. I suggest removing the `audio_module_number_channels_calculate()` and use the one from audio_defines.h instead 
created_at: 2025-05-15T06:10:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -212,27 +214,40 @@ static void subgroup_send(struct stream_index stream_idx)
 {
 	int ret;
 	static int prev_ret;
+	struct audio_data audio_frame = {0};
 
path: samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
user: login: alexsven
body: It does matter for the locations, since we do an or-operation. Also I find it cleaner to not have random values set in case a module later on tries to use a value that is not set here.
created_at: 2025-05-15T06:16:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1329,16 +1329,27 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec
 			   struct net_buf *buf)
 {
 	int ret;
-	bool bad_frame = false;
-	struct stream_index idx;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	/* Populate the audio frame structure */
+	audio_frame.data = buf->data;
+	audio_frame.data_size = buf->len;
+	audio_frame.meta.bad_data = false;
+	audio_frame.meta.reference_ts_us = info->ts;
+	le_audio_freq_hz_get(stream->codec_cfg, &audio_frame.meta.sample_rate_hz);
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c
user: login: alexsven
body: The missing meta data are `coding`, `bits_per_sample`, `carried_bits_per_sample`, and `locations`. I can try to get `coding` and `locations`, but the `bits_per_sample` and `carried...` can be whatever at this point, that is up to the decoder to decide really.
Same for the comment below
created_at: 2025-05-15T06:21:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -898,29 +899,32 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
 	*delay_us = ctrl_blk.pres_comp.pres_delay_us;
 }
 
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us)
+void audio_datapath_stream_out(struct audio_data *audio_frame)
 {
 	if (!ctrl_blk.stream_started) {
 		LOG_WRN("Stream not started");
 		return;
 	}
 
 	/*** Check incoming data ***/
+	struct net_buf *audio_buf = audio_frame->data;
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: koffes
body: Discuss naming.
created_at: 2025-05-15T07:12:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: koffes
body: Suggest we add "TO" and "FROM" to the print.
created_at: 2025-05-15T07:13:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
 		/* Get PCM data from I2S */
 		/* Since one audio frame is divided into a number of
 		 * blocks, we need to fetch the pointers to all of these
 		 * blocks before copying it to a continuous area of memory
 		 * before sending it to the encoder
 		 */
+		/* TODO: Check data_len_us and adjust for-loop accordingly */
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: koffes
body: Status here?
created_at: 2025-05-15T07:14:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
 		/* Get PCM data from I2S */
 		/* Since one audio frame is divided into a number of
 		 * blocks, we need to fetch the pointers to all of these
 		 * blocks before copying it to a continuous area of memory
 		 * before sending it to the encoder
 		 */
+		/* TODO: Check data_len_us and adjust for-loop accordingly */
 		for (int i = 0; i < CONFIG_FIFO_FRAME_SPLIT_NUM; i++) {
-			ret = data_fifo_pointer_last_filled_get(&fifo_rx, &tmp_pcm_raw_data[i],
+			struct audio_data *audio_block = NULL;
+
+			ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void *)&audio_block,
 								&pcm_block_size, K_FOREVER);
 			ERR_CHK(ret);
-			memcpy(pcm_raw_data + (i * BLOCK_SIZE_BYTES), tmp_pcm_raw_data[i],
-			       pcm_block_size);
 
-			data_fifo_block_free(&fifo_rx, tmp_pcm_raw_data[i]);
+			struct net_buf *buf = audio_block->data;
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: koffes
body: Rename
created_at: 2025-05-15T07:14:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -54,27 +48,18 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 	}
 
 	/* Capture timestamp of when audio frame is received */
-	uint32_t recv_frame_ts = audio_sync_timer_capture();
+	audio_frame->meta.data_rx_ts_us = audio_sync_timer_capture();
 
 	rx_stats[channel_index].recv_cnt++;
 
-	if (data_size != desired_data_size) {
-		/* A valid frame should always be equal to desired_data_size, set bad_frame
-		 * if that is not the case
-		 */
-		bad_frame = true;
-		rx_stats[channel_index].data_size_mismatch_cnt++;
-	}
-
-	if (bad_frame) {
+	if (audio_frame->meta.bad_data) {
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: koffes
body: Why was the desired size removed?
created_at: 2025-05-15T07:15:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -98,38 +84,44 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 	if (blocks_alloced_num >= CONFIG_BUF_BLE_RX_PACKET_NUM) {
 		/* FIFO buffer is full, swap out oldest frame for a new one */
 
-		void *stale_data;
+		struct audio_data *stale_data;
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: koffes
body: Discuss name. "stale_data"
created_at: 2025-05-15T07:16:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -170,9 +173,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: koffes
body: For clarity:  
```suggestion
		audio_frame->meta.data_coding =SW_CODEC_LC3;
```
created_at: 2025-05-15T07:30:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -111,7 +113,8 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 		/* Since LC3 is a single channel codec, we must split the
 		 * stereo PCM stream
 		 */
-		ret = pscm_two_channel_split(pcm_data, pcm_size, CONFIG_AUDIO_BIT_DEPTH_BITS,
+		ret = pscm_two_channel_split(audio_buf->data, audio_buf->len,
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: koffes
body: Discuss: When to make the change here. Create new issue?
created_at: 2025-05-15T07:31:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -224,12 +224,12 @@ int broadcast_source_id_get(uint8_t big_index, uint32_t *broadcast_id);
  *
  * @param[in]	big_index	Index of the Broadcast Isochronous Group (BIG) to broadcast.
  * @param[in]	subgroup_index	Index of the subgroup to broadcast.
- * @param[in]	enc_audio	Encoded audio struct.
+ * @param[in]	audio_frame	Pointer to the audio to send.
  *
  * @return	0 for success, error otherwise.
  */
 int broadcast_source_send(uint8_t big_index, uint8_t subgroup_index,
-			  struct le_audio_encoded_audio enc_audio);
+			  struct audio_data *audio_frame);
path: applications/nrf5340_audio/src/bluetooth/bt_stream/broadcast/broadcast_source.h
user: login: koffes
body: Since this is being send, can it be 
```suggestion
			  struct audio_data const * const audio_frame);
```
created_at: 2025-05-15T07:33:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -187,8 +188,7 @@ static int iso_conn_handle_set(struct bt_bap_stream *bap_stream, uint16_t *iso_c
 	return 0;
 }
 
-int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
-			struct le_audio_encoded_audio enc_audio)
+int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx, struct audio_data *audio_frame)
path: applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
user: login: koffes
body: ```suggestion
int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx, struct audio_data const*const audio_frame)
``` ?
created_at: 2025-05-15T07:34:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -257,13 +267,14 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 		common_interval = tx[i].cap_stream->bap_stream.qos->interval;
 
+		struct net_buf *audio_buf = audio_frame->data;
path: applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
user: login: koffes
body: Everywhere where we do a `x = audio_frame->data` should we have "data" in the name?
created_at: 2025-05-15T07:35:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -337,19 +337,35 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = {
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
 			   struct net_buf *buf)
 {
-	bool bad_frame = false;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	/* Populate the audio frame structure */
+	audio_frame.data = buf->data;
+	audio_frame.data_size = buf->len;
+	audio_frame.meta.bad_data = false;
+	audio_frame.meta.reference_ts_us = info->ts;
+	le_audio_freq_hz_get(stream->codec_cfg, &audio_frame.meta.sample_rate_hz);
+	le_audio_duration_us_get(stream->codec_cfg, &audio_frame.meta.data_len_us);
+	/* TODO: Get channel allocation */
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
user: login: koffes
body: Status?
created_at: 2025-05-15T07:36:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,34 +105,57 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size
 		return;
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+	buf_in = net_buf_alloc(&pool_in, K_NO_WAIT);
+	if (buf_in == NULL) {
+		LOG_WRN("Out of RX buffers");
+		net_buf_unref(buffer);
+		return;
+	}
+
+	/* Copy data to RX FIFO */
+	net_buf_add_mem(buf_in, buffer->data, size);
+	net_buf_unref(buffer);
 
-	/* RX FIFO can fill up due to retransmissions or disconnect */
+	ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
+
+	/* RX FIFO can fill up due to re-transmissions or disconnect */
 	if (ret == -ENOMEM) {
-		void *temp;
+		struct audio_data *temp;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: koffes
body: temp is a bit vague.
created_at: 2025-05-15T07:37:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -102,4 +103,31 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
+{
+	uint32_t mask = audio_frame->meta.locations;
+	uint32_t count = 0;
+
+	if (mask == 0) {
+		return 1;
+	}
+
+	while (mask) {
+		count += mask & 1;
+		mask >>= 1;
+	}
+
+	return count;
path: include/audio_defines.h
user: login: koffes
body: This function is set to return an uint8_t but returns a uint32_t.
created_at: 2025-05-15T07:39:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -898,29 +899,32 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us)
 	*delay_us = ctrl_blk.pres_comp.pres_delay_us;
 }
 
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us)
+void audio_datapath_stream_out(struct audio_data *audio_frame)
 {
 	if (!ctrl_blk.stream_started) {
 		LOG_WRN("Stream not started");
 		return;
 	}
 
 	/*** Check incoming data ***/
+	struct net_buf *audio_buf = audio_frame->data;
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: alexsven
body: Discussed changing to a net_buf in audio_data struct, so new name would be audio_frame->buf
created_at: 2025-05-15T08:38:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -98,38 +84,44 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 	if (blocks_alloced_num >= CONFIG_BUF_BLE_RX_PACKET_NUM) {
 		/* FIFO buffer is full, swap out oldest frame for a new one */
 
-		void *stale_data;
+		struct audio_data *stale_data;
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: alexsven
body: Change to stale_audio_block or similar
created_at: 2025-05-15T08:45:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -170,9 +173,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: alexsven
body: I'll have a look
created_at: 2025-05-15T08:47:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -111,7 +113,8 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 		/* Since LC3 is a single channel codec, we must split the
 		 * stereo PCM stream
 		 */
-		ret = pscm_two_channel_split(pcm_data, pcm_size, CONFIG_AUDIO_BIT_DEPTH_BITS,
+		ret = pscm_two_channel_split(audio_buf->data, audio_buf->len,
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: alexsven
body: Yes
created_at: 2025-05-15T08:47:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,34 +105,57 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size
 		return;
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+	buf_in = net_buf_alloc(&pool_in, K_NO_WAIT);
+	if (buf_in == NULL) {
+		LOG_WRN("Out of RX buffers");
+		net_buf_unref(buffer);
+		return;
+	}
+
+	/* Copy data to RX FIFO */
+	net_buf_add_mem(buf_in, buffer->data, size);
+	net_buf_unref(buffer);
 
-	/* RX FIFO can fill up due to retransmissions or disconnect */
+	ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
+
+	/* RX FIFO can fill up due to re-transmissions or disconnect */
 	if (ret == -ENOMEM) {
-		void *temp;
+		struct audio_data *temp;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: alexsven
body: stale_usb_data
created_at: 2025-05-15T08:48:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: alexsven
body: Discussed, will be done in a later PR
created_at: 2025-05-16T11:34:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,59 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = NULL;
+
+		frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
 
 		/* Get PCM data from I2S */
 		/* Since one audio frame is divided into a number of
 		 * blocks, we need to fetch the pointers to all of these
 		 * blocks before copying it to a continuous area of memory
 		 * before sending it to the encoder
 		 */
+		/* TODO: Check data_len_us and adjust for-loop accordingly */
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: alexsven
body: Done
created_at: 2025-05-16T12:02:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -170,9 +173,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: alexsven
body: Not the same, and in my eyes they don't need to be
created_at: 2025-05-16T12:06:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -111,7 +113,8 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 		/* Since LC3 is a single channel codec, we must split the
 		 * stereo PCM stream
 		 */
-		ret = pscm_two_channel_split(pcm_data, pcm_size, CONFIG_AUDIO_BIT_DEPTH_BITS,
+		ret = pscm_two_channel_split(audio_buf->data, audio_buf->len,
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: alexsven
body: Done, ref: OCT-3377
created_at: 2025-05-16T12:20:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -337,19 +337,35 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = {
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
 			   struct net_buf *buf)
 {
-	bool bad_frame = false;
+	struct audio_data audio_frame;
 
 	if (receive_cb == NULL) {
 		LOG_ERR("The RX callback has not been set");
 		return;
 	}
 
-	if (!(info->flags & BT_ISO_FLAGS_VALID)) {
-		bad_frame = true;
+	/* Populate the audio frame structure */
+	audio_frame.data = buf->data;
+	audio_frame.data_size = buf->len;
+	audio_frame.meta.bad_data = false;
+	audio_frame.meta.reference_ts_us = info->ts;
+	le_audio_freq_hz_get(stream->codec_cfg, &audio_frame.meta.sample_rate_hz);
+	le_audio_duration_us_get(stream->codec_cfg, &audio_frame.meta.data_len_us);
+	/* TODO: Get channel allocation */
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
user: login: alexsven
body: Done
created_at: 2025-05-16T12:22:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -170,9 +173,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: koffes
body: Discuss
created_at: 2025-05-21T06:31:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,34 +105,57 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size
 		return;
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+	buf_in = net_buf_alloc(&pool_in, K_NO_WAIT);
+	if (buf_in == NULL) {
+		LOG_WRN("Out of RX buffers");
+		net_buf_unref(buffer);
+		return;
+	}
+
+	/* Copy data to RX FIFO */
+	net_buf_add_mem(buf_in, buffer->data, size);
+	net_buf_unref(buffer);
 
-	/* RX FIFO can fill up due to retransmissions or disconnect */
+	ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
+
+	/* RX FIFO can fill up due to re-transmissions or disconnect */
 	if (ret == -ENOMEM) {
-		void *temp;
+		struct audio_data *temp;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: koffes
body: This has the same name.
created_at: 2025-05-21T06:33:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,34 +105,57 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size
 		return;
 	}
 
-	ret = data_fifo_pointer_first_vacant_get(fifo_rx, &data_in, K_NO_WAIT);
+	buf_in = net_buf_alloc(&pool_in, K_NO_WAIT);
+	if (buf_in == NULL) {
+		LOG_WRN("Out of RX buffers");
+		net_buf_unref(buffer);
+		return;
+	}
+
+	/* Copy data to RX FIFO */
+	net_buf_add_mem(buf_in, buffer->data, size);
+	net_buf_unref(buffer);
 
-	/* RX FIFO can fill up due to retransmissions or disconnect */
+	ret = data_fifo_pointer_first_vacant_get(fifo_rx, (void *)&audio_block, K_NO_WAIT);
+
+	/* RX FIFO can fill up due to re-transmissions or disconnect */
 	if (ret == -ENOMEM) {
-		void *temp;
+		struct audio_data *temp;
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: alexsven
body: Fixed
created_at: 2025-05-21T06:48:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -26,10 +27,8 @@ uint8_t stream_state_get(void);
 /**
  * @brief Send audio data over the stream.
  *
- * @param data		Data to send.
- * @param size		Size of data.
- * @param num_ch	Number of audio channels.
+ * @param audio_frame		Pointer to the audio data to send.
  */
-void streamctrl_send(void const *const data, size_t size, uint8_t num_ch);
+void streamctrl_send(struct audio_data *audio_frame);
path: applications/nrf5340_audio/src/audio/streamctrl.h
user: login: Thalley
body: Should this be 
```suggestion
void streamctrl_send(const struct audio_data *audio_frame);
```

Or can/should the function be allowed to modify the frame before sending? 
created_at: 2025-05-21T07:20:39Z
author_association: NONE
diff_hunk: @@ -570,6 +573,10 @@ static struct {
 	bool buf_1_in_use;
 } alt;
 
+/* Buffers used for I2S RX. Used interchangeably by I2S. */
+static uint32_t rx_buf_0[BLK_STEREO_SIZE_OCTETS];
+static uint32_t rx_buf_1[BLK_STEREO_SIZE_OCTETS];
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: Thalley
body: These can be moved to the scope of `audio_datapath_i2s_start`
created_at: 2025-05-21T07:22:18Z
author_association: NONE
diff_hunk: @@ -688,51 +695,74 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t
 	}
 
 	/********** I2S RX **********/
-	static uint32_t *rx_buf;
 	static int prev_ret;
+	struct audio_data *rx_audio_block = NULL;
+	struct net_buf *buf_in;
 
 	if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == GATEWAY)) {
-		/* Lock last filled buffer into message queue */
-		if (rx_buf_released != NULL) {
-			ret = data_fifo_block_lock(ctrl_blk.in.fifo, (void **)&rx_buf_released,
-						   BLOCK_SIZE_BYTES);
-
-			ERR_CHK_MSG(ret, "Unable to lock block RX");
+		if (rx_buf_released == NULL) {
+			/* No RX data available */
+			ERR_CHK_MSG(-ENOMEM, "No RX data available");
 		}
 
-		/* Get new empty buffer to send to I2S HW */
-		ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void **)&rx_buf,
-							 K_NO_WAIT);
-		if (ret == 0 && prev_ret == -ENOMEM) {
-			LOG_WRN("I2S RX continuing stream");
-			prev_ret = ret;
+		buf_in = net_buf_alloc(&pool_i2s_rx, K_NO_WAIT);
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: Thalley
body: After `buf_in` has been allocated, you'll need to free the buffer in any following error conditions
created_at: 2025-05-21T07:25:29Z
author_association: NONE
diff_hunk: @@ -53,14 +54,9 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us);
  *       and processed before being outputted over I2S. The audio is synchronized
  *       using sdu_ref_us
  *
- * @param buf Pointer to audio data frame
- * @param size Size of audio data frame in bytes
- * @param sdu_ref_us ISO timestamp reference from BLE controller
- * @param bad_frame Indicating if the audio frame is bad or not
- * @param recv_frame_ts_us Timestamp of when audio frame was received
+ * @param audio_frame Pointer to the audio data frame to be processed
  */
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us);
+void audio_datapath_stream_out(struct audio_data *audio_frame);
path: applications/nrf5340_audio/src/audio/audio_datapath.h
user: login: Thalley
body: Should this be 
```suggestion
void audio_datapath_stream_out(const struct audio_data *audio_frame);
```

created_at: 2025-05-21T07:27:06Z
author_association: NONE
diff_hunk: @@ -33,7 +34,8 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
 K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
 
 DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
-DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
+DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(fifo_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, 0, NULL);
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: Thalley
body: Did you consider the approach of having the data storage in the `audio_data` struct, instead of separating the data from the struct and using the pointer? 
created_at: 2025-05-21T07:29:21Z
author_association: NONE
diff_hunk: @@ -33,7 +34,8 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
 K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
 
 DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
-DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
+DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(fifo_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, 0, NULL);
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: Thalley
body: That would of course require significant more stack memory if doing things like `struct audio_data audio_frame = {0};`
created_at: 2025-05-21T07:30:07Z
author_association: NONE
diff_hunk: @@ -115,35 +117,68 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: Thalley
body: If this happens, then the encoder event will have been polled, but is there any data that needs to be discarded or anything like that? 
created_at: 2025-05-21T07:31:18Z
author_association: NONE
diff_hunk: @@ -97,39 +82,44 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 
 	if (blocks_alloced_num >= CONFIG_BUF_BLE_RX_PACKET_NUM) {
 		/* FIFO buffer is full, swap out oldest frame for a new one */
-
-		void *stale_data;
+		struct audio_data *stale_audio_frame;
 		size_t stale_size;
 		num_overruns++;
 
 		if ((num_overruns % 100) == 1) {
 			LOG_WRN("BLE ISO RX overrun: Num: %d", num_overruns);
 		}
 
-		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, &stale_data, &stale_size,
-							K_NO_WAIT);
+		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&stale_audio_frame,
+							&stale_size, K_NO_WAIT);
 		ERR_CHK(ret);
 
-		data_fifo_block_free(&ble_fifo_rx, stale_data);
+		struct net_buf *stale_buf = stale_audio_frame->data;
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: Thalley
body: Can this ever be NULL?
created_at: 2025-05-21T07:34:37Z
author_association: NONE
diff_hunk: @@ -10,16 +10,10 @@
 /**
  * @brief Data handler when ISO data has been received.
  *
- * @param[in] p_data		Pointer to the received data.
- * @param[in] data_size		Size of the received data.
- * @param[in] bad_frame		Bad frame flag. (I.e. set for missed ISO data).
- * @param[in] sdu_ref		SDU reference timestamp.
+ * @param[in] audio_frame	Pointer to the received data.
  * @param[in] channel_index	Which channel is received.
- * @param[in] desired_data_size	The expected data size.
  */
-void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, bool bad_frame,
-			      uint32_t sdu_ref, enum audio_channel channel_index,
-			      size_t desired_data_size);
+void le_audio_rx_data_handler(struct audio_data *audio_frame, uint8_t channel_index);
path: applications/nrf5340_audio/src/audio/le_audio_rx.h
user: login: Thalley
body: Ditto, should it be
```suggestion
void le_audio_rx_data_handler(const struct audio_data *audio_frame, uint8_t channel_index);
```
created_at: 2025-05-21T07:35:07Z
author_association: NONE
diff_hunk: @@ -170,9 +174,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: Thalley
body: Something that caught my eye here is the naming: 
You store the value LC3 in the meta.data_coding which can be a bit confusing when comparing the the metadata of LE Audio (where the codec information is specifically _not_ in the metadata). 

Not something that needs to be changed, but something to consider at least :) 
created_at: 2025-05-21T07:36:51Z
author_association: NONE
diff_hunk: @@ -248,26 +255,28 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool
 			break;
 		}
 		case SW_CODEC_STEREO: {
-			if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
+			if (audio_frame->meta.bad_data &&
+			    IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
 				memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO);
 				memset(decoded_data_mono[AUDIO_CH_R], 0, PCM_NUM_BYTES_MONO);
 				decoded_data_size = PCM_NUM_BYTES_MONO;
 			} else {
 				/* Decode left channel */
-				ret = sw_codec_lc3_dec_run(
-					encoded_data, encoded_size / 2, LC3_PCM_NUM_BYTES_MONO,
-					AUDIO_CH_L, decoded_data_mono[AUDIO_CH_L],
-					(uint16_t *)&decoded_data_size, bad_frame);
+				ret = sw_codec_lc3_dec_run(audio_buf->data, (audio_buf->len / 2),
+							   LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_L,
+							   decoded_data_mono[AUDIO_CH_L],
+							   (uint16_t *)&decoded_data_size,
+							   audio_frame->meta.bad_data);
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: Thalley
body: ```suggestion
				frame_size = audio_buf->len / 2 ;
				ret = sw_codec_lc3_dec_run(net_buf_pull_mem(audio_buf->data, frame_size,  frame_size,
							   LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_L,
							   decoded_data_mono[AUDIO_CH_L],
							   (uint16_t *)&decoded_data_size,
							   audio_frame->meta.bad_data);
```

created_at: 2025-05-21T07:39:48Z
author_association: NONE
diff_hunk: @@ -248,26 +255,28 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool
 			break;
 		}
 		case SW_CODEC_STEREO: {
-			if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
+			if (audio_frame->meta.bad_data &&
+			    IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
 				memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO);
 				memset(decoded_data_mono[AUDIO_CH_R], 0, PCM_NUM_BYTES_MONO);
 				decoded_data_size = PCM_NUM_BYTES_MONO;
 			} else {
 				/* Decode left channel */
-				ret = sw_codec_lc3_dec_run(
-					encoded_data, encoded_size / 2, LC3_PCM_NUM_BYTES_MONO,
-					AUDIO_CH_L, decoded_data_mono[AUDIO_CH_L],
-					(uint16_t *)&decoded_data_size, bad_frame);
+				ret = sw_codec_lc3_dec_run(audio_buf->data, (audio_buf->len / 2),
+							   LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_L,
+							   decoded_data_mono[AUDIO_CH_L],
+							   (uint16_t *)&decoded_data_size,
+							   audio_frame->meta.bad_data);
 				if (ret) {
 					return ret;
 				}
 
 				/* Decode right channel */
 				ret = sw_codec_lc3_dec_run(
-					(encoded_data + (encoded_size / 2)), encoded_size / 2,
-					LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_R,
+					(audio_buf->data + (audio_buf->len / 2)),
+					(audio_buf->len / 2), LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_R,
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: Thalley
body: ```suggestion
					net_buf_pull_mem(audio_buf->data, frame_size),
					frame_size, LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_R,
```
created_at: 2025-05-21T07:40:15Z
author_association: NONE
diff_hunk: @@ -248,26 +255,28 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool
 			break;
 		}
 		case SW_CODEC_STEREO: {
-			if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
+			if (audio_frame->meta.bad_data &&
+			    IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
 				memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO);
 				memset(decoded_data_mono[AUDIO_CH_R], 0, PCM_NUM_BYTES_MONO);
 				decoded_data_size = PCM_NUM_BYTES_MONO;
 			} else {
 				/* Decode left channel */
-				ret = sw_codec_lc3_dec_run(
-					encoded_data, encoded_size / 2, LC3_PCM_NUM_BYTES_MONO,
-					AUDIO_CH_L, decoded_data_mono[AUDIO_CH_L],
-					(uint16_t *)&decoded_data_size, bad_frame);
+				ret = sw_codec_lc3_dec_run(audio_buf->data, (audio_buf->len / 2),
+							   LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_L,
+							   decoded_data_mono[AUDIO_CH_L],
+							   (uint16_t *)&decoded_data_size,
+							   audio_frame->meta.bad_data);
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: Thalley
body: By pulling the memory from the net_buf, you advance the data pointer, so that when you want to decode the right channel, `audio_buf->data` will automatically point to the right frame
created_at: 2025-05-21T07:41:03Z
author_association: NONE
diff_hunk: @@ -246,7 +256,8 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 
 		if (data_size_pr_stream != LE_AUDIO_SDU_SIZE_OCTETS(bitrate)) {
-			LOG_ERR("The encoded data size does not match the SDU size");
+			LOG_ERR("The encoded data size (%d) does not match the SDU size (%d)",
path: applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
user: login: Thalley
body: ```suggestion
			LOG_ERR("The encoded data size (%zu) does not match the SDU size (%d)",
```
created_at: 2025-05-21T07:42:51Z
author_association: NONE
diff_hunk: @@ -257,13 +268,14 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 		common_interval = tx[i].cap_stream->bap_stream.qos->interval;
 
+		struct net_buf *audio_buf = audio_frame->data;
 		/* Check if same audio is sent to all channels */
-		if (enc_audio.num_ch == 1) {
-			ret = iso_stream_send(enc_audio.data, data_size_pr_stream, tx[i].cap_stream,
-					      tx_info, common_tx_sync_ts_us);
+		if (num_ch == 1) {
+			ret = iso_stream_send(audio_buf->data, data_size_pr_stream,
+					      tx[i].cap_stream, tx_info, common_tx_sync_ts_us);
 		} else {
 			ret = iso_stream_send(
-				&enc_audio.data[(data_size_pr_stream * tx[i].audio_channel)],
+				&audio_buf->data[(data_size_pr_stream * tx[i].audio_channel)],
path: applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
user: login: Thalley
body: You should be able to do something like 

```suggestion
				net_buf_pull_mem(audio_buf, data_size_pr_stream),
```

assuming that the data in `audio_buf` is ordered
created_at: 2025-05-21T07:45:29Z
author_association: NONE
diff_hunk: @@ -257,13 +268,14 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 		common_interval = tx[i].cap_stream->bap_stream.qos->interval;
 
+		struct net_buf *audio_buf = audio_frame->data;
path: applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
user: login: Thalley
body: When is `audio_buf` unref'ed? 
created_at: 2025-05-21T07:46:10Z
author_association: NONE
diff_hunk: @@ -337,19 +337,42 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = {
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
user: login: Thalley
body: The `stream_recv_cb` function for multiple roles seems to be identical. Did you consider a common callback function or some other common function to handle this without duplicating code? 
created_at: 2025-05-21T07:47:36Z
author_association: NONE
diff_hunk: @@ -42,29 +45,29 @@ static void data_write(const struct device *dev)
 
 	void *data_out;
 	size_t data_out_size;
-	struct net_buf *buf_out;
+	struct net_buf *audio_buf_out;
 
-	buf_out = net_buf_alloc(&pool_out, K_NO_WAIT);
+	audio_buf_out = net_buf_alloc(&pool_out, K_NO_WAIT);
 
 	ret = data_fifo_pointer_last_filled_get(fifo_tx, &data_out, &data_out_size, K_NO_WAIT);
 	if (ret) {
 		tx_num_underruns++;
 		if ((tx_num_underruns % 100) == 1) {
 			LOG_WRN("USB TX underrun. Num: %d", tx_num_underruns);
 		}
-		net_buf_unref(buf_out);
+		net_buf_unref(audio_buf_out);
 
 		return;
 	}
 
-	memcpy(buf_out->data, data_out, data_out_size);
+	memcpy(audio_buf_out->data, data_out, data_out_size);
 	data_fifo_block_free(fifo_tx, data_out);
 
 	if (data_out_size == usb_audio_get_in_frame_size(dev)) {
-		ret = usb_audio_send(dev, buf_out, data_out_size);
+		ret = usb_audio_send(dev, audio_buf_out, data_out_size);
 		if (ret) {
 			LOG_WRN("USB TX failed, ret: %d", ret);
-			net_buf_unref(buf_out);
+			net_buf_unref(audio_buf_out);
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: Thalley
body: Missing a return here? 

Else if `!tx_first_data` then you also log `LOG_INF("USB TX first data sent.");` after `LOG_WRN("USB TX failed, ret: %d", ret);`
created_at: 2025-05-21T07:48:42Z
author_association: NONE
diff_hunk: @@ -102,4 +103,35 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
path: include/audio_defines.h
user: login: Thalley
body: Suggest to use `bt_audio_get_chan_count` in this function
created_at: 2025-05-21T07:51:26Z
author_association: NONE
diff_hunk: @@ -59,7 +59,7 @@ int data_fifo_block_lock(struct data_fifo *data_fifo, void **data, size_t size)
 	int ret;
 
 	if (size > data_fifo->block_size_max) {
-		LOG_ERR("Size %zu too big", size);
+		LOG_ERR("Size %zu too big, max: %d", size, data_fifo->block_size_max);
path: lib/data_fifo/data_fifo.c
user: login: Thalley
body: ```suggestion
		LOG_ERR("Size %zu too big, max: %zu", size, data_fifo->block_size_max);
```
created_at: 2025-05-21T07:51:43Z
author_association: NONE
diff_hunk: @@ -215,27 +217,40 @@ static void subgroup_send(struct stream_index stream_idx)
 {
 	int ret;
 	static int prev_ret;
+	struct audio_data audio_frame = {0};
 
 	uint8_t num_bis = subgroups[stream_idx.lvl1][stream_idx.lvl2].num_bises;
 	size_t frame_size = lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_size;
-	uint8_t frame_buffer[num_bis][frame_size];
+	struct net_buf *audio_buf = net_buf_alloc(&ble_tx_pool, K_NO_WAIT);
path: samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
user: login: Thalley
body: Missing return check? 
created_at: 2025-05-21T07:52:01Z
author_association: NONE
diff_hunk: @@ -215,27 +217,40 @@ static void subgroup_send(struct stream_index stream_idx)
 {
 	int ret;
 	static int prev_ret;
+	struct audio_data audio_frame = {0};
 
 	uint8_t num_bis = subgroups[stream_idx.lvl1][stream_idx.lvl2].num_bises;
 	size_t frame_size = lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_size;
-	uint8_t frame_buffer[num_bis][frame_size];
+	struct net_buf *audio_buf = net_buf_alloc(&ble_tx_pool, K_NO_WAIT);
 
 	for (int i = 0; i < num_bis; i++) {
 		uint8_t *frame_ptr =
 			lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_ptrs[i];
 
-		if (frame_ptr == NULL) {
-			memset(frame_buffer[i], 0, frame_size);
-		} else {
-			memcpy(frame_buffer[i], frame_ptr, frame_size);
-		}
+		net_buf_add_mem(audio_buf, frame_ptr, frame_size);
+
+		audio_frame.meta.locations |=
+			(uint32_t)subgroups[stream_idx.lvl1][stream_idx.lvl2].location[i];
 	}
 
-	struct le_audio_encoded_audio enc_audio = {
-		.data = (uint8_t *)frame_buffer, .size = frame_size * num_bis, .num_ch = num_bis};
+	audio_frame.data = audio_buf;
+	audio_frame.data_size = frame_size * num_bis;
+	audio_frame.meta.data_coding = LC3;
 
-	ret = broadcast_source_send(stream_idx.lvl1, stream_idx.lvl2, enc_audio);
+	struct bt_audio_codec_cfg *codec_cfg =
+		&subgroups[stream_idx.lvl1][stream_idx.lvl2].group_lc3_preset.codec_cfg;
 
+	ret = le_audio_freq_hz_get(codec_cfg, &audio_frame.meta.sample_rate_hz);
+	if (ret) {
+		LOG_ERR("Failed to get frequency: %d", ret);
+	}
+
+	ret = le_audio_duration_us_get(codec_cfg, &audio_frame.meta.data_len_us);
+	if (ret) {
+		LOG_ERR("Failed to get frame duration: %d", ret);
+	}
path: samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
user: login: Thalley
body: If you can't get the frequency or duration, how can you continue with the TX? 
created_at: 2025-05-21T07:52:37Z
author_association: NONE
diff_hunk: @@ -248,26 +255,28 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool
 			break;
 		}
 		case SW_CODEC_STEREO: {
-			if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
+			if (audio_frame->meta.bad_data &&
+			    IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) {
 				memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO);
 				memset(decoded_data_mono[AUDIO_CH_R], 0, PCM_NUM_BYTES_MONO);
 				decoded_data_size = PCM_NUM_BYTES_MONO;
 			} else {
 				/* Decode left channel */
-				ret = sw_codec_lc3_dec_run(
-					encoded_data, encoded_size / 2, LC3_PCM_NUM_BYTES_MONO,
-					AUDIO_CH_L, decoded_data_mono[AUDIO_CH_L],
-					(uint16_t *)&decoded_data_size, bad_frame);
+				ret = sw_codec_lc3_dec_run(audio_buf->data, (audio_buf->len / 2),
+							   LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_L,
+							   decoded_data_mono[AUDIO_CH_L],
+							   (uint16_t *)&decoded_data_size,
+							   audio_frame->meta.bad_data);
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: alexsven
body: Nice, I'll make sure to include this in a future PR. We are discussing moving over entirely to net_bufs
created_at: 2025-05-21T08:38:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -688,51 +695,74 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t
 	}
 
 	/********** I2S RX **********/
-	static uint32_t *rx_buf;
 	static int prev_ret;
+	struct audio_data *rx_audio_block = NULL;
+	struct net_buf *buf_in;
 
 	if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == GATEWAY)) {
-		/* Lock last filled buffer into message queue */
-		if (rx_buf_released != NULL) {
-			ret = data_fifo_block_lock(ctrl_blk.in.fifo, (void **)&rx_buf_released,
-						   BLOCK_SIZE_BYTES);
-
-			ERR_CHK_MSG(ret, "Unable to lock block RX");
+		if (rx_buf_released == NULL) {
+			/* No RX data available */
+			ERR_CHK_MSG(-ENOMEM, "No RX data available");
 		}
 
-		/* Get new empty buffer to send to I2S HW */
-		ret = data_fifo_pointer_first_vacant_get(ctrl_blk.in.fifo, (void **)&rx_buf,
-							 K_NO_WAIT);
-		if (ret == 0 && prev_ret == -ENOMEM) {
-			LOG_WRN("I2S RX continuing stream");
-			prev_ret = ret;
+		buf_in = net_buf_alloc(&pool_i2s_rx, K_NO_WAIT);
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: alexsven
body: All failing conditions leads to an ERR_CHK which will either halt or restart the system.
created_at: 2025-05-21T12:18:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -53,14 +54,9 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us);
  *       and processed before being outputted over I2S. The audio is synchronized
  *       using sdu_ref_us
  *
- * @param buf Pointer to audio data frame
- * @param size Size of audio data frame in bytes
- * @param sdu_ref_us ISO timestamp reference from BLE controller
- * @param bad_frame Indicating if the audio frame is bad or not
- * @param recv_frame_ts_us Timestamp of when audio frame was received
+ * @param audio_frame Pointer to the audio data frame to be processed
  */
-void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref_us, bool bad_frame,
-			       uint32_t recv_frame_ts_us);
+void audio_datapath_stream_out(struct audio_data *audio_frame);
path: applications/nrf5340_audio/src/audio/audio_datapath.h
user: login: alexsven
body: We might want to reuse the audio_frame to contain decoded audio_data, since most of the meta data should be the same, but can add a `const` for now.
created_at: 2025-05-21T12:21:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,7 +34,8 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL);
 K_THREAD_STACK_DEFINE(encoder_thread_stack, CONFIG_ENCODER_STACK_SIZE);
 
 DATA_FIFO_DEFINE(fifo_tx, FIFO_TX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
-DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(BLOCK_SIZE_BYTES));
+DATA_FIFO_DEFINE(fifo_rx, FIFO_RX_BLOCK_COUNT, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(fifo_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, 0, NULL);
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: alexsven
body: Yes, it has been discussed. Since we need the struct to contain both PCM data and LC3 data, though not at the same time, we didn't want to allocate a "max" space. 
created_at: 2025-05-21T12:23:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -115,35 +117,68 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3)
 	uint32_t blocks_locked_num;
 
 	int debug_trans_count = 0;
-	size_t encoded_data_size = 0;
 
-	void *tmp_pcm_raw_data[CONFIG_FIFO_FRAME_SPLIT_NUM];
 	char pcm_raw_data[FRAME_SIZE_BYTES];
 
-	static uint8_t *encoded_data;
 	static size_t pcm_block_size;
 	static uint32_t test_tone_finite_pos;
 
 	while (1) {
 		/* Don't start encoding until the stream needing it has started */
 		ret = k_poll(&encoder_evt, 1, K_FOREVER);
+		struct audio_data audio_frame = {0};
+		struct net_buf *frame_buf = net_buf_alloc(&fifo_rx_pool, K_NO_WAIT);
+
+		if (frame_buf == NULL) {
+			LOG_ERR("Out of RX buffers");
+			continue;
+		}
path: applications/nrf5340_audio/src/audio/audio_system.c
user: login: alexsven
body: No, the polling event just ensures that the encoder thread sleeps if there is no need for encoding. We could consider adding a purge of the `fifo_rx_pool` when `audio_system_encoder_stop()` is called though.
created_at: 2025-05-21T12:27:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -97,39 +82,44 @@ void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, boo
 
 	if (blocks_alloced_num >= CONFIG_BUF_BLE_RX_PACKET_NUM) {
 		/* FIFO buffer is full, swap out oldest frame for a new one */
-
-		void *stale_data;
+		struct audio_data *stale_audio_frame;
 		size_t stale_size;
 		num_overruns++;
 
 		if ((num_overruns % 100) == 1) {
 			LOG_WRN("BLE ISO RX overrun: Num: %d", num_overruns);
 		}
 
-		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, &stale_data, &stale_size,
-							K_NO_WAIT);
+		ret = data_fifo_pointer_last_filled_get(&ble_fifo_rx, (void *)&stale_audio_frame,
+							&stale_size, K_NO_WAIT);
 		ERR_CHK(ret);
 
-		data_fifo_block_free(&ble_fifo_rx, stale_data);
+		struct net_buf *stale_buf = stale_audio_frame->data;
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: alexsven
body: It shouldn't, and there is an assert in the unref to catch NULL pointers.
created_at: 2025-05-21T12:29:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -10,16 +10,10 @@
 /**
  * @brief Data handler when ISO data has been received.
  *
- * @param[in] p_data		Pointer to the received data.
- * @param[in] data_size		Size of the received data.
- * @param[in] bad_frame		Bad frame flag. (I.e. set for missed ISO data).
- * @param[in] sdu_ref		SDU reference timestamp.
+ * @param[in] audio_frame	Pointer to the received data.
  * @param[in] channel_index	Which channel is received.
- * @param[in] desired_data_size	The expected data size.
  */
-void le_audio_rx_data_handler(uint8_t const *const p_data, size_t data_size, bool bad_frame,
-			      uint32_t sdu_ref, enum audio_channel channel_index,
-			      size_t desired_data_size);
+void le_audio_rx_data_handler(struct audio_data *audio_frame, uint8_t channel_index);
path: applications/nrf5340_audio/src/audio/le_audio_rx.h
user: login: alexsven
body: We want to be able to change the meta data to capture the timestamp as soon as possible
created_at: 2025-05-21T12:33:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -170,9 +174,11 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz
 			return -ENODEV;
 		}
 
-		*encoded_data = m_encoded_data;
-		*encoded_size = encoded_bytes_written;
+		audio_frame->meta.data_coding = LC3;
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: alexsven
body: This audio struct is for the internal audio modules and not for the LE Audio, the two should be viewed separately.
created_at: 2025-05-21T12:35:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -257,13 +268,14 @@ int bt_le_audio_tx_send(struct le_audio_tx_info *tx, uint8_t num_tx,
 		}
 		common_interval = tx[i].cap_stream->bap_stream.qos->interval;
 
+		struct net_buf *audio_buf = audio_frame->data;
path: applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c
user: login: alexsven
body: It is unref'ed in the same function/thread the allocated it. I've tried to keep that consistent so that it doesn't matter what modules this passes by on it's way.
created_at: 2025-05-21T12:39:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -337,19 +337,42 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = {
 static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
path: applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c
user: login: alexsven
body: Did consider it, decided it should be a separate PR, but then went ahead and fixed it now :P
created_at: 2025-05-21T13:24:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,29 +45,29 @@ static void data_write(const struct device *dev)
 
 	void *data_out;
 	size_t data_out_size;
-	struct net_buf *buf_out;
+	struct net_buf *audio_buf_out;
 
-	buf_out = net_buf_alloc(&pool_out, K_NO_WAIT);
+	audio_buf_out = net_buf_alloc(&pool_out, K_NO_WAIT);
 
 	ret = data_fifo_pointer_last_filled_get(fifo_tx, &data_out, &data_out_size, K_NO_WAIT);
 	if (ret) {
 		tx_num_underruns++;
 		if ((tx_num_underruns % 100) == 1) {
 			LOG_WRN("USB TX underrun. Num: %d", tx_num_underruns);
 		}
-		net_buf_unref(buf_out);
+		net_buf_unref(audio_buf_out);
 
 		return;
 	}
 
-	memcpy(buf_out->data, data_out, data_out_size);
+	memcpy(audio_buf_out->data, data_out, data_out_size);
 	data_fifo_block_free(fifo_tx, data_out);
 
 	if (data_out_size == usb_audio_get_in_frame_size(dev)) {
-		ret = usb_audio_send(dev, buf_out, data_out_size);
+		ret = usb_audio_send(dev, audio_buf_out, data_out_size);
 		if (ret) {
 			LOG_WRN("USB TX failed, ret: %d", ret);
-			net_buf_unref(buf_out);
+			net_buf_unref(audio_buf_out);
path: applications/nrf5340_audio/src/modules/audio_usb.c
user: login: alexsven
body: Yeah, returned added
created_at: 2025-05-21T13:25:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -215,27 +217,40 @@ static void subgroup_send(struct stream_index stream_idx)
 {
 	int ret;
 	static int prev_ret;
+	struct audio_data audio_frame = {0};
 
 	uint8_t num_bis = subgroups[stream_idx.lvl1][stream_idx.lvl2].num_bises;
 	size_t frame_size = lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_size;
-	uint8_t frame_buffer[num_bis][frame_size];
+	struct net_buf *audio_buf = net_buf_alloc(&ble_tx_pool, K_NO_WAIT);
 
 	for (int i = 0; i < num_bis; i++) {
 		uint8_t *frame_ptr =
 			lc3_stream_infos[stream_idx.lvl1][stream_idx.lvl2].frame_ptrs[i];
 
-		if (frame_ptr == NULL) {
-			memset(frame_buffer[i], 0, frame_size);
-		} else {
-			memcpy(frame_buffer[i], frame_ptr, frame_size);
-		}
+		net_buf_add_mem(audio_buf, frame_ptr, frame_size);
+
+		audio_frame.meta.locations |=
+			(uint32_t)subgroups[stream_idx.lvl1][stream_idx.lvl2].location[i];
 	}
 
-	struct le_audio_encoded_audio enc_audio = {
-		.data = (uint8_t *)frame_buffer, .size = frame_size * num_bis, .num_ch = num_bis};
+	audio_frame.data = audio_buf;
+	audio_frame.data_size = frame_size * num_bis;
+	audio_frame.meta.data_coding = LC3;
 
-	ret = broadcast_source_send(stream_idx.lvl1, stream_idx.lvl2, enc_audio);
+	struct bt_audio_codec_cfg *codec_cfg =
+		&subgroups[stream_idx.lvl1][stream_idx.lvl2].group_lc3_preset.codec_cfg;
 
+	ret = le_audio_freq_hz_get(codec_cfg, &audio_frame.meta.sample_rate_hz);
+	if (ret) {
+		LOG_ERR("Failed to get frequency: %d", ret);
+	}
+
+	ret = le_audio_duration_us_get(codec_cfg, &audio_frame.meta.data_len_us);
+	if (ret) {
+		LOG_ERR("Failed to get frame duration: %d", ret);
+	}
path: samples/bluetooth/nrf_auraconfig/src/nrf_auraconfig.c
user: login: alexsven
body: It's currently not used, so it's not blocking but should be caught by CI if it happens.
created_at: 2025-05-21T13:30:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -91,6 +92,8 @@ LOG_MODULE_REGISTER(audio_datapath, CONFIG_AUDIO_DATAPATH_LOG_LEVEL);
 /* How often to print under-run warning */
 #define UNDERRUN_LOG_INTERVAL_BLKS 5000
 
+NET_BUF_POOL_FIXED_DEFINE(pool_i2s_rx, FIFO_NUM_BLKS, BLK_STEREO_SIZE_OCTETS, 8, net_buf_destroy);
path: applications/nrf5340_audio/src/audio/audio_datapath.c
user: login: Thalley
body: This could in theory also be moved to `audio_datapath_i2s_blk_complete` if you want to reduce number of global variables :) 
created_at: 2025-05-21T13:36:36Z
author_association: NONE
diff_hunk: @@ -4,47 +4,42 @@
  * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
  */
 
+#include "le_audio_rx.h"
+
 #include <zephyr/kernel.h>
 #include <nrfx_clock.h>
+#include <zephyr/net_buf.h>
 
 #include "streamctrl.h"
 #include "audio_datapath.h"
 #include "macros_common.h"
 #include "audio_system.h"
 #include "audio_sync_timer.h"
+#include "audio_defines.h"
 
 #include <zephyr/logging/log.h>
 LOG_MODULE_REGISTER(le_audio_rx, CONFIG_LE_AUDIO_RX_LOG_LEVEL);
 
-struct ble_iso_data {
-	uint8_t data[CONFIG_BT_ISO_RX_MTU];
-	size_t data_size;
-	bool bad_frame;
-	uint32_t sdu_ref;
-	uint32_t recv_frame_ts;
-} __packed;
-
 struct rx_stats {
 	uint32_t recv_cnt;
 	uint32_t bad_frame_cnt;
-	uint32_t data_size_mismatch_cnt;
 };
 
 static bool initialized;
 static struct k_thread audio_datapath_thread_data;
 static k_tid_t audio_datapath_thread_id;
 K_THREAD_STACK_DEFINE(audio_datapath_thread_stack, CONFIG_AUDIO_DATAPATH_STACK_SIZE);
 
-DATA_FIFO_DEFINE(ble_fifo_rx, CONFIG_BUF_BLE_RX_PACKET_NUM, WB_UP(sizeof(struct ble_iso_data)));
+DATA_FIFO_DEFINE(ble_fifo_rx, CONFIG_BUF_BLE_RX_PACKET_NUM, WB_UP(sizeof(struct audio_data)));
+NET_BUF_POOL_FIXED_DEFINE(ble_rx_pool, CONFIG_BUF_BLE_RX_PACKET_NUM, CONFIG_BT_ISO_RX_MTU, 0, NULL);
path: applications/nrf5340_audio/src/audio/le_audio_rx.c
user: login: Thalley
body: `ble_rx_pool` could be moved to `le_audio_rx_data_handler` if you want to reduce number of global variables
created_at: 2025-05-21T13:38:41Z
author_association: NONE
diff_hunk: @@ -83,20 +83,22 @@ bool sw_codec_is_initialized(void)
 	return m_config.initialized;
 }
 
-int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, size_t *encoded_size)
+int sw_codec_encode(struct audio_data *audio_frame)
 {
 	int ret;
 
 	/* Temp storage for split stereo PCM signal */
 	char pcm_data_mono_system_sample_rate[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0};
 	/* Make sure we have enough space for two frames (stereo) */
-	static uint8_t m_encoded_data[ENC_MAX_FRAME_SIZE * AUDIO_CH_NUM];
+	uint8_t m_encoded_data[ENC_MAX_FRAME_SIZE * AUDIO_CH_NUM];
path: applications/nrf5340_audio/src/audio/sw_codec_select.c
user: login: Thalley
body: Bear in mind that removing `static` here would increase stack size 
created_at: 2025-05-21T13:39:23Z
author_association: NONE
diff_hunk: @@ -102,4 +103,35 @@ struct audio_data {
 	struct audio_metadata meta;
 };
 
+/**
+ * @brief Get the number of channels in the audio data.
+ *
+ * This function will count the number of bits set in the
+ * locations field of the audio metadata.
+ *
+ * @param audio_frame Pointer to the audio data structure.
+ *
+ * @return The number of channels.
+ */
+static inline uint8_t audio_data_num_ch_get(struct audio_data const *const audio_frame)
path: include/audio_defines.h
user: login: alexsven
body: This has been done
created_at: 2025-05-22T06:48:20Z
author_association: CONTRIBUTOR

PR comments:
user: login: NordicBuilder
created_at: 2025-04-28T15:39:52Z
body: ## CI Information

<sup>_To view the history of this post, clich the 'edited' button above_</sup>
Build number: 33
### Inputs:
#### Sources:
sdk-nrf: PR head: [e3a2a6d127d5308d99bfb6d42e6fd4dd7f2918a6](https://github.com/nrfconnect/sdk-nrf/pull/22100/commits/e3a2a6d127d5308d99bfb6d42e6fd4dd7f2918a6)
<details><summary> more details</summary>

sdk-nrf:
> PR head: [e3a2a6d127d5308d99bfb6d42e6fd4dd7f2918a6](https://github.com/nrfconnect/sdk-nrf/pull/22100/commits/e3a2a6d127d5308d99bfb6d42e6fd4dd7f2918a6)
> merge base: [9f68ef18bd017e04c97de3bd25ea59da7f7cd667](https://github.com/nrfconnect/sdk-nrf/commit/9f68ef18bd017e04c97de3bd25ea59da7f7cd667)
> target head (main): [9570e652230f28be3b1b69d77a4ca977c25b1daa](https://github.com/nrfconnect/sdk-nrf/commit/9570e652230f28be3b1b69d77a4ca977c25b1daa)
> [Diff](https://github.com/nrfconnect/sdk-nrf/compare/9f68ef18bd017e04c97de3bd25ea59da7f7cd667..e3a2a6d127d5308d99bfb6d42e6fd4dd7f2918a6)</details>

#### Github labels
| Enabled | Name | Description |
| -- | -- | -- |
|| ci-disabled | _Disable the ci execution_ | 
|| ci-all-test | _Run all of ci, no test spec filtering will be done_ | 
|| ci-force-downstream | _Force execution of downstream even if twister fails_ | 
|| ci-run-twister | _Force run twister_ | 
|| ci-run-zephyr-twister | _Force run zephyr twister_ | 

<details><summary> List of changed files detected by CI (29)</summary>

```
applications
│  ├── nrf5340_audio
│  │  ├── broadcast_sink
│  │  │  │ main.c
│  │  ├── broadcast_source
│  │  │  │ main.c
│  │  ├── src
│  │  │  ├── audio
│  │  │  │  ├── audio_datapath.c
│  │  │  │  ├── audio_datapath.h
│  │  │  │  ├── audio_system.c
│  │  │  │  ├── audio_system.h
│  │  │  │  ├── le_audio_rx.c
│  │  │  │  ├── le_audio_rx.h
│  │  │  │  ├── streamctrl.h
│  │  │  │  ├── sw_codec_select.c
│  │  │  │  │ sw_codec_select.h
│  │  │  ├── bluetooth
│  │  │  │  ├── bt_stream
│  │  │  │  │  ├── broadcast
│  │  │  │  │  │  ├── broadcast_sink.c
│  │  │  │  │  │  ├── broadcast_source.c
│  │  │  │  │  │  │ broadcast_source.h
│  │  │  │  │  ├── bt_le_audio_tx
│  │  │  │  │  │  ├── bt_le_audio_tx.c
│  │  │  │  │  │  │ bt_le_audio_tx.h
│  │  │  │  │  ├── le_audio.c
│  │  │  │  │  ├── le_audio.h
│  │  │  │  │  ├── unicast
│  │  │  │  │  │  ├── unicast_client.c
│  │  │  │  │  │  ├── unicast_client.h
│  │  │  │  │  │  ├── unicast_server.c
│  │  │  │  │  │  │ unicast_server.h
│  │  │  ├── modules
│  │  │  │  │ audio_usb.c
│  │  ├── unicast_client
│  │  │  │ main.c
│  │  ├── unicast_server
│  │  │  │ main.c
doc
│  ├── nrf
│  │  ├── releases_and_maturity
│  │  │  ├── releases
│  │  │  │  │ release-notes-changelog.rst
include
│  │ audio_defines.h
lib
│  ├── data_fifo
│  │  │ data_fifo.c
samples
│  ├── bluetooth
│  │  ├── nrf_auraconfig
│  │  │  ├── src
│  │  │  │  │ nrf_auraconfig.c
```
</details>

### Outputs:

#### Toolchain
Version: 1d2c5d0ab5
Build docker image: docker-dtr.nordicsemi.no/sw-production/ncs-build:1d2c5d0ab5_e85602c25f

#### Test Spec & Results: :white_check_mark: Success; :x: Failure; :orange_circle: Queued; :yellow_circle: Progress; :white_medium_square: Skipped; :warning: Quarantine
- :white_medium_square: Toolchain - Skipped: existing toolchain is used
- :white_check_mark: Build twister - Skipped: Skipping Build & Test as it succeeded in a previous run: 32
- :white_check_mark: Integration tests
   - :white_check_mark: test-sdk-audio

<details><summary>Disabled integration tests</summary>

- 
   - desktop52_verification
   - doc-internal
   - test_ble_nrf_config
   - test-fw-nrfconnect-apps
   - test-fw-nrfconnect-ble_mesh
   - test-fw-nrfconnect-ble_samples
   - test-fw-nrfconnect-boot
   - test-fw-nrfconnect-chip
   - test-fw-nrfconnect-fem
   - test-fw-nrfconnect-nfc
   - test-fw-nrfconnect-nrf-iot_cloud
   - test-fw-nrfconnect-nrf-iot_libmodem-nrf
   - test-fw-nrfconnect-nrf-iot_lwm2m
   - test-fw-nrfconnect-nrf-iot_mosh
   - test-fw-nrfconnect-nrf-iot_positioning
   - test-fw-nrfconnect-nrf-iot_samples
   - test-fw-nrfconnect-nrf-iot_serial_lte_modem
   - test-fw-nrfconnect-nrf-iot_thingy91
   - test-fw-nrfconnect-nrf-iot_zephyr_lwm2m
   - test-fw-nrfconnect-nrf_crypto
   - test-fw-nrfconnect-proprietary_esb
   - test-fw-nrfconnect-ps-main
   - test-fw-nrfconnect-rpc
   - test-fw-nrfconnect-rs
   - test-fw-nrfconnect-tfm
   - test-fw-nrfconnect-thread-main
   - test-low-level
   - test-sdk-find-my
   - test-sdk-mcuboot
   - test-sdk-pmic-samples
   - test-sdk-wifi
   - test-secdom-samples-public
</details>



*Note: This message is automatically posted and updated by the CI*
author_association: CONTRIBUTOR
user: login: alexsven
created_at: 2025-05-08T14:45:56Z
body: Will squash into one commit once reviewed
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-12T10:48:46Z
body: You can find the documentation preview for this PR [here](https://ncsdoc.z6.web.core.windows.net/PR-22100/).

Preview links for modified nRF Connect SDK documents:

https://ncsdoc.z6.web.core.windows.net/PR-22100/nrf/releases_and_maturity/releases/release-notes-changelog.html
author_association: NONE
user: login: Thalley
created_at: 2025-05-21T07:55:03Z
body: A general comment: It was a bit difficult to figure out when/who the net_buf's were unref'ed; it may be my lack of familiarity with the code base, but in general either the caller/provider of the net_bufs unref them when the called function returns, or the called function takes ownership (unless it returns an error). 

I suggest that you decide, if you haven't already, on a design of the data path and ownership, document that somewhere internally and then ensure that it's being applied
author_association: NONE