blob: d9f2e284edce82a6693f2fc0ee538ea731814afa [file] [log] [blame]
Austin Schuh41baf202022-01-01 14:33:40 -08001/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27/*
28 * This driver supports at most one out EP, one in EP, one control EP, and one feedback EP and one alternative interface other than zero. Hence, only one input terminal and one output terminal are support, if you need more adjust the driver!
29 * It supports multiple TX and RX channels.
30 *
31 * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function.
32 *
33 * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host
34 *
35 * 1. Input data -> SW-FIFO -> MCU USB
36 *
37 * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available)
38 *
39 * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB
40 *
41 * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required.
42 *
43 * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB
44 *
45 * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer.
46 *
47 * The same holds in the RX case.
48 *
49 * */
50
51#include "tusb_option.h"
52
53#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO)
54
55//--------------------------------------------------------------------+
56// INCLUDE
57//--------------------------------------------------------------------+
58#include "device/usbd.h"
59#include "device/usbd_pvt.h"
60
61#include "audio_device.h"
62
63//--------------------------------------------------------------------+
64// MACRO CONSTANT TYPEDEF
65//--------------------------------------------------------------------+
66
67// Use ring buffer if it's available, some MCUs need extra RAM requirements
68#ifndef TUD_AUDIO_PREFER_RING_BUFFER
69#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
70#define TUD_AUDIO_PREFER_RING_BUFFER 0
71#else
72#define TUD_AUDIO_PREFER_RING_BUFFER 1
73#endif
74#endif
75
76// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer
77// is available or driver is would need to be changed dramatically
78
79// Only STM32 synopsys and dcd_transdimension use non-linear buffer for now
80// Synopsys detection copied from dcd_synopsys.c (refactor later on)
81#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
82 defined (STM32F107xB) || defined (STM32F107xC)
83#define STM32F1_SYNOPSYS
84#endif
85
86#if defined (STM32L475xx) || defined (STM32L476xx) || \
87 defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
88 defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
89 defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
90#define STM32L4_SYNOPSYS
91#endif
92
93#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
94 CFG_TUSB_MCU == OPT_MCU_STM32F2 || \
95 CFG_TUSB_MCU == OPT_MCU_STM32F4 || \
96 CFG_TUSB_MCU == OPT_MCU_STM32F7 || \
97 CFG_TUSB_MCU == OPT_MCU_STM32H7 || \
98 (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) || \
99 CFG_TUSB_MCU == OPT_MCU_RX63X || \
100 CFG_TUSB_MCU == OPT_MCU_RX65X || \
101 CFG_TUSB_MCU == OPT_MCU_RX72N || \
102 CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \
103 CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
104 CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
105 CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
106 CFG_TUSB_MCU == OPT_MCU_MSP432E4
107#if TUD_AUDIO_PREFER_RING_BUFFER
108#define USE_LINEAR_BUFFER 0
109#else
110#define USE_LINEAR_BUFFER 1
111#endif
112#else
113#define USE_LINEAR_BUFFER 1
114#endif
115
116// Declaration of buffers
117
118// Check for maximum supported numbers
119#if CFG_TUD_AUDIO > 3
120#error Maximum number of audio functions restricted to three!
121#endif
122
123// EP IN software buffers and mutexes
124#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
125#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
126CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
127#if CFG_FIFO_MUTEX
128osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
129#endif
130#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
131#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
132CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
133#if CFG_FIFO_MUTEX
134osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
135#endif
136#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
137#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
138CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
139#if CFG_FIFO_MUTEX
140osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
141#endif
142#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
143#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
144
145// Linear buffer TX in case:
146// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
147// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
148#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
149#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
150CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
151#endif
152#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
153CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
154#endif
155#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
156CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
157#endif
158#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
159
160// EP OUT software buffers and mutexes
161#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
162#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
163CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
164#if CFG_FIFO_MUTEX
165osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
166#endif
167#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
168#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
169CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
170#if CFG_FIFO_MUTEX
171osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
172#endif
173#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
174#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
175CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
176#if CFG_FIFO_MUTEX
177osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
178#endif
179#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
180#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
181
182// Linear buffer RX in case:
183// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
184// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
185#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
186#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
187CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
188#endif
189#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
190CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
191#endif
192#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
193CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
194#endif
195#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
196
197// Control buffers
198CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
199#if CFG_TUD_AUDIO > 1
200CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
201#endif
202#if CFG_TUD_AUDIO > 2
203CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
204#endif
205
206// Active alternate setting of interfaces
207uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
208#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
209uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
210#endif
211#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
212uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
213#endif
214
215// Software encoding/decoding support FIFOs
216#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
217#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
218CFG_TUSB_MEM_SECTION 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];
219tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
220#if CFG_FIFO_MUTEX
221osal_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
222#endif
223#endif
224#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
225CFG_TUSB_MEM_SECTION 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];
226tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
227#if CFG_FIFO_MUTEX
228osal_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
229#endif
230#endif
231#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
232CFG_TUSB_MEM_SECTION 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];
233tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
234#if CFG_FIFO_MUTEX
235osal_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
236#endif
237#endif
238#endif
239
240#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
241#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
242CFG_TUSB_MEM_SECTION 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];
243tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
244#if CFG_FIFO_MUTEX
245osal_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
246#endif
247#endif
248#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
249CFG_TUSB_MEM_SECTION 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];
250tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
251#if CFG_FIFO_MUTEX
252osal_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
253#endif
254#endif
255#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
256CFG_TUSB_MEM_SECTION 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];
257tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
258#if CFG_FIFO_MUTEX
259osal_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
260#endif
261#endif
262#endif
263
264typedef struct
265{
266 uint8_t rhport;
267 uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function
268
269#if CFG_TUD_AUDIO_ENABLE_EP_IN
270 uint8_t ep_in; // TX audio data EP.
271 uint16_t ep_in_sz; // Current size of TX EP
272 uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
273#endif
274
275#if CFG_TUD_AUDIO_ENABLE_EP_OUT
276 uint8_t ep_out; // Incoming (into uC) audio data EP.
277 uint16_t ep_out_sz; // Current size of RX EP
278 uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
279
280#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
281 uint8_t ep_fb; // Feedback EP.
282#endif
283
284#endif
285
286#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
287 uint8_t ep_int_ctr; // Audio control interrupt EP.
288#endif
289
290 /*------------- From this point, data is not cleared by bus reset -------------*/
291
292 uint16_t desc_length; // Length of audio function descriptor
293
294 // Buffer for control requests
295 uint8_t * ctrl_buf;
296 uint8_t ctrl_buf_sz;
297
298 // Current active alternate settings
299 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!
300
301 // EP Transfer buffers and FIFOs
302#if CFG_TUD_AUDIO_ENABLE_EP_OUT
303#if !CFG_TUD_AUDIO_ENABLE_DECODING
304 tu_fifo_t ep_out_ff;
305#endif
306
307#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
308 uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
309#endif
310#endif
311
312#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
313 tu_fifo_t ep_in_ff;
314#endif
315
316 // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
317#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
318 CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
319#endif
320
321 // Decoding parameters - parameters are set when alternate AS interface is set by host
322 // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently.
323#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
324 audio_format_type_t format_type_rx;
325 uint8_t n_channels_rx;
326
327#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
328 audio_data_format_type_I_t format_type_I_rx;
329 uint8_t n_bytes_per_sampe_rx;
330 uint8_t n_channels_per_ff_rx;
331 uint8_t n_ff_used_rx;
332#endif
333#endif
334
335 // Encoding parameters - parameters are set when alternate AS interface is set by host
336#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
337 audio_format_type_t format_type_tx;
338 uint8_t n_channels_tx;
339
340#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
341 audio_data_format_type_I_t format_type_I_tx;
342 uint8_t n_bytes_per_sampe_tx;
343 uint8_t n_channels_per_ff_tx;
344 uint8_t n_ff_used_tx;
345#endif
346#endif
347
348 // Support FIFOs for software encoding and decoding
349#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
350 tu_fifo_t * rx_supp_ff;
351 uint8_t n_rx_supp_ff;
352 uint16_t rx_supp_ff_sz_max;
353#endif
354
355#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
356 tu_fifo_t * tx_supp_ff;
357 uint8_t n_tx_supp_ff;
358 uint16_t tx_supp_ff_sz_max;
359#endif
360
361 // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used
362#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
363 uint8_t * lin_buf_out;
364#define USE_LINEAR_BUFFER_RX 1
365#endif
366
367#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
368 uint8_t * lin_buf_in;
369#define USE_LINEAR_BUFFER_TX 1
370#endif
371
372} audiod_function_t;
373
374#ifndef USE_LINEAR_BUFFER_TX
375#define USE_LINEAR_BUFFER_TX 0
376#endif
377
378#ifndef USE_LINEAR_BUFFER_RX
379#define USE_LINEAR_BUFFER_RX 0
380#endif
381
382#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf)
383
384//--------------------------------------------------------------------+
385// INTERNAL OBJECT & FUNCTION DECLARATION
386//--------------------------------------------------------------------+
387CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
388
389#if CFG_TUD_AUDIO_ENABLE_EP_OUT
390static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
391#endif
392
393#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
394static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
395#endif
396
397#if CFG_TUD_AUDIO_ENABLE_EP_IN
398static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio);
399#endif
400
401#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
402static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio);
403#endif
404
405static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request);
406static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request);
407
408static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int);
409static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int);
410static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id);
411static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
412static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
413static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
414
415#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
416static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf);
417
418static inline uint8_t tu_desc_subtype(void const* desc)
419{
420 return ((uint8_t const*) desc)[2];
421}
422#endif
423
424bool tud_audio_n_mounted(uint8_t func_id)
425{
426 TU_VERIFY(func_id < CFG_TUD_AUDIO);
427 audiod_function_t* audio = &_audiod_fct[func_id];
428
429#if CFG_TUD_AUDIO_ENABLE_EP_OUT
430 if (audio->ep_out == 0) return false;
431#endif
432
433#if CFG_TUD_AUDIO_ENABLE_EP_IN
434 if (audio->ep_in == 0) return false;
435#endif
436
437#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
438 if (audio->ep_int_ctr == 0) return false;
439#endif
440
441#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
442 if (audio->ep_fb == 0) return false;
443#endif
444
445 return true;
446}
447
448//--------------------------------------------------------------------+
449// READ API
450//--------------------------------------------------------------------+
451
452#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
453
454uint16_t tud_audio_n_available(uint8_t func_id)
455{
456 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
457 return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff);
458}
459
460uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize)
461{
462 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
463 return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize);
464}
465
466bool tud_audio_n_clear_ep_out_ff(uint8_t func_id)
467{
468 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
469 return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
470}
471
472tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id)
473{
474 if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff;
475 return NULL;
476}
477
478#endif
479
480#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
481// Delete all content in the support RX FIFOs
482bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
483{
484 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
485 return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
486}
487
488uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx)
489{
490 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
491 return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
492}
493
494uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize)
495{
496 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
497 return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize);
498}
499
500tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
501{
502 if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx];
503 return NULL;
504}
505#endif
506
507// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels).
508// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0.
509
510#if CFG_TUD_AUDIO_ENABLE_EP_OUT
511
512static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
513{
514 uint8_t idxItf;
515 uint8_t const *dummy2;
516 uint8_t idx_audio_fct = 0;
517
518 if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb)
519 {
520 idx_audio_fct = audiod_get_audio_fct_idx(audio);
521 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
522 }
523
524 // 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)
525 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]));
526
527#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
528
529 switch (audio->format_type_rx)
530 {
531 case AUDIO_FORMAT_TYPE_UNDEFINED:
532 // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE!
533 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
534 TU_BREAKPOINT();
535 break;
536
537 case AUDIO_FORMAT_TYPE_I:
538
539 switch (audio->format_type_I_tx)
540 {
541 case AUDIO_DATA_FORMAT_TYPE_I_PCM:
542 TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
543 break;
544
545 default:
546 // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED!
547 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n");
548 TU_BREAKPOINT();
549 break;
550 }
551 break;
552
553 default:
554 // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!
555 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n");
556 TU_BREAKPOINT();
557 break;
558 }
559
560 // Prepare for next transmission
561 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
562
563#else
564
565#if USE_LINEAR_BUFFER_RX
566 // Data currently is in linear buffer, copy into EP OUT FIFO
567 TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received));
568
569 // Schedule for next receive
570 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
571#else
572 // Data is already placed in EP FIFO, schedule for next receive
573 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
574#endif
575
576#endif
577
578 // Call a weak callback here - a possibility for user to get informed decoding was completed
579 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]));
580
581 return true;
582}
583
584#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT
585
586// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0
587#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
588
589// Decoding according to 2.3.1.5 Audio Streams
590
591// Helper function
592static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used)
593{
594
595 // This function is an optimized version of
596 // while((uint8_t *)dst < dst_end)
597 // {
598 // memcpy(dst, src, nBytesToCopy);
599 // dst = (uint8_t *)dst + nBytesToCopy;
600 // src += nBytesToCopy * n_ff_used;
601 // }
602
603 // Optimize for fast half word copies
604 typedef struct{
605 uint16_t val;
606 } __attribute((__packed__)) unaligned_uint16_t;
607
608 // Optimize for fast word copies
609 typedef struct{
610 uint32_t val;
611 } __attribute((__packed__)) unaligned_uint32_t;
612
613 switch (nBytesToCopy)
614 {
615 case 1:
616 while((uint8_t *)dst < dst_end)
617 {
618 *(uint8_t *)dst++ = *src;
619 src += n_ff_used;
620 }
621 break;
622
623 case 2:
624 while((uint8_t *)dst < dst_end)
625 {
626 *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
627 dst += 2;
628 src += 2 * n_ff_used;
629 }
630 break;
631
632 case 3:
633 while((uint8_t *)dst < dst_end)
634 {
635 // memcpy(dst, src, 3);
636 // dst = (uint8_t *)dst + 3;
637 // src += 3 * n_ff_used;
638
639 // TODO: Is there a faster way to copy 3 bytes?
640 *(uint8_t *)dst++ = *src++;
641 *(uint8_t *)dst++ = *src++;
642 *(uint8_t *)dst++ = *src++;
643
644 src += 3 * (n_ff_used - 1);
645 }
646 break;
647
648 case 4:
649 while((uint8_t *)dst < dst_end)
650 {
651 *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
652 dst += 4;
653 src += 4 * n_ff_used;
654 }
655 break;
656 }
657
658 return src;
659}
660
661static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
662{
663 (void) rhport;
664
665 // Determine amount of samples
666 uint8_t const n_ff_used = audio->n_ff_used_rx;
667 uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used;
668 uint8_t cnt_ff;
669
670 // Decode
671 uint8_t * src;
672 uint8_t * dst_end;
673
674 tu_fifo_buffer_info_t info;
675
676 for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
677 {
678 tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info);
679
680 if (info.len_lin != 0)
681 {
682 info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
683 src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
684 dst_end = info.ptr_lin + info.len_lin;
685 src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
686
687 // Handle wrapped part of FIFO
688 info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
689 if (info.len_wrap != 0)
690 {
691 dst_end = info.ptr_wrap + info.len_wrap;
692 audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
693 }
694 tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
695 }
696 }
697
698 // 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
699 // TU_VERIFY(cnt != n_bytes);
700
701 return true;
702}
703#endif //CFG_TUD_AUDIO_ENABLE_DECODING
704
705//--------------------------------------------------------------------+
706// WRITE API
707//--------------------------------------------------------------------+
708
709#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
710
711/**
712 * \brief Write data to EP in buffer
713 *
714 * Write data to buffer. If it is full, new data can be inserted once a transmit was scheduled. See audiod_tx_done_cb().
715 * If TX FIFOs are used, this function is not available in order to not let the user mess up the encoding process.
716 *
717 * \param[in] func_id: Index of audio function interface
718 * \param[in] data: Pointer to data array to be copied from
719 * \param[in] len: # of array elements to copy
720 * \return Number of bytes actually written
721 */
722uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len)
723{
724 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
725 return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len);
726}
727
728bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO
729{
730 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
731 return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
732}
733
734tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id)
735{
736 if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff;
737 return NULL;
738}
739
740#endif
741
742#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
743
744uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit
745{
746 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
747 audiod_function_t* audio = &_audiod_fct[func_id];
748
749 uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]);
750
751 TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio));
752
753 n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]);
754 n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size;
755
756 return n_bytes_copied;
757}
758
759bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
760{
761 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
762 return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]);
763}
764
765uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len)
766{
767 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
768 return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len);
769}
770
771tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
772{
773 if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx];
774 return NULL;
775}
776
777#endif
778
779
780#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
781
782// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user
783uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len)
784{
785 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
786
787 // We write directly into the EP's buffer - abort if previous transfer not complete
788 TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr));
789
790 // Check length
791 TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE);
792
793 memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len);
794
795 // Schedule transmit
796 TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len));
797
798 return true;
799}
800
801#endif
802
803
804// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
805// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write.
806
807// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame.
808#if CFG_TUD_AUDIO_ENABLE_EP_IN
809static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
810{
811 uint8_t idxItf;
812 uint8_t const *dummy2;
813
814 uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
815 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
816
817 // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications
818 if (audio->alt_setting[idxItf] == 0) return false;
819
820 // 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
821 // 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().
822 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]));
823
824 // Send everything in ISO EP FIFO
825 uint16_t n_bytes_tx;
826
827 // If support FIFOs are used, encode and schedule transmit
828#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
829 switch (audio->format_type_tx)
830 {
831 case AUDIO_FORMAT_TYPE_UNDEFINED:
832 // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE!
833 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
834 TU_BREAKPOINT();
835 n_bytes_tx = 0;
836 break;
837
838 case AUDIO_FORMAT_TYPE_I:
839
840 switch (audio->format_type_I_tx)
841 {
842 case AUDIO_DATA_FORMAT_TYPE_I_PCM:
843
844 n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio);
845 break;
846
847 default:
848 // YOUR ENCODING IS REQUIRED HERE!
849 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n");
850 TU_BREAKPOINT();
851 n_bytes_tx = 0;
852 break;
853 }
854 break;
855
856 default:
857 // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!
858 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n");
859 TU_BREAKPOINT();
860 n_bytes_tx = 0;
861 break;
862 }
863
864 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
865
866#else
867 // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule
868
869 n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO
870
871#if USE_LINEAR_BUFFER_TX
872 tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
873 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
874#else
875 // Send everything in ISO EP FIFO
876 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx));
877#endif
878
879#endif
880
881 // 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
882 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]));
883
884 return true;
885}
886
887#endif //CFG_TUD_AUDIO_ENABLE_EP_IN
888
889#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
890// Take samples from the support buffer and encode them into the IN EP software FIFO
891// Returns number of bytes written into linear buffer
892
893/* 2.3.1.7.1 PCM Format
894The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio
895data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It
896is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused
897bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the
898range [-1, +1)
899 */
900
901/*
902 * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples
903 * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and
904 * does not change the number of bytes per sample.
905 * */
906
907// Helper function
908static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
909{
910 // Optimize for fast half word copies
911 typedef struct{
912 uint16_t val;
913 } __attribute((__packed__)) unaligned_uint16_t;
914
915 // Optimize for fast word copies
916 typedef struct{
917 uint32_t val;
918 } __attribute((__packed__)) unaligned_uint32_t;
919
920 switch (nBytesToCopy)
921 {
922 case 1:
923 while(src < src_end)
924 {
925 *dst = *src++;
926 dst += n_ff_used;
927 }
928 break;
929
930 case 2:
931 while(src < src_end)
932 {
933 *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
934 src += 2;
935 dst += 2 * n_ff_used;
936 }
937 break;
938
939 case 3:
940 while(src < src_end)
941 {
942 // memcpy(dst, src, 3);
943 // src = (uint8_t *)src + 3;
944 // dst += 3 * n_ff_used;
945
946 // TODO: Is there a faster way to copy 3 bytes?
947 *dst++ = *src++;
948 *dst++ = *src++;
949 *dst++ = *src++;
950
951 dst += 3 * (n_ff_used - 1);
952 }
953 break;
954
955 case 4:
956 while(src < src_end)
957 {
958 *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
959 src += 4;
960 dst += 4 * n_ff_used;
961 }
962 break;
963 }
964
965 return dst;
966}
967
968static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio)
969{
970 // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap
971 // This is ensured within set_interface, where the FIFOs are reconfigured according to this size
972
973 // We encode directly into IN EP's linear buffer - abort if previous transfer not complete
974 TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
975
976 // Determine amount of samples
977 uint8_t const n_ff_used = audio->n_ff_used_tx;
978 uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx;
979 uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes
980 uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
981 uint8_t cnt_ff;
982
983 for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++)
984 {
985 uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
986 if (count < nBytesPerFFToSend)
987 {
988 nBytesPerFFToSend = count;
989 }
990 }
991
992 // Check if there is enough
993 if (nBytesPerFFToSend == 0) return 0;
994
995 // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
996 nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF);
997
998 // Round to full number of samples (flooring)
999 nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy;
1000
1001 // Encode
1002 uint8_t * dst;
1003 uint8_t * src_end;
1004
1005 tu_fifo_buffer_info_t info;
1006
1007 for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
1008 {
1009 dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx];
1010
1011 tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
1012
1013 if (info.len_lin != 0)
1014 {
1015 info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length
1016 src_end = (uint8_t *)info.ptr_lin + info.len_lin;
1017 dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
1018
1019 // Limit up to desired length
1020 info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
1021
1022 // Handle wrapped part of FIFO
1023 if (info.len_wrap != 0)
1024 {
1025 src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
1026 audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
1027 }
1028
1029 tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
1030 }
1031 }
1032
1033 return nBytesPerFFToSend * n_ff_used;
1034}
1035#endif //CFG_TUD_AUDIO_ENABLE_ENCODING
1036
1037// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
1038
1039#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1040static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio)
1041{
1042 return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4);
1043}
1044#endif
1045
1046//--------------------------------------------------------------------+
1047// USBD Driver API
1048//--------------------------------------------------------------------+
1049void audiod_init(void)
1050{
1051 tu_memclr(_audiod_fct, sizeof(_audiod_fct));
1052
1053 for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
1054 {
1055 audiod_function_t* audio = &_audiod_fct[i];
1056
1057 // Initialize control buffers
1058 switch (i)
1059 {
1060 case 0:
1061 audio->ctrl_buf = ctrl_buf_1;
1062 audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ;
1063 break;
1064#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0
1065 case 1:
1066 audio->ctrl_buf = ctrl_buf_2;
1067 audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ;
1068 break;
1069#endif
1070#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0
1071 case 2:
1072 audio->ctrl_buf = ctrl_buf_3;
1073 audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ;
1074 break;
1075#endif
1076 }
1077
1078 // Initialize active alternate interface buffers
1079 switch (i)
1080 {
1081#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0
1082 case 0:
1083 audio->alt_setting = alt_setting_1;
1084 break;
1085#endif
1086#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
1087 case 1:
1088 audio->alt_setting = alt_setting_2;
1089 break;
1090#endif
1091#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
1092 case 2:
1093 audio->alt_setting = alt_setting_3;
1094 break;
1095#endif
1096 }
1097
1098 // Initialize IN EP FIFO if required
1099#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
1100
1101 switch (i)
1102 {
1103#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
1104 case 0:
1105 tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
1106#if CFG_FIFO_MUTEX
1107 tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL);
1108#endif
1109 break;
1110#endif
1111#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
1112 case 1:
1113 tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
1114#if CFG_FIFO_MUTEX
1115 tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL);
1116#endif
1117 break;
1118#endif
1119#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
1120 case 2:
1121 tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
1122#if CFG_FIFO_MUTEX
1123 tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL);
1124#endif
1125 break;
1126#endif
1127 }
1128#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
1129
1130 // Initialize linear buffers
1131#if USE_LINEAR_BUFFER_TX
1132 switch (i)
1133 {
1134#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
1135 case 0:
1136 audio->lin_buf_in = lin_buf_in_1;
1137 break;
1138#endif
1139#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
1140 case 1:
1141 audio->lin_buf_in = lin_buf_in_2;
1142 break;
1143#endif
1144#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
1145 case 2:
1146 audio->lin_buf_in = lin_buf_in_3;
1147 break;
1148#endif
1149 }
1150#endif // USE_LINEAR_BUFFER_TX
1151
1152 // Initialize OUT EP FIFO if required
1153#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
1154
1155 switch (i)
1156 {
1157#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
1158 case 0:
1159 tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
1160#if CFG_FIFO_MUTEX
1161 tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1));
1162#endif
1163 break;
1164#endif
1165#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
1166 case 1:
1167 tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
1168#if CFG_FIFO_MUTEX
1169 tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2));
1170#endif
1171 break;
1172#endif
1173#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
1174 case 2:
1175 tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
1176#if CFG_FIFO_MUTEX
1177 tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3));
1178#endif
1179 break;
1180#endif
1181 }
1182#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
1183
1184 // Initialize linear buffers
1185#if USE_LINEAR_BUFFER_RX
1186 switch (i)
1187 {
1188#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
1189 case 0:
1190 audio->lin_buf_out = lin_buf_out_1;
1191 break;
1192#endif
1193#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
1194 case 1:
1195 audio->lin_buf_out = lin_buf_out_2;
1196 break;
1197#endif
1198#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
1199 case 2:
1200 audio->lin_buf_out = lin_buf_out_3;
1201 break;
1202#endif
1203 }
1204#endif // USE_LINEAR_BUFFER_TX
1205
1206 // Initialize TX support FIFOs if required
1207#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1208
1209 switch (i)
1210 {
1211#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
1212 case 0:
1213 audio->tx_supp_ff = tx_supp_ff_1;
1214 audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO;
1215 audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ;
1216 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
1217 {
1218 tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true);
1219#if CFG_FIFO_MUTEX
1220 tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL);
1221#endif
1222 }
1223
1224 break;
1225#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
1226
1227#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1228 case 1:
1229 audio->tx_supp_ff = tx_supp_ff_2;
1230 audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO;
1231 audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ;
1232 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++)
1233 {
1234 tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true);
1235#if CFG_FIFO_MUTEX
1236 tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL);
1237#endif
1238 }
1239
1240 break;
1241#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1242
1243#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
1244 case 2:
1245 audio->tx_supp_ff = tx_supp_ff_3;
1246 audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO;
1247 audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ;
1248 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++)
1249 {
1250 tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true);
1251#if CFG_FIFO_MUTEX
1252 tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL);
1253#endif
1254 }
1255
1256 break;
1257#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1258 }
1259#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1260
1261 // Set encoding parameters for Type_I formats
1262#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
1263 switch (i)
1264 {
1265#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
1266 case 0:
1267 audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX;
1268 break;
1269#endif
1270#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1271 case 1:
1272 audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX;
1273 break;
1274#endif
1275#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
1276 case 2:
1277 audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX;
1278 break;
1279#endif
1280 }
1281#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
1282
1283 // Initialize RX support FIFOs if required
1284#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
1285
1286 switch (i)
1287 {
1288#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
1289 case 0:
1290 audio->rx_supp_ff = rx_supp_ff_1;
1291 audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO;
1292 audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ;
1293 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++)
1294 {
1295 tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true);
1296#if CFG_FIFO_MUTEX
1297 tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL);
1298#endif
1299 }
1300
1301 break;
1302#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
1303
1304#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1305 case 1:
1306 audio->rx_supp_ff = rx_supp_ff_2;
1307 audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO;
1308 audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ;
1309 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++)
1310 {
1311 tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true);
1312#if CFG_FIFO_MUTEX
1313 tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL);
1314#endif
1315 }
1316
1317 break;
1318#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1319
1320#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
1321 case 2:
1322 audio->rx_supp_ff = rx_supp_ff_3;
1323 audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO;
1324 audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ;
1325 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++)
1326 {
1327 tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true);
1328#if CFG_FIFO_MUTEX
1329 tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL);
1330#endif
1331 }
1332
1333 break;
1334#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1335 }
1336#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1337
1338 // Set encoding parameters for Type_I formats
1339#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
1340 switch (i)
1341 {
1342#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
1343 case 0:
1344 audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX;
1345 break;
1346#endif
1347#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1348 case 1:
1349 audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX;
1350 break;
1351#endif
1352#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
1353 case 2:
1354 audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX;
1355 break;
1356#endif
1357 }
1358#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
1359 }
1360}
1361
1362void audiod_reset(uint8_t rhport)
1363{
1364 (void) rhport;
1365
1366 for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
1367 {
1368 audiod_function_t* audio = &_audiod_fct[i];
1369 tu_memclr(audio, ITF_MEM_RESET_SIZE);
1370
1371#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
1372 tu_fifo_clear(&audio->ep_in_ff);
1373#endif
1374
1375#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
1376 tu_fifo_clear(&audio->ep_out_ff);
1377#endif
1378
1379#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1380 for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
1381 {
1382 tu_fifo_clear(&audio->tx_supp_ff[cnt]);
1383 }
1384#endif
1385
1386#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
1387 for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
1388 {
1389 tu_fifo_clear(&audio->rx_supp_ff[cnt]);
1390 }
1391#endif
1392 }
1393}
1394
1395uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
1396{
1397 (void) max_len;
1398
1399 TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass &&
1400 AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass);
1401
1402 // Verify version is correct - this check can be omitted
1403 TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
1404
1405 // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted
1406 if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed
1407 {
1408 TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0);
1409 }
1410
1411 // Alternate setting MUST be zero - this check can be omitted
1412 TU_VERIFY(itf_desc->bAlternateSetting == 0);
1413
1414 // Find available audio driver interface
1415 uint8_t i;
1416 for (i = 0; i < CFG_TUD_AUDIO; i++)
1417 {
1418 if (!_audiod_fct[i].p_desc)
1419 {
1420 _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one
1421 _audiod_fct[i].rhport = rhport;
1422
1423 // Setup descriptor lengths
1424 switch (i)
1425 {
1426 case 0:
1427 _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN;
1428 break;
1429#if CFG_TUD_AUDIO > 1
1430 case 1:
1431 _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN;
1432 break;
1433#endif
1434#if CFG_TUD_AUDIO > 2
1435 case 2:
1436 _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN;
1437 break;
1438#endif
1439 }
1440
1441 break;
1442 }
1443 }
1444
1445 // Verify we found a free one
1446 TU_ASSERT( i < CFG_TUD_AUDIO );
1447
1448 // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification)
1449 uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor
1450
1451 return drv_len;
1452}
1453
1454static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request)
1455{
1456 uint8_t const itf = tu_u16_low(p_request->wIndex);
1457
1458 // Find index of audio streaming interface
1459 uint8_t func_id, idxItf;
1460 uint8_t const *dummy;
1461
1462 TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
1463 TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1));
1464
1465 TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]);
1466
1467 return true;
1468}
1469
1470static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request)
1471{
1472 (void) rhport;
1473
1474 // Here we need to do the following:
1475
1476 // 1. Find the audio driver assigned to the given interface to be set
1477 // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors.
1478 // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching
1479
1480 // 2. Close EPs which are currently open
1481 // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them
1482
1483 // 3. Open new EP
1484
1485 uint8_t const itf = tu_u16_low(p_request->wIndex);
1486 uint8_t const alt = tu_u16_low(p_request->wValue);
1487
1488 TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt);
1489
1490 // Find index of audio streaming interface and index of interface
1491 uint8_t func_id, idxItf;
1492 uint8_t const *p_desc;
1493 TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
1494
1495 audiod_function_t* audio = &_audiod_fct[func_id];
1496
1497 // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open)
1498#if CFG_TUD_AUDIO_ENABLE_EP_IN
1499 if (audio->ep_in_as_intf_num == itf)
1500 {
1501 audio->ep_in_as_intf_num = 0;
1502 usbd_edpt_close(rhport, audio->ep_in);
1503
1504 // Clear FIFOs, since data is no longer valid
1505#if !CFG_TUD_AUDIO_ENABLE_ENCODING
1506 tu_fifo_clear(&audio->ep_in_ff);
1507#else
1508 for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
1509 {
1510 tu_fifo_clear(&audio->tx_supp_ff[cnt]);
1511 }
1512#endif
1513
1514 // Invoke callback - can be used to stop data sampling
1515 if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
1516
1517 audio->ep_in = 0; // Necessary?
1518
1519 }
1520#endif
1521
1522#if CFG_TUD_AUDIO_ENABLE_EP_OUT
1523 if (audio->ep_out_as_intf_num == itf)
1524 {
1525 audio->ep_out_as_intf_num = 0;
1526 usbd_edpt_close(rhport, audio->ep_out);
1527
1528 // Clear FIFOs, since data is no longer valid
1529#if !CFG_TUD_AUDIO_ENABLE_DECODING
1530 tu_fifo_clear(&audio->ep_out_ff);
1531#else
1532 for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
1533 {
1534 tu_fifo_clear(&audio->rx_supp_ff[cnt]);
1535 }
1536#endif
1537
1538 // Invoke callback - can be used to stop data sampling
1539 if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
1540
1541 audio->ep_out = 0; // Necessary?
1542
1543 // Close corresponding feedback EP
1544#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1545 usbd_edpt_close(rhport, audio->ep_fb);
1546 audio->ep_fb = 0; // Necessary?
1547#endif
1548 }
1549#endif
1550
1551 // Save current alternative interface setting
1552 audio->alt_setting[idxItf] = alt;
1553
1554 // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface
1555 // Get pointer at end
1556 uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
1557
1558 // p_desc starts at required interface with alternate setting zero
1559 while (p_desc < p_desc_end)
1560 {
1561 // Find correct interface
1562 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt)
1563 {
1564#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
1565 uint8_t const * p_desc_parse_for_params = p_desc;
1566#endif
1567 // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary
1568 uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints;
1569 while (foundEPs < nEps && p_desc < p_desc_end)
1570 {
1571 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
1572 {
1573 tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1574 TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
1575
1576 uint8_t const ep_addr = desc_ep->bEndpointAddress;
1577
1578 //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND!
1579 usbd_edpt_clear_stall(rhport, ep_addr);
1580
1581#if CFG_TUD_AUDIO_ENABLE_EP_IN
1582 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP
1583 {
1584 // Save address
1585 audio->ep_in = ep_addr;
1586 audio->ep_in_as_intf_num = itf;
1587 audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
1588
1589 // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
1590#if CFG_TUD_AUDIO_ENABLE_ENCODING
1591 audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
1592
1593 // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
1594#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
1595 const uint16_t active_fifo_depth = (audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx;
1596 for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
1597 {
1598 tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
1599 }
1600 audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx;
1601 TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff );
1602#endif
1603
1604#endif
1605 // Invoke callback - can be used to trigger data sampling if not already running
1606 if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
1607
1608 // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded
1609 // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there
1610 TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
1611 }
1612#endif // CFG_TUD_AUDIO_ENABLE_EP_IN
1613
1614#if CFG_TUD_AUDIO_ENABLE_EP_OUT
1615
1616 if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary
1617 {
1618 // Save address
1619 audio->ep_out = ep_addr;
1620 audio->ep_out_as_intf_num = itf;
1621 audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
1622
1623#if CFG_TUD_AUDIO_ENABLE_DECODING
1624 audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
1625
1626 // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
1627#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
1628 const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx;
1629 for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
1630 {
1631 tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
1632 }
1633 audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx;
1634 TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
1635#endif
1636#endif
1637
1638#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1639 // In case of asynchronous EP, call Cb after ep_fb is set
1640 if ( !(desc_ep->bmAttributes.sync == 0x01 && audio->ep_fb == 0) )
1641 {
1642 if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
1643 }
1644#else
1645 // Invoke callback
1646 if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
1647#endif
1648 // Prepare for incoming data
1649#if USE_LINEAR_BUFFER_RX
1650 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
1651#else
1652 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
1653#endif
1654 }
1655
1656#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1657 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback
1658 {
1659 audio->ep_fb = ep_addr;
1660
1661 // Invoke callback after ep_out is set
1662 if (audio->ep_out != 0)
1663 {
1664 if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
1665 }
1666 }
1667#endif
1668#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
1669
1670 foundEPs += 1;
1671 }
1672 p_desc = tu_desc_next(p_desc);
1673 }
1674
1675 TU_VERIFY(foundEPs == nEps);
1676
1677 // We are done - abort loop
1678 break;
1679 }
1680
1681 // Moving forward
1682 p_desc = tu_desc_next(p_desc);
1683 }
1684
1685 tud_control_status(rhport, p_request);
1686
1687 return true;
1688}
1689
1690// Invoked when class request DATA stage is finished.
1691// return false to stall control EP (e.g Host send non-sense DATA)
1692static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
1693{
1694 // Handle audio class specific set requests
1695 if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
1696 {
1697 uint8_t func_id;
1698
1699 switch (p_request->bmRequestType_bit.recipient)
1700 {
1701 case TUSB_REQ_RCPT_INTERFACE:
1702 {
1703 uint8_t itf = TU_U16_LOW(p_request->wIndex);
1704 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
1705
1706 if (entityID != 0)
1707 {
1708 if (tud_audio_set_req_entity_cb)
1709 {
1710 // Check if entity is present and get corresponding driver index
1711 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
1712
1713 // Invoke callback
1714 return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
1715 }
1716 else
1717 {
1718 TU_LOG2(" No entity set request callback available!\r\n");
1719 return false; // In case no callback function is present or request can not be conducted we stall it
1720 }
1721 }
1722 else
1723 {
1724 if (tud_audio_set_req_itf_cb)
1725 {
1726 // Find index of audio driver structure and verify interface really exists
1727 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
1728
1729 // Invoke callback
1730 return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
1731 }
1732 else
1733 {
1734 TU_LOG2(" No interface set request callback available!\r\n");
1735 return false; // In case no callback function is present or request can not be conducted we stall it
1736 }
1737 }
1738 }
1739 break;
1740
1741 case TUSB_REQ_RCPT_ENDPOINT:
1742 {
1743 uint8_t ep = TU_U16_LOW(p_request->wIndex);
1744
1745 if (tud_audio_set_req_ep_cb)
1746 {
1747 // Check if entity is present and get corresponding driver index
1748 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
1749
1750 // Invoke callback
1751 return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
1752 }
1753 else
1754 {
1755 TU_LOG2(" No EP set request callback available!\r\n");
1756 return false; // In case no callback function is present or request can not be conducted we stall it
1757 }
1758 }
1759 break;
1760 // Unknown/Unsupported recipient
1761 default: TU_BREAKPOINT(); return false;
1762 }
1763 }
1764 return true;
1765}
1766
1767// Handle class control request
1768// return false to stall control endpoint (e.g unsupported request)
1769static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
1770{
1771 (void) rhport;
1772
1773 // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here
1774 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
1775 {
1776 switch (p_request->bRequest)
1777 {
1778 case TUSB_REQ_GET_INTERFACE:
1779 return audiod_get_interface(rhport, p_request);
1780
1781 case TUSB_REQ_SET_INTERFACE:
1782 return audiod_set_interface(rhport, p_request);
1783
1784 // Unknown/Unsupported request
1785 default: TU_BREAKPOINT(); return false;
1786 }
1787 }
1788
1789 // Handle class requests
1790 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
1791 {
1792 uint8_t itf = TU_U16_LOW(p_request->wIndex);
1793 uint8_t func_id;
1794
1795 // Conduct checks which depend on the recipient
1796 switch (p_request->bmRequestType_bit.recipient)
1797 {
1798 case TUSB_REQ_RCPT_INTERFACE:
1799 {
1800 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
1801
1802 // Verify if entity is present
1803 if (entityID != 0)
1804 {
1805 // Find index of audio driver structure and verify entity really exists
1806 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
1807
1808 // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
1809 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
1810 {
1811 if (tud_audio_get_req_entity_cb)
1812 {
1813 return tud_audio_get_req_entity_cb(rhport, p_request);
1814 }
1815 else
1816 {
1817 TU_LOG2(" No entity get request callback available!\r\n");
1818 return false; // Stall
1819 }
1820 }
1821 }
1822 else
1823 {
1824 // Find index of audio driver structure and verify interface really exists
1825 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
1826
1827 // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
1828 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
1829 {
1830 if (tud_audio_get_req_itf_cb)
1831 {
1832 return tud_audio_get_req_itf_cb(rhport, p_request);
1833 }
1834 else
1835 {
1836 TU_LOG2(" No interface get request callback available!\r\n");
1837 return false; // Stall
1838 }
1839 }
1840 }
1841 }
1842 break;
1843
1844 case TUSB_REQ_RCPT_ENDPOINT:
1845 {
1846 uint8_t ep = TU_U16_LOW(p_request->wIndex);
1847
1848 // Find index of audio driver structure and verify EP really exists
1849 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
1850
1851 // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
1852 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
1853 {
1854 if (tud_audio_get_req_ep_cb)
1855 {
1856 return tud_audio_get_req_ep_cb(rhport, p_request);
1857 }
1858 else
1859 {
1860 TU_LOG2(" No EP get request callback available!\r\n");
1861 return false; // Stall
1862 }
1863 }
1864 }
1865 break;
1866
1867 // Unknown/Unsupported recipient
1868 default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
1869 }
1870
1871 // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished
1872 TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz));
1873 return true;
1874 }
1875
1876 // There went something wrong - unsupported control request type
1877 TU_BREAKPOINT();
1878 return false;
1879}
1880
1881bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
1882{
1883 if ( stage == CONTROL_STAGE_SETUP )
1884 {
1885 return audiod_control_request(rhport, request);
1886 }
1887 else if ( stage == CONTROL_STAGE_DATA )
1888 {
1889 return audiod_control_complete(rhport, request);
1890 }
1891
1892 return true;
1893}
1894
1895bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
1896{
1897 (void) result;
1898 (void) xferred_bytes;
1899
1900 // Search for interface belonging to given end point address and proceed as required
1901 uint8_t func_id;
1902 for (func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
1903 {
1904
1905#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
1906
1907 // Data transmission of control interrupt finished
1908 if (_audiod_fct[func_id].ep_int_ctr == ep_addr)
1909 {
1910 // According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
1911 // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
1912 // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ???
1913
1914 // I assume here, that things above are handled by PHY
1915 // All transmission is done - what remains to do is to inform job was completed
1916
1917 if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes));
1918 }
1919
1920#endif
1921
1922#if CFG_TUD_AUDIO_ENABLE_EP_IN
1923
1924 // Data transmission of audio packet finished
1925 if (_audiod_fct[func_id].ep_in == ep_addr && _audiod_fct[func_id].alt_setting != 0)
1926 {
1927 // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified."
1928 // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available."
1929 // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP.
1930
1931 // Check if there is data to load into EPs buffer - if not load it with ZLP
1932 // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before!
1933 // This is the only place where we can fill something into the EPs buffer!
1934
1935 // Load new data
1936 TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
1937
1938 // Transmission of ZLP is done by audiod_tx_done_cb()
1939 return true;
1940 }
1941#endif
1942
1943#if CFG_TUD_AUDIO_ENABLE_EP_OUT
1944
1945 // New audio packet received
1946 if (_audiod_fct[func_id].ep_out == ep_addr)
1947 {
1948 TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_fct[func_id], (uint16_t) xferred_bytes));
1949 return true;
1950 }
1951
1952
1953#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1954 // Transmission of feedback EP finished
1955 if (_audiod_fct[func_id].ep_fb == ep_addr)
1956 {
1957 if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
1958
1959 // Schedule a transmit with the new value if EP is not busy
1960 if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
1961 {
1962 // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
1963 return audiod_fb_send(rhport, &_audiod_fct[func_id]);
1964 }
1965 }
1966#endif
1967#endif
1968 }
1969
1970 return false;
1971}
1972
1973bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len)
1974{
1975 // Handles only sending of data not receiving
1976 if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false;
1977
1978 // Get corresponding driver index
1979 uint8_t func_id;
1980 uint8_t itf = TU_U16_LOW(p_request->wIndex);
1981
1982 // Conduct checks which depend on the recipient
1983 switch (p_request->bmRequestType_bit.recipient)
1984 {
1985 case TUSB_REQ_RCPT_INTERFACE:
1986 {
1987 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
1988
1989 // Verify if entity is present
1990 if (entityID != 0)
1991 {
1992 // Find index of audio driver structure and verify entity really exists
1993 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
1994 }
1995 else
1996 {
1997 // Find index of audio driver structure and verify interface really exists
1998 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
1999 }
2000 }
2001 break;
2002
2003 case TUSB_REQ_RCPT_ENDPOINT:
2004 {
2005 uint8_t ep = TU_U16_LOW(p_request->wIndex);
2006
2007 // Find index of audio driver structure and verify EP really exists
2008 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
2009 }
2010 break;
2011
2012 // Unknown/Unsupported recipient
2013 default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
2014 }
2015
2016 // Crop length
2017 if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz;
2018
2019 // Copy into buffer
2020 memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len);
2021
2022 // Schedule transmit
2023 return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len);
2024}
2025
2026// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function
2027// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
2028// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
2029static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int)
2030{
2031 if (audio->p_desc)
2032 {
2033 // Get pointer at end
2034 uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
2035
2036 // Advance past AC descriptors
2037 uint8_t const *p_desc = tu_desc_next(audio->p_desc);
2038 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
2039
2040 uint8_t tmp = 0;
2041 while (p_desc < p_desc_end)
2042 {
2043 // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
2044 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
2045 {
2046 if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
2047 {
2048 *idxItf = tmp;
2049 *pp_desc_int = p_desc;
2050 return true;
2051 }
2052 // Increase index, bytes read, and pointer
2053 tmp++;
2054 }
2055 p_desc = tu_desc_next(p_desc);
2056 }
2057 }
2058 return false;
2059}
2060
2061// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function
2062// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
2063// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
2064static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int)
2065{
2066 // Loop over audio driver interfaces
2067 uint8_t i;
2068 for (i = 0; i < CFG_TUD_AUDIO; i++)
2069 {
2070 if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int))
2071 {
2072 *func_id = i;
2073 return true;
2074 }
2075 }
2076
2077 return false;
2078}
2079
2080// Verify an entity with the given ID exists and returns also the corresponding driver index
2081static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id)
2082{
2083 uint8_t i;
2084 for (i = 0; i < CFG_TUD_AUDIO; i++)
2085 {
2086 // Look for the correct driver by checking if the unique standard AC interface number fits
2087 if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
2088 {
2089 // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between
2090 uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor
2091 uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc;
2092 p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor
2093
2094 while (p_desc < p_desc_end)
2095 {
2096 if (p_desc[3] == entityID) // Entity IDs are always at offset 3
2097 {
2098 *func_id = i;
2099 return true;
2100 }
2101 p_desc = tu_desc_next(p_desc);
2102 }
2103 }
2104 }
2105 return false;
2106}
2107
2108static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id)
2109{
2110 uint8_t i;
2111 for (i = 0; i < CFG_TUD_AUDIO; i++)
2112 {
2113 if (_audiod_fct[i].p_desc)
2114 {
2115 // Get pointer at beginning and end
2116 uint8_t const *p_desc = _audiod_fct[i].p_desc;
2117 uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
2118
2119 while (p_desc < p_desc_end)
2120 {
2121 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
2122 {
2123 *func_id = i;
2124 return true;
2125 }
2126 p_desc = tu_desc_next(p_desc);
2127 }
2128 }
2129 }
2130 return false;
2131}
2132
2133static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
2134{
2135 uint8_t i;
2136 for (i = 0; i < CFG_TUD_AUDIO; i++)
2137 {
2138 if (_audiod_fct[i].p_desc)
2139 {
2140 // Get pointer at end
2141 uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length;
2142
2143 // Advance past AC descriptors - EP we look for are streaming EPs
2144 uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);
2145 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
2146
2147 while (p_desc < p_desc_end)
2148 {
2149 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
2150 {
2151 *func_id = i;
2152 return true;
2153 }
2154 p_desc = tu_desc_next(p_desc);
2155 }
2156 }
2157 }
2158 return false;
2159}
2160
2161#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
2162// p_desc points to the AS interface of alternate setting zero
2163// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter
2164// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
2165static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf)
2166{
2167 p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor
2168
2169 while (p_desc < p_desc_end)
2170 {
2171 // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished
2172 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
2173
2174 // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels
2175 if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL)
2176 {
2177#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2178 if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently
2179#endif
2180#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
2181 if (as_itf != audio->ep_in_as_intf_num) break;
2182#endif
2183#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2184 if (as_itf != audio->ep_out_as_intf_num) break;
2185#endif
2186
2187#if CFG_TUD_AUDIO_ENABLE_EP_IN
2188 if (as_itf == audio->ep_in_as_intf_num)
2189 {
2190 audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
2191 audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
2192
2193#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
2194 audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
2195#endif
2196 }
2197#endif
2198
2199#if CFG_TUD_AUDIO_ENABLE_EP_OUT
2200 if (as_itf == audio->ep_out_as_intf_num)
2201 {
2202 audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
2203 audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
2204#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
2205 audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
2206#endif
2207 }
2208#endif
2209 }
2210
2211 // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
2212#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
2213 if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I)
2214 {
2215#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2216 if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently
2217#endif
2218#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
2219 if (as_itf != audio->ep_in_as_intf_num) break;
2220#endif
2221#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2222 if (as_itf != audio->ep_out_as_intf_num) break;
2223#endif
2224
2225#if CFG_TUD_AUDIO_ENABLE_EP_IN
2226 if (as_itf == audio->ep_in_as_intf_num)
2227 {
2228 audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
2229 }
2230#endif
2231
2232#if CFG_TUD_AUDIO_ENABLE_EP_OUT
2233 if (as_itf == audio->ep_out_as_intf_num)
2234 {
2235 audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
2236 }
2237#endif
2238 }
2239#endif
2240
2241 // Other format types are not supported yet
2242
2243 p_desc = tu_desc_next(p_desc);
2244 }
2245}
2246#endif
2247
2248#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2249
2250// Input value feedback has to be in 16.16 format - the format will be converted according to speed settings automatically
2251bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
2252{
2253 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
2254
2255 // Format the feedback value
2256#if !TUD_OPT_HIGH_SPEED
2257 uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
2258
2259 // For FS format is 10.14
2260 *(fb++) = (feedback >> 2) & 0xFF;
2261 *(fb++) = (feedback >> 10) & 0xFF;
2262 *(fb++) = (feedback >> 18) & 0xFF;
2263 // 4th byte is needed to work correctly with MS Windows
2264 *fb = 0;
2265#else
2266 // For HS format is 16.16 as originally demanded
2267 _audiod_fct[func_id].fb_val = feedback;
2268#endif
2269
2270 // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
2271 if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
2272 {
2273 return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]);
2274 }
2275
2276 return true;
2277}
2278#endif
2279
2280// No security checks here - internal function only which should always succeed
2281uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
2282{
2283 for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++)
2284 {
2285 if (&_audiod_fct[cnt] == audio) return cnt;
2286 }
2287 return 0;
2288}
2289
2290#endif //TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO