@@ -38,8 +38,11 @@ K_MEM_SLAB_DEFINE_STATIC(usb_rx_slab, ROUND_UP(USB_BLOCK_SIZE_MULTI_CHAN, UDC_BU
3838static struct k_msgq * audio_q_tx ;
3939static struct k_msgq * audio_q_rx ;
4040
41+ /* USB blocks are 1 ms each, but we split them into 0.5 ms blocks for processing,
42+ * hence the dividing by two
43+ */
4144NET_BUF_POOL_FIXED_DEFINE (pool_in , USB_BLOCKS ,
42- (USB_BLOCK_SIZE_MULTI_CHAN * CONFIG_FIFO_FRAME_SPLIT_NUM ),
45+ (USB_BLOCK_SIZE_MULTI_CHAN * CONFIG_FIFO_FRAME_SPLIT_NUM / 2 ),
4346 sizeof (struct audio_metadata ), NULL );
4447
4548static uint32_t rx_num_overruns ;
@@ -167,6 +170,21 @@ static void *get_recv_buf_cb(const struct device *dev, uint8_t terminal, uint16_
167170 return buf ;
168171}
169172
173+ static void half_buf_add (struct net_buf * frame , void * data , uint16_t size ,
174+ uint32_t * blocks_in_frame )
175+ {
176+ const uint32_t half_data_len_us = usb_in_meta .data_len_us / 2 ;
177+ const uint32_t half_bytes_per_location = usb_in_meta .bytes_per_location / 2 ;
178+
179+ net_buf_add_mem (frame , data , size );
180+
181+ struct audio_metadata * meta = net_buf_user_data (frame );
182+
183+ meta -> data_len_us += half_data_len_us ;
184+ meta -> bytes_per_location += half_bytes_per_location ;
185+ (* blocks_in_frame )++ ;
186+ }
187+
170188static void data_recv_cb (const struct device * dev , uint8_t terminal , void * buf , uint16_t size ,
171189 void * user_data )
172190{
@@ -175,23 +193,20 @@ static void data_recv_cb(const struct device *dev, uint8_t terminal, void *buf,
175193 ARG_UNUSED (user_data );
176194
177195 int ret ;
178- /* Frame accumulation for 10ms frames */
179- static struct net_buf * current_frame ;
180- static uint32_t blocks_in_current_frame ;
196+ /* Frame accumulation */
197+ static struct net_buf * frame_current ;
198+ static struct net_buf * frame_spillover ;
199+ static uint32_t blocks_in_frame_current ;
200+ static uint32_t blocks_in_frame_spillover ;
181201
182202 if (unlikely (buf == NULL )) {
183203 LOG_ERR ("Received NULL buffer" );
184204 return ;
185205 }
186206
187207 /* Fast exit conditions */
188- if (unlikely (size == 0 || !playing_state )) {
189- k_mem_slab_free (& usb_rx_slab , buf );
190- return ;
191- }
192-
193- /* Terminal check */
194- if (unlikely (!(terminal_headset_out_enabled || terminal_headphones_out_enabled ))) {
208+ if (unlikely (size == 0 || !playing_state ) ||
209+ !(terminal_headset_out_enabled || terminal_headphones_out_enabled )) {
195210 k_mem_slab_free (& usb_rx_slab , buf );
196211 return ;
197212 }
@@ -204,52 +219,96 @@ static void data_recv_cb(const struct device *dev, uint8_t terminal, void *buf,
204219 }
205220
206221 /* Allocate new frame if we don't have one */
207- if (current_frame == NULL ) {
208- /* Check space availability */
209- if (unlikely (k_msgq_num_free_get (audio_q_rx ) == 0 || pool_in .avail_count == 0 )) {
210- goto overrun_cleanup ;
222+ if (frame_current == NULL ) {
223+ if (frame_spillover != NULL ) {
224+ frame_current = frame_spillover ;
225+ blocks_in_frame_current = blocks_in_frame_spillover ;
226+ frame_spillover = NULL ;
227+ blocks_in_frame_spillover = 0 ;
228+ } else {
229+ /* Check space availability */
230+ if (unlikely (k_msgq_num_free_get (audio_q_rx ) == 0 ||
231+ pool_in .avail_count == 0 )) {
232+ goto overrun_cleanup ;
233+ }
234+
235+ frame_current = net_buf_alloc (& pool_in , K_NO_WAIT );
236+ if (unlikely (frame_current == NULL )) {
237+ LOG_WRN ("Out of RX buffers for frame" );
238+ goto overrun_cleanup ;
239+ }
240+
241+ /* Initialize metadata for the first block */
242+ struct audio_metadata * meta = net_buf_user_data (frame_current );
243+
244+ * meta = usb_in_meta ;
245+ meta -> data_len_us = 0 ;
246+ meta -> bytes_per_location = 0 ;
247+ blocks_in_frame_current = 0 ;
248+ }
249+ }
250+
251+ /* Check if we are about to spill over, if so: allocate spill_over frame */
252+ if ((blocks_in_frame_current + 2 ) > CONFIG_FIFO_FRAME_SPLIT_NUM ) {
253+ const size_t half_size = size / 2 ;
254+
255+ /* Add half the buffer to current frame */
256+ half_buf_add (frame_current , buf , half_size , & blocks_in_frame_current );
257+
258+ if (frame_spillover != NULL ) {
259+ LOG_WRN ("Previous spillover frame not consumed, dropping it" );
260+ net_buf_unref (frame_spillover );
261+ blocks_in_frame_spillover = 0 ;
211262 }
212263
213- current_frame = net_buf_alloc (& pool_in , K_NO_WAIT );
214- if (unlikely (current_frame == NULL )) {
215- LOG_WRN ("Out of RX buffers for frame" );
264+ /* Allocate new frame for spill over data since current frame is full. If allocation
265+ * fails, drop the spill over data to prevent blocking the USB endpoint, but keep
266+ * the current frame to allow it to be sent to the audio system.
267+ */
268+ frame_spillover = net_buf_alloc (& pool_in , K_NO_WAIT );
269+ if (unlikely (frame_spillover == NULL )) {
270+ LOG_WRN ("Out of RX buffers for spill over frame" );
216271 goto overrun_cleanup ;
217272 }
218273
219274 /* Initialize metadata for the first block */
220- struct audio_metadata * meta = net_buf_user_data (current_frame );
221- * meta = usb_in_meta ;
222- meta -> data_len_us = 0 ;
223- meta -> bytes_per_location = 0 ;
224- blocks_in_current_frame = 0 ;
225- }
226-
227- /* Add block data directly to current frame */
228- net_buf_add_mem (current_frame , buf , size );
275+ struct audio_metadata * meta_spill_over = net_buf_user_data (frame_spillover );
229276
230- /* Update metadata */
231- struct audio_metadata * meta = net_buf_user_data (current_frame );
277+ * meta_spill_over = usb_in_meta ;
278+ meta_spill_over -> data_len_us = 0 ;
279+ meta_spill_over -> bytes_per_location = 0 ;
280+ blocks_in_frame_spillover = 0 ;
232281
233- /* Accumulate per-block duration (typically 1 ms) */
234- meta -> data_len_us += usb_in_meta .data_len_us ;
235- meta -> bytes_per_location += usb_in_meta .bytes_per_location ;
236- blocks_in_current_frame ++ ;
282+ /* Add half the buffer to spill over frame */
283+ half_buf_add (frame_spillover , (char * )buf + half_size , half_size ,
284+ & blocks_in_frame_spillover );
285+ } else {
286+ /* Add block data directly to current frame */
287+ net_buf_add_mem (frame_current , buf , size );
288+ /* Update metadata */
289+ struct audio_metadata * meta = net_buf_user_data (frame_current );
290+
291+ /* Accumulate one full 1 ms USB buffer, which counts as two 0.5 ms blocks. */
292+ meta -> data_len_us += usb_in_meta .data_len_us ;
293+ meta -> bytes_per_location += usb_in_meta .bytes_per_location ;
294+ blocks_in_frame_current += 2 ;
295+ }
237296
238297 /* Release USB buffer */
239298 k_mem_slab_free (& usb_rx_slab , buf );
240299
241300 /* Check if we have a complete frame */
242- if (blocks_in_current_frame >= CONFIG_FIFO_FRAME_SPLIT_NUM ) {
301+ if (blocks_in_frame_current >= CONFIG_FIFO_FRAME_SPLIT_NUM ) {
243302 /* Put complete frame into RX queue */
244- ret = k_msgq_put (audio_q_rx , (void * )& current_frame , K_NO_WAIT );
303+ ret = k_msgq_put (audio_q_rx , (void * )& frame_current , K_NO_WAIT );
245304 if (ret ) {
246305 LOG_ERR ("Failed to store complete frame" );
247- net_buf_unref (current_frame );
306+ net_buf_unref (frame_current );
248307 }
249308
250309 /* Reset for next frame */
251- current_frame = NULL ;
252- blocks_in_current_frame = 0 ;
310+ frame_current = NULL ;
311+ blocks_in_frame_current = 0 ;
253312 }
254313
255314 return ;
0 commit comments