summaryrefslogtreecommitdiff
path: root/src/class/audio/audio_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/class/audio/audio_device.c')
-rw-r--r--src/class/audio/audio_device.c563
1 files changed, 356 insertions, 207 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index ed380424f..8c86de433 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg
+ * Copyright (c) 2023 HiFiPhile
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -65,8 +66,10 @@
//--------------------------------------------------------------------+
// Use ring buffer if it's available, some MCUs need extra RAM requirements
+// For DWC2 enable ring buffer will disable DMA (if available)
#ifndef TUD_AUDIO_PREFER_RING_BUFFER
- #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
+ #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \
+ defined(TUP_USBIP_DWC2)
#define TUD_AUDIO_PREFER_RING_BUFFER 0
#else
#define TUD_AUDIO_PREFER_RING_BUFFER 1
@@ -118,23 +121,23 @@
// EP IN software buffers and mutexes
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
- IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
+ tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
+ tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
- IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
+ tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
+ tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
- IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
+ tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
+ tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
@@ -144,38 +147,38 @@
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
+ tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
+ tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
+ tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
// EP OUT software buffers and mutexes
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
- OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
+ tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
+ tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
- OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
+ tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
+ tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
- OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
+ tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
+ tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
@@ -185,89 +188,89 @@
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
+ tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
+ tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
+ tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
// Control buffers
-CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
+tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
#if CFG_TUD_AUDIO > 1
-CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
+tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
#endif
#if CFG_TUD_AUDIO > 2
-CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
+tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
#endif
// Active alternate setting of interfaces
-uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
+tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
-uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
+tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
-uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
+tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
// Software encoding/decoding support FIFOs
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
- CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
- tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
+ tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
+ tu_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
+ tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
- CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
- tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
+ tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
+ tu_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
+ tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
- CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
- tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
+ tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
+ tu_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
+ tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
- CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
- tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
+ tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
+ tu_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
+ tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
- CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
- tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
+ tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
+ tu_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
+ tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
- CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
- tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
+ tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
+ tu_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
- osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
+ tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif
#endif
@@ -300,19 +303,18 @@ typedef struct
bool mounted; // Device opened
- /*------------- From this point, data is not cleared by bus reset -------------*/
-
uint16_t desc_length; // Length of audio function descriptor
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
struct {
- CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
+ CFG_TUSB_MEM_ALIGN uint32_t send_buf;
+ uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
uint8_t compute_method;
-
+ bool format_correction;
union {
uint8_t power_of_2; // pre-computed power of 2 shift
float float_const; // pre-computed float constant
@@ -322,12 +324,12 @@ typedef struct
uint32_t mclk_freq;
}fixed;
-#if 0 // implement later
struct {
- uint32_t nominal_value;
- uint32_t threshold_bytes;
+ uint32_t nom_value; // In 16.16 format
+ uint32_t fifo_lvl_avg; // In 16.16 format
+ uint16_t fifo_lvl_thr; // fifo level threshold
+ uint16_t rate_const[2]; // pre-computed feedback/fifo_depth rate
}fifo_count;
-#endif
}compute;
} feedback;
@@ -365,6 +367,8 @@ typedef struct
#endif
#endif
+ /*------------- From this point, data is not cleared by bus reset -------------*/
+
// Buffer for control requests
uint8_t * ctrl_buf;
uint8_t ctrl_buf_sz;
@@ -373,14 +377,10 @@ typedef struct
uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
// EP Transfer buffers and FIFOs
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT
-#if !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t ep_out_ff;
#endif
-
-#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
-
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t ep_in_ff;
#endif
@@ -390,7 +390,6 @@ typedef struct
CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
#endif
-
// Support FIFOs for software encoding and decoding
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t * rx_supp_ff;
@@ -434,9 +433,146 @@ typedef struct
#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf)
//--------------------------------------------------------------------+
+// WEAK FUNCTION STUBS
+//--------------------------------------------------------------------+
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) {
+ (void) rhport;
+ (void) func_id;
+ (void) ep_in;
+ (void) cur_alt_setting;
+ return true;
+}
+
+TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) {
+ (void) rhport;
+ (void) n_bytes_copied;
+ (void) func_id;
+ (void) ep_in;
+ (void) cur_alt_setting;
+ return true;
+}
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) {
+ (void) rhport;
+ (void) n_bytes_received;
+ (void) func_id;
+ (void) ep_out;
+ (void) cur_alt_setting;
+ return true;
+}
+
+TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) {
+ (void) rhport;
+ (void) n_bytes_received;
+ (void) func_id;
+ (void) ep_out;
+ (void) cur_alt_setting;
+ return true;
+}
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id) {
+ (void) func_id;
+}
+
+TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) {
+ (void) func_id;
+ (void) alt_itf;
+ feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED;
+}
+
+TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id) {
+ (void) func_id;
+ return CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION;
+}
+#endif
+
+TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) {
+ (void) func_id;
+ (void) frame_number;
+ (void) interval_shift;
+}
+
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) {
+ (void) rhport;
+}
+#endif
+
+// Invoked when audio set interface request received
+TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
+ (void) rhport;
+ (void) p_request;
+ return true;
+}
+
+// Invoked when audio set interface request received which closes an EP
+TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
+ (void) rhport;
+ (void) p_request;
+ return true;
+}
+
+// Invoked when audio class specific set request received for an EP
+TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
+ (void) rhport;
+ (void) p_request;
+ (void) pBuff;
+ TU_LOG2(" No EP set request callback available!\r\n");
+ return false; // In case no callback function is present or request can not be conducted we stall it
+}
+
+// Invoked when audio class specific set request received for an interface
+TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
+ (void) rhport;
+ (void) p_request;
+ (void) pBuff;
+ TU_LOG2(" No interface set request callback available!\r\n");
+ return false; // In case no callback function is present or request can not be conducted we stall it
+}
+
+// Invoked when audio class specific set request received for an entity
+TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
+ (void) rhport;
+ (void) p_request;
+ (void) pBuff;
+ TU_LOG2(" No entity set request callback available!\r\n");
+ return false; // In case no callback function is present or request can not be conducted we stall it
+}
+
+// Invoked when audio class specific get request received for an EP
+TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
+ (void) rhport;
+ (void) p_request;
+ TU_LOG2(" No EP get request callback available!\r\n");
+ return false; // Stall
+}
+
+// Invoked when audio class specific get request received for an interface
+TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
+ (void) rhport;
+ (void) p_request;
+ TU_LOG2(" No interface get request callback available!\r\n");
+ return false; // Stall
+}
+
+// Invoked when audio class specific get request received for an entity
+TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
+ (void) rhport;
+ (void) p_request;
+ TU_LOG2(" No entity get request callback available!\r\n");
+ return false; // Stall
+}
+
+//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
+tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
@@ -479,7 +615,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
+static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
+static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new);
#endif
bool tud_audio_n_mounted(uint8_t func_id)
@@ -560,19 +697,13 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
uint8_t const *dummy2;
uint8_t idx_audio_fct = 0;
- if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb)
- {
- idx_audio_fct = audiod_get_audio_fct_idx(audio);
- TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
- }
+ idx_audio_fct = audiod_get_audio_fct_idx(audio);
+ TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
// Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO)
- if (tud_audio_rx_done_pre_read_cb)
- {
- TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
- }
+ TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
-#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
+#if CFG_TUD_AUDIO_ENABLE_DECODING
switch (audio->format_type_rx)
{
@@ -621,13 +752,17 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
#endif
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT)
+ {
+ audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff));
+ }
+#endif
+
#endif
// Call a weak callback here - a possibility for user to get informed decoding was completed
- if (tud_audio_rx_done_post_read_cb)
- {
- TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
- }
+ TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
return true;
}
@@ -731,6 +866,13 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
// Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
// TU_VERIFY(cnt != n_bytes);
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT)
+ {
+ audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0]));
+ }
+#endif
+
return true;
}
#endif //CFG_TUD_AUDIO_ENABLE_DECODING
@@ -854,7 +996,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
// Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or
// if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer().
- if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
+ TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
// Send everything in ISO EP FIFO
uint16_t n_bytes_tx;
@@ -917,7 +1059,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
#endif
// Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame
- if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
+ TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
return true;
}
@@ -1073,9 +1215,38 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio)
+static inline bool audiod_fb_send(audiod_function_t *audio)
{
- return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4);
+ bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction;
+ // Format the feedback value
+ if (apply_correction)
+ {
+ uint8_t * fb = (uint8_t *) &audio->feedback.send_buf;
+
+ // For FS format is 10.14
+ *(fb++) = (audio->feedback.value >> 2) & 0xFF;
+ *(fb++) = (audio->feedback.value >> 10) & 0xFF;
+ *(fb++) = (audio->feedback.value >> 18) & 0xFF;
+ *fb = 0;
+ } else
+ {
+ audio->feedback.send_buf = audio->feedback.value;
+ }
+
+ // About feedback format on FS
+ //
+ // 3 variables: Format | packetSize | sendSize | Working OS:
+ // 16.16 4 4 Linux, Windows
+ // 16.16 4 3 Linux
+ // 16.16 3 4 Linux
+ // 16.16 3 3 Linux
+ // 10.14 4 4 Linux
+ // 10.14 4 3 Linux
+ // 10.14 3 4 Linux, OSX
+ // 10.14 3 3 Linux, OSX
+ //
+ // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly
+ return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) &audio->feedback.send_buf, apply_correction ? 3 : 4);
}
#endif
@@ -1693,7 +1864,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
// Invoke callback - can be used to stop data sampling
- if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+ TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_in = 0; // Necessary?
@@ -1724,7 +1895,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
// Invoke callback - can be used to stop data sampling
- if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+ TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_out = 0; // Necessary?
@@ -1842,9 +2013,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
{
audio->ep_fb = ep_addr;
audio->feedback.frame_shift = desc_ep->bInterval -1;
-
- // Enable SOF interrupt if callback is implemented
- if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, true);
}
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1857,20 +2025,23 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
TU_VERIFY(foundEPs == nEps);
// Invoke one callback for a final set interface
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+ TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- // Prepare feedback computation if callback is available
- if (tud_audio_feedback_params_cb)
+ // Prepare feedback computation if endpoint is available
+ if(audio->ep_fb != 0)
{
audio_feedback_params_t fb_param;
tud_audio_feedback_params_cb(func_id, alt, &fb_param);
audio->feedback.compute_method = fb_param.method;
+ if(TUSB_SPEED_FULL == tud_speed_get())
+ audio->feedback.format_correction = tud_audio_feedback_format_correction_cb(func_id);
+
// Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame)
uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
- audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16;
+ audio->feedback.min_value = ((fb_param.sample_freq - 1)/frame_div) << 16;
audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16;
switch(fb_param.method)
@@ -1878,20 +2049,32 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
- set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
+ audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
break;
- #if 0 // implement later
case AUDIO_FEEDBACK_METHOD_FIFO_COUNT:
{
- uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16;
- audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div);
- audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes;
-
- tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value);
+ // Initialize the threshold level to half filled
+ uint16_t fifo_lvl_thr;
+#if CFG_TUD_AUDIO_ENABLE_DECODING
+ fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2;
+#else
+ fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2;
+#endif
+ audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr;
+ audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t)fifo_lvl_thr) << 16;
+ // Avoid 64bit division
+ uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100);
+ audio->feedback.compute.fifo_count.nom_value = nominal;
+ audio->feedback.compute.fifo_count.rate_const[0] = (audio->feedback.max_value - nominal) / fifo_lvl_thr;
+ audio->feedback.compute.fifo_count.rate_const[1] = (nominal - audio->feedback.min_value) / fifo_lvl_thr;
+ // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability
+ if(tud_speed_get() == TUSB_SPEED_HIGH) {
+ audio->feedback.compute.fifo_count.rate_const[0] /= 8;
+ audio->feedback.compute.fifo_count.rate_const[1] /= 8;
+ }
}
break;
- #endif
// nothing to do
default: break;
@@ -1909,16 +2092,19 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
// Disable SOF interrupt if no driver has any enabled feedback EP
- bool disable = true;
+ bool enable_sof = false;
for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
{
- if (_audiod_fct[i].ep_fb != 0)
+ if (_audiod_fct[i].ep_fb != 0 &&
+ (_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED ||
+ _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT ||
+ _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2 ))
{
- disable = false;
+ enable_sof = true;
break;
}
}
- if (disable) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, false);
+ usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, enable_sof);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
@@ -1948,35 +2134,19 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
if (entityID != 0)
{
- if (tud_audio_set_req_entity_cb)
- {
- // Check if entity is present and get corresponding driver index
- TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+ // Check if entity is present and get corresponding driver index
+ TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
- // Invoke callback
- return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
- }
- else
- {
- TU_LOG2(" No entity set request callback available!\r\n");
- return false; // In case no callback function is present or request can not be conducted we stall it
- }
+ // Invoke callback
+ return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
- if (tud_audio_set_req_itf_cb)
- {
- // Find index of audio driver structure and verify interface really exists
- TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ // Find index of audio driver structure and verify interface really exists
+ TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
- // Invoke callback
- return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
- }
- else
- {
- TU_LOG2(" No interface set request callback available!\r\n");
- return false; // In case no callback function is present or request can not be conducted we stall it
- }
+ // Invoke callback
+ return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
}
break;
@@ -1985,19 +2155,11 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
{
uint8_t ep = TU_U16_LOW(p_request->wIndex);
- if (tud_audio_set_req_ep_cb)
- {
- // Check if entity is present and get corresponding driver index
- TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+ // Check if entity is present and get corresponding driver index
+ TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
- // Invoke callback
- return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
- }
- else
- {
- TU_LOG2(" No EP set request callback available!\r\n");
- return false; // In case no callback function is present or request can not be conducted we stall it
- }
+ // Invoke callback
+ return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
break;
// Unknown/Unsupported recipient
@@ -2054,15 +2216,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
- if (tud_audio_get_req_entity_cb)
- {
- return tud_audio_get_req_entity_cb(rhport, p_request);
- }
- else
- {
- TU_LOG2(" No entity get request callback available!\r\n");
- return false; // Stall
- }
+ return tud_audio_get_req_entity_cb(rhport, p_request);
}
}
else
@@ -2073,15 +2227,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
- if (tud_audio_get_req_itf_cb)
- {
- return tud_audio_get_req_itf_cb(rhport, p_request);
- }
- else
- {
- TU_LOG2(" No interface get request callback available!\r\n");
- return false; // Stall
- }
+ return tud_audio_get_req_itf_cb(rhport, p_request);
}
}
}
@@ -2097,15 +2243,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
- if (tud_audio_get_req_ep_cb)
- {
- return tud_audio_get_req_ep_cb(rhport, p_request);
- }
- else
- {
- TU_LOG2(" No EP get request callback available!\r\n");
- return false; // Stall
- }
+ return tud_audio_get_req_ep_cb(rhport, p_request);
}
}
break;
@@ -2160,7 +2298,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// I assume here, that things above are handled by PHY
// All transmission is done - what remains to do is to inform job was completed
- if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport);
+ tud_audio_int_done_cb(rhport);
return true;
}
@@ -2201,13 +2339,13 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// Transmission of feedback EP finished
if (audio->ep_fb == ep_addr)
{
- if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id);
+ tud_audio_fb_done_cb(func_id);
// Schedule a transmit with the new value if EP is not busy
- if (!usbd_edpt_busy(rhport, audio->ep_fb))
+ if (usbd_edpt_claim(rhport, audio->ep_fb))
{
// Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
- return audiod_fb_send(rhport, audio);
+ return audiod_fb_send(audio);
}
}
#endif
@@ -2219,7 +2357,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
+static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
{
// Check if frame interval is within sane limits
// The interval value n_frames was taken from the descriptors within audiod_set_interface()
@@ -2238,11 +2376,11 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u
if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq))
{
audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
- audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq);
+ audio->feedback.compute.power_of_2 = 16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq);
}
else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT)
{
- audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift));
+ audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1)));
}
else
{
@@ -2253,6 +2391,38 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u
return true;
}
+static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new)
+{
+ /* Low-pass (averaging) filter */
+ uint32_t lvl = audio->feedback.compute.fifo_count.fifo_lvl_avg;
+ lvl = (uint32_t)(((uint64_t)lvl * 63 + ((uint32_t)lvl_new << 16)) >> 6);
+ audio->feedback.compute.fifo_count.fifo_lvl_avg = lvl;
+
+ uint32_t const ff_lvl = lvl >> 16;
+ uint16_t const ff_thr = audio->feedback.compute.fifo_count.fifo_lvl_thr;
+ uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const;
+
+ uint32_t feedback;
+
+ if(ff_lvl < ff_thr)
+ {
+ feedback = audio->feedback.compute.fifo_count.nom_value + (ff_thr - ff_lvl) * rate[0];
+ } else
+ {
+ feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1];
+ }
+
+ if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
+ if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
+ audio->feedback.value = feedback;
+
+ // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
+ if (usbd_edpt_claim(audio->rhport, audio->ep_fb))
+ {
+ audiod_fb_send(audio);
+ }
+}
+
uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
{
audiod_function_t* audio = &_audiod_fct[func_id];
@@ -2270,7 +2440,7 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
{
- uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift);
+ uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1));
feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq);
}
break;
@@ -2289,6 +2459,21 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
return feedback;
}
+
+bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
+{
+ TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+
+ _audiod_fct[func_id].feedback.value = feedback;
+
+ // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
+ if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
+ {
+ return audiod_fb_send(&_audiod_fct[func_id]);
+ }
+
+ return true;
+}
#endif
TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
@@ -2315,7 +2500,7 @@ TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust);
if ( 0 == (frame_count & (interval-1)) )
{
- if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
+ tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
}
}
}
@@ -2703,44 +2888,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da
#endif
-#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-
-bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
-{
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
-
- // Format the feedback value
-#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
- if ( TUSB_SPEED_FULL == tud_speed_get() )
- {
- uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value;
-
- // For FS format is 10.14
- *(fb++) = (feedback >> 2) & 0xFF;
- *(fb++) = (feedback >> 10) & 0xFF;
- *(fb++) = (feedback >> 18) & 0xFF;
- // 4th byte is needed to work correctly with MS Windows
- *fb = 0;
- }else
-#else
- {
- // Send value as-is, caller will choose the appropriate format
- _audiod_fct[func_id].feedback.value = feedback;
- }
-#endif
-
- // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
- if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
- {
- return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]);
- }
-
- return true;
-}
-#endif
-
// No security checks here - internal function only which should always succeed
-uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
+static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
{
for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++)
{