arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
USBDeviceAudioAPI.h
1#pragma once
2
3#include "class/audio/audio.h"
4#include "common/tusb_mcu.h"
5#include "common/tusb_verify.h"
6#include "device/usbd.h"
7#include "device/usbd_pvt.h"
8#include "osal/osal.h"
9#include "tusb.h"
10#include "tusb_option.h"
11#include "vector"
12
13#undef OUT_SW_BUF_MEM_SECTION
14#undef CFG_TUSB_MEM_ALIGN
15#define OUT_SW_BUF_MEM_SECTION
16#define CFG_TUSB_MEM_ALIGN
17
18class USBDeviceAudio;
19
20enum {
21 AUDIO_FEEDBACK_METHOD_DISABLED,
22 AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED,
23 AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT,
24 AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, // For driver internal use only
25 AUDIO_FEEDBACK_METHOD_FIFO_COUNT
26};
27
29 uint8_t method;
30 uint32_t sample_freq; // sample frequency in Hz
31
32 union {
33 struct {
34 uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to
35 // which sample clock is based on
36 } frequency;
37 };
38};
39
44 public:
45 int rh_port = 0;
46 uint8_t channels = 2;
47 uint32_t sample_rate = 48000;
48 uint8_t bits_per_sample = 16;
49 bool enable_feedback_ep = true;
50 bool enable_interrupt_ep = true;
51 bool enable_feedback_forward_correction = false;
52 bool enable_feedback_interval_isr = false;
53 bool enable_ep_in_flow_control = true;
54 bool enable_linear_buffer_tx = true;
55 bool enable_linear_buffer_rx = true;
56 bool enable_fifo_mutex = CFG_FIFO_MUTEX;
57 int func_n_as_int = 1;
58 int func_ctl_buffer_size = 0;
59 int func_ep_in_sw_buffer_size = 0;
60 int func_ep_out_sw_buffer_size = 0;
61 int func_ep_in_size_max = 0; // CFG_TUD_AUDIO_EP_SZ_IN
62 int func_ep_out_size_max = 0; // CFG_TUD_AUDIO_EP_SZ_OUT
63 size_t (*p_write_callback)(const uint8_t *data, size_t len,
64 USBDeviceAudio &ref) = nullptr;
65 size_t (*p_read_callback)(uint8_t *data, size_t len,
66 USBDeviceAudio &ref) = nullptr;
67
68 bool is_ep_out() { return p_write_callback != nullptr; }
69 bool is_ep_in() { return p_read_callback != nullptr; };
70
71 // setup (missing) default values
72 void begin() {
73 if (func_ctl_buffer_size == 0) func_ctl_buffer_size = 64;
74 if (func_ep_in_size_max == 0)
75 func_ep_in_size_max =
76 TUD_AUDIO_EP_SIZE(sample_rate, bits_per_sample / 8, channels);
77 if (func_ep_out_size_max == 0)
78 func_ep_out_size_max =
79 TUD_AUDIO_EP_SIZE(sample_rate, bits_per_sample / 8, channels);
80 if (func_ep_out_size_max == 0)
81 func_ep_in_sw_buffer_size =
82 (TUD_OPT_HIGH_SPEED ? 32 : 4) *
83 func_ep_in_size_max; // Example write FIFO every 1ms, so it should be
84 // 8 times larger for HS device
85 if (func_ep_out_sw_buffer_size == 0)
86 func_ep_out_sw_buffer_size =
87 (TUD_OPT_HIGH_SPEED ? 32 : 4) *
88 func_ep_out_size_max; // Example write FIFO every 1ms, so it should
89 // be 8 times larger for HS device
90 }
91 void clear() {
92 func_ctl_buffer_size = 0;
93 func_ep_in_size_max = 0;
94 func_ep_out_size_max = 0;
95 func_ep_in_sw_buffer_size = 0;
96 func_ep_out_sw_buffer_size = 0;
97 }
98};
99
100/***
101 * @brief Basic TinyUSB Audio User Callbacks
102 */
104 public:
105 USBAudioCB() = default;
106 virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
107 uint16_t bufsize) = 0;
108
109 virtual size_t getInterfaceDescriptorLength(uint8_t itfnum) = 0;
110
111 // Invoked when set interface is called, typically on start/stop streaming or
112 // format change
113 virtual bool set_itf_cb(uint8_t rhport,
114 tusb_control_request_t const *p_request) = 0;
115
116 // Invoked when audio class specific set request received for an EP
117 virtual bool set_req_ep_cb(uint8_t rhport,
118 tusb_control_request_t const *p_request,
119 uint8_t *pBuff) = 0;
120
121 // Invoked when audio class specific set request received for an interface
122 virtual bool set_req_itf_cb(uint8_t rhport,
123 tusb_control_request_t const *p_request,
124 uint8_t *pBuff) = 0;
125
126 // Invoked when audio class specific set request received for an entity
127 virtual bool set_req_entity_cb(uint8_t rhport,
128 tusb_control_request_t const *p_request,
129 uint8_t *pBuff) = 0;
130 // Invoked when audio class specific get request received for an EP
131 virtual bool get_req_ep_cb(uint8_t rhport,
132 tusb_control_request_t const *p_request) = 0;
133
134 // Invoked when audio class specific get request received for an interface
135 virtual bool get_req_itf_cb(uint8_t rhport,
136 tusb_control_request_t const *p_request) = 0;
137
138 // Invoked when audio class specific get request received for an entity
139 virtual bool get_req_entity_cb(uint8_t rhport,
140 tusb_control_request_t const *p_request) = 0;
141 virtual bool tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in,
142 uint8_t cur_alt_setting) = 0;
143
144 virtual bool tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied,
145 uint8_t itf, uint8_t ep_in,
146 uint8_t cur_alt_setting) = 0;
147
148 virtual bool rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received,
149 uint8_t func_id, uint8_t ep_out,
150 uint8_t cur_alt_setting) = 0;
151 virtual bool rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received,
152 uint8_t func_id, uint8_t ep_out,
153 uint8_t cur_alt_setting) = 0;
154
155 virtual bool set_itf_close_EP_cb(uint8_t rhport,
156 tusb_control_request_t const *p_request) = 0;
157
158 // for speaker
159 virtual void feedback_params_cb(uint8_t func_id, uint8_t alt_itf,
160 audio_feedback_params_t *feedback_param) = 0;
161
162 virtual void int_done_cb(uint8_t rhport) {};
163 virtual void fb_done_cb(uint8_t func_id) {};
164 virtual void feedback_interval_isr(uint8_t func_id, uint32_t frame_number,
165 uint8_t interval_shift) {}
166
167 virtual uint8_t allocInterface(uint8_t count = 1) = 0;
168 virtual uint8_t allocEndpoint(uint8_t in) = 0;
169
170 int func_id = 0;
171};
172
173/***
174 * @brief Baisc TinyUSB Audio Device Driver as C++ class which does not rely on
175 * preprocesser defines!.
176 */
178 public:
179 bool tud_audio_n_mounted(uint8_t func_id) {
180 TU_VERIFY(func_id < cfg.func_n_as_int);
181 audiod_function_t *audio = &_audiod_fct[func_id];
182
183 return audio->mounted;
184 }
185
186 //--------------------------------------------------------------------+
187 // READ API
188 //--------------------------------------------------------------------+
189
190 uint16_t tud_audio_n_available(uint8_t func_id) {
191 TU_VERIFY(func_id < cfg.func_n_as_int &&
192 _audiod_fct[func_id].p_desc != NULL);
193 return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff);
194 }
195
196 uint16_t tud_audio_n_read(uint8_t func_id, void *buffer, uint16_t bufsize) {
197 TU_VERIFY(func_id < cfg.func_n_as_int &&
198 _audiod_fct[func_id].p_desc != NULL);
199 return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize);
200 }
201
202 bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) {
203 TU_VERIFY(func_id < cfg.func_n_as_int &&
204 _audiod_fct[func_id].p_desc != NULL);
205 return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
206 }
207
208 tu_fifo_t *tud_audio_n_get_ep_out_ff(uint8_t func_id) {
209 if (func_id < cfg.func_n_as_int && _audiod_fct[func_id].p_desc != NULL)
210 return &_audiod_fct[func_id].ep_out_ff;
211 return NULL;
212 }
213
214 //--------------------------------------------------------------------+
215 // WRITE API
216 //--------------------------------------------------------------------+
217
231 uint16_t tud_audio_n_write(uint8_t func_id, const void *data, uint16_t len) {
232 TU_VERIFY(func_id < cfg.func_n_as_int &&
233 _audiod_fct[func_id].p_desc != NULL);
234 return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len);
235 }
236
237 bool tud_audio_n_clear_ep_in_ff(
238 uint8_t func_id) // Delete all content in the EP IN FIFO
239 {
240 TU_VERIFY(func_id < cfg.func_n_as_int &&
241 _audiod_fct[func_id].p_desc != NULL);
242 return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
243 }
244
245 tu_fifo_t *tud_audio_n_get_ep_in_ff(uint8_t func_id) {
246 if (func_id < cfg.func_n_as_int && _audiod_fct[func_id].p_desc != NULL)
247 return &_audiod_fct[func_id].ep_in_ff;
248 return NULL;
249 }
250
251 // If no interrupt transmit is pending bytes get written into buffer and a
252 // transmit is scheduled - once transmit completed tud_audio_int_done_cb() is
253 // called in inform user
254 bool tud_audio_int_n_write(uint8_t func_id,
255 const audio_interrupt_data_t *data) {
256 TU_VERIFY(func_id < cfg.func_n_as_int &&
257 _audiod_fct[func_id].p_desc != NULL);
258
259 TU_VERIFY(_audiod_fct[func_id].ep_int != 0);
260
261 // We write directly into the EP's buffer - abort if previous transfer not
262 // complete
263 TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport,
264 _audiod_fct[func_id].ep_int));
265
266 // Check length
267 if (tu_memcpy_s(_audiod_fct[func_id].ep_int_buf,
268 sizeof(_audiod_fct[func_id].ep_int_buf), data,
269 sizeof(audio_interrupt_data_t)) == 0) {
270 // Schedule transmit
271 TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport,
272 _audiod_fct[func_id].ep_int,
273 _audiod_fct[func_id].ep_int_buf,
274 sizeof(_audiod_fct[func_id].ep_int_buf)),
275 0);
276 } else {
277 // Release endpoint since we don't make any transfer
278 usbd_edpt_release(_audiod_fct[func_id].rhport,
279 _audiod_fct[func_id].ep_int);
280 }
281
282 return true;
283 }
284
285 //--------------------------------------------------------------------+
286 // USBD Driver API
287 //--------------------------------------------------------------------+
288 void begin(USBAudioCB *cb, USBAudioConfig config) {
289 p_cb = cb;
290 cfg = config;
291 cfg.begin();
292 }
293
294 void audiod_init() {
295 if (p_cb == nullptr) return;
296 _audiod_fct.resize(cfg.func_n_as_int);
297 ctrl_buf_1.resize(cfg.func_ctl_buffer_size);
298 alt_setting_1.resize(cfg.func_n_as_int);
299
300 if (cfg.is_ep_in()) {
301 if (cfg.enable_linear_buffer_rx)
302 lin_buf_in_1.resize(cfg.func_ep_in_size_max);
303 audio_ep_in_sw_buf_1.resize(cfg.func_ep_in_sw_buffer_size);
304 }
305
306 if (cfg.is_ep_out()) {
307 if (cfg.enable_linear_buffer_tx)
308 audio_ep_out_sw_buf_1.resize(cfg.func_ep_out_sw_buffer_size);
309 lin_buf_out_1.resize(cfg.func_ep_out_sw_buffer_size);
310 }
311
312 audiod_function_t *audio = &_audiod_fct[0];
313
314 audio->ctrl_buf = ctrl_buf_1.data();
315 audio->ctrl_buf_sz = cfg.func_ctl_buffer_size;
316 audio->alt_setting = alt_setting_1.data();
317
318 // Initialize IN EP FIFO if required
319 if (cfg.is_ep_in()) {
320 tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1.data(),
321 cfg.func_ep_in_sw_buffer_size, 1, true);
322 if (cfg.enable_fifo_mutex)
323 tu_fifo_config_mutex(&audio->ep_in_ff,
324 osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL);
325 }
326 // cfg.is_ep_in() && !ENABLE_ENCODING
327
328 // Initialize linear buffers
329 if (cfg.enable_linear_buffer_tx) audio->lin_buf_in = lin_buf_in_1.data();
330
331 // Initialize OUT EP FIFO if required
332 if (cfg.is_ep_out()) {
333 tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1.data(),
334 cfg.func_ep_in_sw_buffer_size, 1, true);
335 if (cfg.enable_fifo_mutex)
336 tu_fifo_config_mutex(&audio->ep_out_ff, NULL,
337 osal_mutex_create(&ep_out_ff_mutex_rd_1));
338 }
339
340 // Initialize linear buffers
341 if (cfg.enable_linear_buffer_rx) audio->lin_buf_out = lin_buf_out_1.data();
342 }
343
344 bool audiod_deinit(void) { return true; }
345
346 void audiod_reset(uint8_t rhport) {
347 (void)rhport;
348
349 for (uint8_t i = 0; i < cfg.func_n_as_int; i++) {
350 audiod_function_t *audio = &_audiod_fct[i];
351 tu_memclr(audio, sizeof(audiod_function_t));
352
353 if (cfg.is_ep_in()) tu_fifo_clear(&audio->ep_in_ff);
354
355 if (cfg.is_ep_out()) tu_fifo_clear(&audio->ep_out_ff);
356 }
357 }
358
359 uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
360 uint16_t max_len) {
361 (void)max_len;
362 if (p_cb == nullptr) return 0;
363
364 int cls_tobe = TUSB_CLASS_AUDIO;
365 int cls_is = itf_desc->bInterfaceClass;
366
367 // TU_VERIFY(TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass &&
368 // AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass);
369
370 // // Verify version is correct - this check can be omitted
371 // TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
372
373 // Verify interrupt control EP is enabled if demanded by descriptor
374 TU_ASSERT(itf_desc->bNumEndpoints <= 1); // 0 or 1 EPs are allowed
375 if (itf_desc->bNumEndpoints == 1) {
376 TU_ASSERT(cfg.enable_interrupt_ep);
377 }
378
379 // Alternate setting MUST be zero - this check can be omitted
380 TU_VERIFY(itf_desc->bAlternateSetting == 0);
381
382 // Find available audio driver interface
383 uint8_t i;
384 for (i = 0; i < cfg.func_n_as_int; i++) {
385 if (!_audiod_fct[i].p_desc) {
386 int len = p_cb->getInterfaceDescriptor(i, nullptr, 0);
387 _audiod_fct[i].desc_length = len;
388 descriptor.resize(len);
389 _audiod_fct[i].p_desc = descriptor.data();
390 p_cb->getInterfaceDescriptor(i, descriptor.data(), len);
391 _audiod_fct[i].rhport = rhport;
392
393#ifdef TUP_DCD_EDPT_ISO_ALLOC
394 {
395 uint8_t ep_in = 0;
396 uint16_t ep_in_size = 0;
397
398 uint8_t ep_out = 0;
399 uint16_t ep_out_size = 0;
400
401 uint8_t ep_fb = 0;
402 uint8_t const *p_desc = _audiod_fct[i].p_desc;
403 uint8_t const *p_desc_end =
404 p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
405 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
406 // strict-overflow warning
407 while (p_desc_end - p_desc > 0) {
408 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
409 tusb_desc_endpoint_t const *desc_ep =
410 (tusb_desc_endpoint_t const *)p_desc;
411 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
412 if (cfg.enable_feedback_ep) {
413 // Explicit feedback EP
414 if (desc_ep->bmAttributes.usage == 1) {
415 ep_fb = desc_ep->bEndpointAddress;
416 }
417 }
418 // Data EP
419 if (desc_ep->bmAttributes.usage == 0) {
420 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
421 if (cfg.is_ep_in()) {
422 ep_in = desc_ep->bEndpointAddress;
423 ep_in_size =
424 TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
425 }
426 } else {
427 if (cfg.is_ep_out()) {
428 ep_out = desc_ep->bEndpointAddress;
429 ep_out_size =
430 TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
431 }
432 }
433 }
434 }
435 }
436
437 p_desc = tu_desc_next(p_desc);
438 }
439
440 if (cfg.is_ep_in() && ep_in) {
441 usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size);
442 }
443
444
445 if (cfg.is_ep_out() && ep_out) {
446 usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size);
447 }
448
449 if (cfg.enable_feedback_ep) {
450 if (ep_fb) {
451 usbd_edpt_iso_alloc(rhport, ep_fb, 4);
452 }
453 }
454 }
455
456#endif // TUP_DCD_EDPT_ISO_ALLOC
457
458 if (cfg.is_ep_in() && cfg.enable_ep_in_flow_control) {
459 uint8_t const *p_desc = _audiod_fct[i].p_desc;
460 uint8_t const *p_desc_end =
461 p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
462 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
463 // strict-overflow warning
464 while (p_desc_end - p_desc > 0) {
465 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
466 tusb_desc_endpoint_t const *desc_ep =
467 (tusb_desc_endpoint_t const *)p_desc;
468 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
469 if (desc_ep->bmAttributes.usage == 0) {
470 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
471 _audiod_fct[i].interval_tx = desc_ep->bInterval;
472 }
473 }
474 }
475 } else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE &&
476 tu_desc_subtype(p_desc) ==
477 AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) {
478 if (tu_unaligned_read16(p_desc + 4) ==
479 AUDIO_TERM_TYPE_USB_STREAMING) {
480 _audiod_fct[i].bclock_id_tx = p_desc[8];
481 }
482 }
483 p_desc = tu_desc_next(p_desc);
484 }
485 } // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
486
487 if (cfg.enable_interrupt_ep) {
488 uint8_t const *p_desc = _audiod_fct[i].p_desc;
489 uint8_t const *p_desc_end =
490 p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
491 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
492 // strict-overflow warning
493 while (p_desc_end - p_desc > 0) {
494 // For each endpoint
495 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
496 tusb_desc_endpoint_t const *desc_ep =
497 (tusb_desc_endpoint_t const *)p_desc;
498 uint8_t const ep_addr = desc_ep->bEndpointAddress;
499 // If endpoint is input-direction and interrupt-type
500 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN &&
501 desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) {
502 // Store endpoint number and open endpoint
503 _audiod_fct[i].ep_int = ep_addr;
504 TU_ASSERT(usbd_edpt_open(_audiod_fct[i].rhport, desc_ep));
505 }
506 }
507 p_desc = tu_desc_next(p_desc);
508 }
509 }
510
511 _audiod_fct[i].mounted = true;
512 break;
513 }
514 }
515
516 // Verify we found a free one
517 TU_ASSERT(i < cfg.func_n_as_int);
518
519 // This is all we need so far - the EPs are setup by a later set_interface
520 // request (as per UAC2 specification)
521 uint16_t drv_len =
522 _audiod_fct[i].desc_length -
523 TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB
524 // already handles the IAD descriptor
525
526 return drv_len;
527 }
528
529 // Handle class co
530 bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage,
531 tusb_control_request_t const *request) {
532 if (stage == CONTROL_STAGE_SETUP) {
533 return audiod_control_request(rhport, request);
534 } else if (stage == CONTROL_STAGE_DATA) {
535 return audiod_control_complete(rhport, request);
536 }
537
538 return true;
539 }
540
541 bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
542 uint32_t xferred_bytes) {
543 (void)result;
544 (void)xferred_bytes;
545
546 // Search for interface belonging to given end point address and proceed
547 // as required
548 for (uint8_t func_id = 0; func_id < cfg.func_n_as_int; func_id++) {
549 audiod_function_t *audio = &_audiod_fct[func_id];
550
551 if (cfg.enable_interrupt_ep) {
552 // Data transmission of control interrupt finished
553 if (audio->ep_int == ep_addr) {
554 // According to USB2 specification, maximum payload of interrupt EP
555 // is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes
556 // on high speed (but only if an alternate interface other than 0 is
557 // used
558 // - see specification p. 49) In case there is nothing to send we
559 // have to return a NAK - this is taken care of by PHY ??? In case
560 // of an erroneous transmission a retransmission is conducted - this
561 // is taken care of by PHY ???
562
563 // I assume here, that things above are handled by PHY
564 // All transmission is done - what remains to do is to inform job
565 // was completed
566
567 if (p_cb) p_cb->int_done_cb(rhport);
568 return true;
569 }
570 }
571 if (cfg.is_ep_in()) {
572 // Data transmission of audio packet finished
573 if (audio->ep_in == ep_addr && audio->alt_setting != 0) {
574 // USB 2.0, section 5.6.4, third paragraph, states "An isochronous
575 // endpoint must specify its required bus access period. However, an
576 // isochronous endpoint must be prepared to handle poll rates faster
577 // than the one specified." That paragraph goes on to say "An
578 // isochronous IN endpoint must return a zero-length packet whenever
579 // data is requested at a faster interval than the specified
580 // interval and data is not available." This can only be solved
581 // reliably if we load a ZLP after every IN transmission since we
582 // can not say if the host requests samples earlier than we
583 // declared! Once all samples are collected we overwrite the loaded
584 // ZLP.
585
586 // Check if there is data to load into EPs buffer - if not load it
587 // with ZLP Be aware - we as a device are not able to know if the
588 // host polls for data with a faster rate as we stated this in the
589 // descriptors. Therefore we always have to put something into the
590 // EPs buffer. However, once we did that, there is no way of
591 // aborting this or replacing what we put into the buffer before!
592 // This is the only place where we can fill something into the EPs
593 // buffer!
594
595 // Load new data
596 TU_VERIFY(audiod_tx_done_cb(rhport, audio));
597
598 // Transmission of ZLP is done by audiod_tx_done_cb()
599 return true;
600 }
601 }
602
603 if (cfg.is_ep_out()) {
604 // New audio packet received
605 if (audio->ep_out == ep_addr) {
606 TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t)xferred_bytes));
607 return true;
608 }
609
610 if (cfg.enable_feedback_ep) {
611 // Transmission of feedback EP finished
612 if (audio->ep_fb == ep_addr) {
613 if (p_cb) p_cb->fb_done_cb(func_id);
614
615 // Schedule a transmit with the new value if EP is not busy
616 if (!usbd_edpt_busy(rhport, audio->ep_fb)) {
617 // Schedule next transmission - value is changed
618 // bytud_audio_n_fb_set() in the meantime or the old value gets
619 // sent
620 return audiod_fb_send(rhport, audio);
621 }
622 }
623 }
624 }
625 }
626
627 return false;
628 }
629
630 bool tud_audio_buffer_and_schedule_control_xfer(
631 uint8_t rhport, tusb_control_request_t const *p_request, void *data,
632 uint16_t len) {
633 // Handles only sending of data not receiving
634 if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false;
635
636 // Get corresponding driver index
637 uint8_t func_id;
638 uint8_t itf = TU_U16_LOW(p_request->wIndex);
639
640 // Conduct checks which depend on the recipient
641 switch (p_request->bmRequestType_bit.recipient) {
642 case TUSB_REQ_RCPT_INTERFACE: {
643 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
644
645 // Verify if entity is present
646 if (entityID != 0) {
647 // Find index of audio driver structure and verify entity really
648 // exists
649 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
650 } else {
651 // Find index of audio driver structure and verify interface really
652 // exists
653 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
654 }
655 } break;
656
657 case TUSB_REQ_RCPT_ENDPOINT: {
658 uint8_t ep = TU_U16_LOW(p_request->wIndex);
659
660 // Find index of audio driver structure and verify EP really exists
661 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
662 } break;
663
664 // Unknown/Unsupported recipient
665 default:
666 TU_LOG2(" Unsupported recipient: %d\r\n",
667 p_request->bmRequestType_bit.recipient);
668 TU_BREAKPOINT();
669 return false;
670 }
671
672 // Crop length
673 if (len > _audiod_fct[func_id].ctrl_buf_sz)
674 len = _audiod_fct[func_id].ctrl_buf_sz;
675
676 // Copy into buffer
677 TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf,
678 _audiod_fct[func_id].ctrl_buf_sz, data,
679 (size_t)len));
680
681 if (cfg.is_ep_in() && cfg.enable_ep_in_flow_control) {
682 // Find data for sampling_frequency_control
683 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
684 p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) {
685 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
686 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
687 if (_audiod_fct[func_id].bclock_id_tx == entityID &&
688 ctrlSel == AUDIO_CS_CTRL_SAM_FREQ &&
689 p_request->bRequest == AUDIO_CS_REQ_CUR) {
690 _audiod_fct[func_id].sample_rate_tx =
691 tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
692 }
693 }
694 }
695
696 // Schedule transmit
697 return tud_control_xfer(rhport, p_request,
698 (void *)_audiod_fct[func_id].ctrl_buf, len);
699 }
700
701 bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) {
702 TU_VERIFY(func_id < cfg.func_n_as_int &&
703 _audiod_fct[func_id].p_desc != NULL);
704
705 // Format the feedback value
706 if (cfg.enable_feedback_forward_correction) {
707 if (TUSB_SPEED_FULL == tud_speed_get()) {
708 uint8_t *fb = (uint8_t *)&_audiod_fct[func_id].feedback.value;
709
710 // For FS format is 10.14
711 *(fb++) = (feedback >> 2) & 0xFF;
712 *(fb++) = (feedback >> 10) & 0xFF;
713 *(fb++) = (feedback >> 18) & 0xFF;
714 // 4th byte is needed to work correctly with MS Windows
715 *fb = 0;
716 }
717 } else {
718 // Send value as-is, caller will choose the appropriate format
719 _audiod_fct[func_id].feedback.value = feedback;
720 }
721 // Schedule a transmit with the new value if EP is not busy - this
722 // triggers repetitive scheduling of the feedback value
723 if (!usbd_edpt_busy(_audiod_fct[func_id].rhport,
724 _audiod_fct[func_id].ep_fb)) {
725 return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]);
726 }
727
728 return true;
729 }
730
731 void audiod_sof_isr(uint8_t rhport, uint32_t frame_count) {
732 (void)rhport;
733 (void)frame_count;
734
735 if (cfg.is_ep_out() && cfg.enable_feedback_ep) {
736 // Determine feedback value - The feedback method is described
737 // in 5.12.4.2 of the USB 2.0 spec Boiled down, the feedback value Ff =
738 // n_samples / (micro)frame. Since an accuracy of less than 1 Sample /
739 // second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames
740 // need to be measured, where K = 10 for full speed and K = 13 for high
741 // speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu
742 // clock frequency e.g. 100 MHz (or any other master clock whose clock
743 // count is available and locked to f_s) The update interval in the
744 // (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K
745 // - P), where P = min( ceil(log2(f_m / f_s)), K) feedback = n_cycles /
746 // n_frames * f_s / f_m in 16.16 format, where n_cycles are the number
747 // of main clock cycles within fb_n_frames
748
749 // Iterate over audio functions and set feedback value
750 for (uint8_t i = 0; i < cfg.func_n_as_int; i++) {
751 audiod_function_t *audio = &_audiod_fct[i];
752
753 if (audio->ep_fb != 0) {
754 // HS shift need to be adjusted since SOF event is generated for
755 // frame only
756 uint8_t const hs_adjust =
757 (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0;
758 uint32_t const interval =
759 1UL << (audio->feedback.frame_shift - hs_adjust);
760 if (0 == (frame_count & (interval - 1))) {
761 if (cfg.enable_feedback_interval_isr && p_cb)
762 p_cb->feedback_interval_isr(i, frame_count,
763 audio->feedback.frame_shift);
764 }
765 }
766 }
767 } // cfg.is_ep_out() && cfg.enable_feedback_ep
768 }
769
770 USBAudioConfig &config() { return cfg; }
771
772 protected:
773 USBAudioCB *p_cb = nullptr;
774 USBAudioConfig cfg;
775 // Linear buffer TX in case:
776 // - target MCU is not capable of handling a ring buffer FIFO e.g. no
777 // hardware buffer is available or driver is would need to be changed
778 // dramatically OR
779 // - the software encoding is used - in this case the linear buffers serve
780 // as a target memory where logical channels are encoded into
781 std::vector<CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t>
782 lin_buf_in_1; //[cfg.func_ep_in_size_max];
783
784 std::vector<OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t>
785 audio_ep_in_sw_buf_1; //[cfg.func_ep_in_sw_buffer_size];
786
787 std::vector<OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t>
788 audio_ep_out_sw_buf_1; //[cfg.func_ep_in_sw_buffer_size];
789
790 // Linear buffer RX in case:
791 // - target MCU is not capable of handling a ring buffer FIFO e.g. no
792 // hardware buffer is available or driver is would need to be changed
793 // dramatically OR
794 // - the software encoding is used - in this case the linear buffers serve
795 // as a target memory where logical channels are encoded into
796 std::vector<CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t>
797 lin_buf_out_1; //[FUNC_1_EP_OUT_SZ_MAX];
798
799 // Control buffers
800 std::vector<CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t>
801 ctrl_buf_1; //[cfg.func_ctl_buffer_size];
802
803 // Active alternate setting of interfaces
804 std::vector<uint8_t> alt_setting_1; //[cfg.func_n_as_int];
805
806 // buffer for descriptor
807 std::vector<uint8_t> descriptor;
808
809 // EP IN software buffers and mutexes
810 // TUP_DCD_EDPT_ISO_ALLOC[cfg.func_ep_in_sw_buffer_size];
811 osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB
812 // driver reads from FIFO
813
814 osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only
815 // USB driver writes into FIFO
816
819 memset(this,0, sizeof(audiod_function_t));
820 }
821 uint8_t n_bytes_per_sample_tx;
822 uint8_t n_channels_tx;
823 uint8_t format_type_tx = AUDIO_FORMAT_TYPE_I;
824
825 uint8_t rhport;
826 uint8_t const
827 *p_desc = nullptr; // Pointer pointing to Standard AC Interface
828 // Descriptor(4.7.1)
829 // - Audio Control descriptor defining audio function
830
831 uint8_t ep_in; // TX audio data EP.
832 uint16_t ep_in_sz; // Current size of TX EP
833 uint8_t
834 ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor
835 // (4.9.1) belonging to output terminal to which
836 // this EP belongs - 0 is invalid (this fits to
837 // UAC2 specification since AS interfaces can not
838 // have interface number equal to zero)
839 uint8_t ep_out; // Incoming (into uC) audio data EP.
840 uint16_t ep_out_sz; // Current size of RX EP
841 uint8_t
842 ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor
843 // (4.9.1) belonging to input terminal to which
844 // this EP belongs - 0 is invalid (this fits to
845 // UAC2 specification since AS interfaces can not
846 // have interface number equal to zero)
847
848 uint8_t ep_fb; // Feedback EP.
849
850 uint8_t ep_int; // Audio control interrupt EP.
851
852 bool mounted; // Device opened
853
854 /*------------- From this point, data is not cleared by bus reset
855 * -------------*/
856
857 uint16_t desc_length; // Length of audio function descriptor
858
859 struct feedback {
860 CFG_TUSB_MEM_ALIGN uint32_t
861 value; // Feedback value for asynchronous mode (in 16.16 format).
862 uint32_t
863 min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
864 uint32_t
865 max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
866
867 uint8_t
868 frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
869 uint8_t compute_method;
870
871 union {
872 uint8_t power_of_2; // pre-computed power of 2 shift
873 float float_const; // pre-computed float constant
874
875 struct {
876 uint32_t sample_freq;
877 uint32_t mclk_freq;
878 } fixed;
879
880 } compute;
881
882 } feedback;
883
884 // Decoding parameters - parameters are set when alternate AS interface is
885 // set by host Coding is currently only supported for EP. Software coding
886 // corresponding to AS interfaces without EPs are not supported currently.
887 uint32_t sample_rate_tx;
888 uint16_t packet_sz_tx[3];
889 uint8_t bclock_id_tx;
890 uint8_t interval_tx;
891
892 // Encoding parameters - parameters are set when alternate AS interface is
893 // set by host
894
895 // Buffer for control requests
896 uint8_t *ctrl_buf;
897 uint8_t ctrl_buf_sz;
898
899 // Current active alternate settings
900 uint8_t *alt_setting; // We need to save the current alternate setting
901 // this way, because it is possible that there are
902 // AS interfaces which do not have an EP!
903
904 // EP Transfer buffers and FIFOs
905 tu_fifo_t ep_out_ff;
906 tu_fifo_t ep_in_ff;
907
908 // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2
909 // specification (p. 74)
910 CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
911
912 // Linear buffer in case target MCU is not capable of handling a ring
913 // buffer FIFO e.g. no hardware buffer is available or driver is would
914 // need to be changed dramatically OR the support FIFOs are used
915 uint8_t *lin_buf_out;
916 uint8_t *lin_buf_in;
917 };
918
919 //--------------------------------------------------------------------+
920 // INTERNAL OBJECT & FUNCTION DECLARATION
921 //--------------------------------------------------------------------+
922 std::vector<CFG_TUD_MEM_SECTION audiod_function_t> _audiod_fct;
923
924 // No security checks here - internal function only which should always
925 // succeed
926 uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio) {
927 for (uint8_t cnt = 0; cnt < cfg.func_n_as_int; cnt++) {
928 if (&_audiod_fct[cnt] == audio) return cnt;
929 }
930 return 0;
931 }
932
933 inline uint8_t tu_desc_subtype(void const *desc) {
934 return ((uint8_t const *)desc)[2];
935 }
936
937 bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio,
938 uint16_t n_bytes_received) {
939 uint8_t idxItf = 0;
940 uint8_t const *dummy2;
941 uint8_t idx_audio_fct = 0;
942
943 if (p_cb) {
944 idx_audio_fct = audiod_get_audio_fct_idx(audio);
945 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio,
946 &idxItf, &dummy2));
947 }
948
949 // Call a weak callback here - a possibility for user to get informed an
950 // audio packet was received and data gets now loaded into EP FIFO (or
951 // decoded into support RX software FIFO)
952 if (p_cb) {
953 TU_VERIFY(p_cb->rx_done_pre_read_cb(rhport, n_bytes_received,
954 idx_audio_fct, audio->ep_out,
955 audio->alt_setting[idxItf]));
956 }
957
958 if (cfg.enable_linear_buffer_rx) {
959 // Data currently is in linear buffer, copy into EP OUT FIFO
960 TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out,
961 n_bytes_received));
962
963 // Schedule for next receive
964 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out,
965 audio->ep_out_sz),
966 false);
967 } else {
968 // Data is already placed in EP FIFO, schedule for next receive
969 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff,
970 audio->ep_out_sz),
971 false);
972 }
973
974 // Call a weak callback here - a possibility for user to get informed
975 // decoding was completed
976 if (p_cb) {
977 TU_VERIFY(p_cb->rx_done_post_read_cb(rhport, n_bytes_received,
978 idx_audio_fct, audio->ep_out,
979 audio->alt_setting[idxItf]));
980 }
981
982 return true;
983 }
984
985 // This function is called once a transmit of an audio packet was
986 // successfully completed. Here, we encode samples and place it in IN EP's
987 // buffer for next transmission. If you prefer your own (more efficient)
988 // implementation suiting your purpose set ENABLE_ENCODING = 0 and use
989 // tud_audio_n_write.
990
991 // n_bytes_copied - Informs caller how many bytes were loaded. In case
992 // n_bytes_copied = 0, a ZLP is scheduled to inform host no data is
993 // available for current frame.
994
995 bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) {
996 uint8_t idxItf;
997 uint8_t const *dummy2;
998
999 uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
1000 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio,
1001 &idxItf, &dummy2));
1002
1003 // Only send something if current alternate interface is not 0 as in this
1004 // case nothing is to be sent due to UAC2 specifications
1005 if (audio->alt_setting[idxItf] == 0) return false;
1006
1007 // Call a weak callback here - a possibility for user to get informed
1008 // former TX was completed and data gets now loaded into EP in buffer (in
1009 // case FIFOs are used) or if no FIFOs are used the user may use this call
1010 // back to load its data into the EP IN buffer by use of
1011 // tud_audio_n_write_ep_in_buffer().
1012 if (p_cb)
1013 TU_VERIFY(p_cb->tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in,
1014 audio->alt_setting[idxItf]));
1015
1016 // Send everything in ISO EP FIFO
1017 uint16_t n_bytes_tx;
1018
1019 // If support FIFOs are used, encode and schedule transmit
1020 // No support FIFOs, if no linear buffer required schedule transmit, else
1021 // put data into linear buffer and schedule
1022 if (cfg.enable_ep_in_flow_control) {
1023 // packet_sz_tx is based on total packet size, here we want size for
1024 // each support buffer.
1025 n_bytes_tx = audiod_tx_packet_size(
1026 audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff),
1027 audio->ep_in_ff.depth, audio->ep_in_sz);
1028 } else {
1029 n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff),
1030 audio->ep_in_sz); // Limit up to max packet size,
1031 // more can not be done for ISO
1032 }
1033 if (cfg.enable_linear_buffer_tx) {
1034 tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
1035 TU_VERIFY(
1036 usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
1037 } else {
1038 // Send everything in ISO EP FIFO
1039 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff,
1040 n_bytes_tx));
1041 }
1042
1043 // Call a weak callback here - a possibility for user to get informed
1044 // former TX was completed and how many bytes were loaded for the next
1045 // frame
1046 if (p_cb)
1047 TU_VERIFY(p_cb->tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct,
1048 audio->ep_in,
1049 audio->alt_setting[idxItf]));
1050 return true;
1051 }
1052
1053 // This function is called once a transmit of a feedback packet was
1054 // successfully completed. Here, we get the next feedback value to be sent
1055
1056 inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) {
1057 return usbd_edpt_xfer(rhport, audio->ep_fb,
1058 (uint8_t *)&audio->feedback.value, 4);
1059 }
1060
1061 bool audiod_set_interface(uint8_t rhport,
1062 tusb_control_request_t const *p_request) {
1063 (void)rhport;
1064
1065 // Here we need to do the following:
1066
1067 // 1. Find the audio driver assigned to the given interface to be set
1068 // Since one audio driver interface has to be able to cover an unknown
1069 // number of interfaces (AC, AS + its alternate settings), the best memory
1070 // efficient way to solve this is to always search through the
1071 // descriptors. The audio driver is mapped to an audio function by a
1072 // reference pointer to the corresponding AC interface of this audio
1073 // function which serves as a starting point for searching
1074
1075 // 2. Close EPs which are currently open
1076 // To do so it is not necessary to know the current active alternate
1077 // interface since we already save the current EP addresses - we simply
1078 // close them
1079
1080 // 3. Open new EP
1081
1082 uint8_t const itf = tu_u16_low(p_request->wIndex);
1083 uint8_t const alt = tu_u16_low(p_request->wValue);
1084
1085 TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt);
1086
1087 // Find index of audio streaming interface and index of interface
1088 uint8_t func_id, idxItf;
1089 uint8_t const *p_desc;
1090 TU_VERIFY(
1091 audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
1092
1093 audiod_function_t *audio = &_audiod_fct[func_id];
1094
1095 // Look if there is an EP to be closed - for this driver, there are only 3
1096 // possible EPs which may be closed (only AS related EPs can be closed, AC
1097 // EP (if present) is always open)
1098 if (cfg.is_ep_in()) {
1099 if (audio->ep_in_as_intf_num == itf) {
1100 audio->ep_in_as_intf_num = 0;
1101#ifndef TUP_DCD_EDPT_ISO_ALLOC
1102 usbd_edpt_close(rhport, audio->ep_in);
1103#endif
1104
1105 // Clear FIFOs, since data is no longer valid
1106 tu_fifo_clear(&audio->ep_in_ff);
1107
1108 // Invoke callback - can be used to stop data sampling
1109 if (p_cb) TU_VERIFY(p_cb->set_itf_close_EP_cb(rhport, p_request));
1110
1111 audio->ep_in = 0; // Necessary?
1112
1113 if (cfg.enable_ep_in_flow_control) {
1114 audio->packet_sz_tx[0] = 0;
1115 audio->packet_sz_tx[1] = 0;
1116 audio->packet_sz_tx[2] = 0;
1117 }
1118 }
1119 }
1120
1121 if (cfg.is_ep_out()) {
1122 if (audio->ep_out_as_intf_num == itf) {
1123 audio->ep_out_as_intf_num = 0;
1124#ifndef TUP_DCD_EDPT_ISO_ALLOC
1125 usbd_edpt_close(rhport, audio->ep_out);
1126#endif
1127
1128 // Clear FIFOs, since data is no longer valid
1129 tu_fifo_clear(&audio->ep_out_ff);
1130 // Invoke callback - can be used to stop data sampling
1131 if (p_cb) TU_VERIFY(p_cb->set_itf_close_EP_cb(rhport, p_request));
1132
1133 audio->ep_out = 0; // Necessary?
1134
1135 // Close corresponding feedback EP
1136 if (cfg.enable_feedback_ep) {
1137#ifndef TUP_DCD_EDPT_ISO_ALLOC
1138 usbd_edpt_close(rhport, audio->ep_fb);
1139#endif
1140 audio->ep_fb = 0;
1141 tu_memclr(&audio->feedback, sizeof(audio->feedback));
1142 }
1143 }
1144 } // cfg.is_ep_out()
1145
1146 // Save current alternative interface setting
1147 audio->alt_setting[idxItf] = alt;
1148
1149 // Open new EP if necessary - EPs are only to be closed or opened for AS
1150 // interfaces - Look for AS interface with correct alternate interface Get
1151 // pointer at end
1152 uint8_t const *p_desc_end =
1153 audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
1154
1155 // p_desc starts at required interface with alternate setting zero
1156 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1157 // strict-overflow warning
1158 while (p_desc_end - p_desc > 0) {
1159 // Find correct interface
1160 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE &&
1161 ((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber == itf &&
1162 ((tusb_desc_interface_t const *)p_desc)->bAlternateSetting == alt) {
1163 uint8_t const *p_desc_parse_for_params = p_desc;
1164 // From this point forward follow the EP descriptors associated to the
1165 // current alternate setting interface - Open EPs if necessary
1166 uint8_t foundEPs = 0,
1167 nEps = ((tusb_desc_interface_t const *)p_desc)->bNumEndpoints;
1168 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1169 // strict-overflow warning
1170 while (foundEPs < nEps && (p_desc_end - p_desc > 0)) {
1171 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
1172 tusb_desc_endpoint_t const *desc_ep =
1173 (tusb_desc_endpoint_t const *)p_desc;
1174#ifdef TUP_DCD_EDPT_ISO_ALLOC
1175 TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep));
1176#else
1177 TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
1178#endif
1179 uint8_t const ep_addr = desc_ep->bEndpointAddress;
1180
1181 // TODO: We need to set EP non busy since this is not taken care
1182 // of right now in ep_close() - THIS IS A WORKAROUND!
1183 usbd_edpt_clear_stall(rhport, ep_addr);
1184
1185 if (cfg.is_ep_in()) {
1186 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN &&
1187 desc_ep->bmAttributes.usage ==
1188 0x00) // Check if usage is data EP
1189 {
1190 // Save address
1191 audio->ep_in = ep_addr;
1192 audio->ep_in_as_intf_num = itf;
1193 audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
1194
1195 // If software encoding is enabled, parse for the
1196 // corresponding parameters - doing this here means only AS
1197 // interfaces with EPs get scanned for parameters
1198 if (cfg.enable_ep_in_flow_control)
1199 audiod_parse_for_AS_params(audio, p_desc_parse_for_params,
1200 p_desc_end, itf);
1201
1202 // Reconfigure size of support FIFOs - this is necessary to
1203 // avoid samples to get split in case of a wrap
1204
1205 // Schedule first transmit if alternate interface is not zero
1206 // i.e. streaming is disabled - in case no sample data is
1207 // available a ZLP is loaded It is necessary to trigger this
1208 // here since the refill is done with an RX FIFO empty
1209 // interrupt which can only trigger if something was in there
1210 TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
1211 }
1212 } // cfg.is_ep_in()
1213
1214 if (cfg.is_ep_out()) {
1215 if (tu_edpt_dir(ep_addr) ==
1216 TUSB_DIR_OUT) // Checking usage not necessary
1217 {
1218 // Save address
1219 audio->ep_out = ep_addr;
1220 audio->ep_out_as_intf_num = itf;
1221 audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
1222
1223 // Prepare for incoming data
1224 if (cfg.enable_linear_buffer_rx) {
1225 TU_VERIFY(
1226 usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out,
1227 audio->ep_out_sz),
1228 false);
1229 } else {
1230 TU_VERIFY(
1231 usbd_edpt_xfer_fifo(rhport, audio->ep_out,
1232 &audio->ep_out_ff, audio->ep_out_sz),
1233 false);
1234 }
1235 }
1236
1237 if (cfg.enable_feedback_ep) {
1238 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN &&
1239 desc_ep->bmAttributes.usage ==
1240 1) // Check if usage is explicit data feedback
1241 {
1242 audio->ep_fb = ep_addr;
1243 audio->feedback.frame_shift = desc_ep->bInterval - 1;
1244
1245 // Enable SOF interrupt if callback is implemented
1246 if (cfg.enable_feedback_interval_isr)
1247 usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, true);
1248 }
1249 }
1250 } // cfg.is_ep_out()
1251
1252 foundEPs += 1;
1253 }
1254 p_desc = tu_desc_next(p_desc);
1255 }
1256
1257 TU_VERIFY(foundEPs == nEps);
1258
1259 // Invoke one callback for a final set interface
1260 if (p_cb) TU_VERIFY(p_cb->set_itf_cb(rhport, p_request));
1261
1262 if (cfg.enable_feedback_ep) {
1263 // Prepare feedback computation if callback is available
1264 if (p_cb) {
1265 audio_feedback_params_t fb_param;
1266
1267 p_cb->feedback_params_cb(func_id, alt, &fb_param);
1268 audio->feedback.compute_method = fb_param.method;
1269
1270 // Minimal/Maximum value in 16.16 format for full speed (1ms per
1271 // frame) or high speed (125 us per frame)
1272 uint32_t const frame_div =
1273 (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
1274 audio->feedback.min_value = (fb_param.sample_freq / frame_div - 1)
1275 << 16;
1276 audio->feedback.max_value = (fb_param.sample_freq / frame_div + 1)
1277 << 16;
1278
1279 switch (fb_param.method) {
1280 case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
1281 case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
1282 case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
1283 set_fb_params_freq(audio, fb_param.sample_freq,
1284 fb_param.frequency.mclk_freq);
1285 break;
1286
1287 // nothing to do
1288 default:
1289 break;
1290 }
1291 }
1292 } // cfg.enable_feedback_ep
1293
1294 // We are done - abort loop
1295 break;
1296 }
1297
1298 // Moving forward
1299 p_desc = tu_desc_next(p_desc);
1300 }
1301
1302 if (cfg.enable_feedback_ep) {
1303 // Disable SOF interrupt if no driver has any enabled feedback EP
1304 bool disable = true;
1305 for (uint8_t i = 0; i < cfg.func_n_as_int; i++) {
1306 if (_audiod_fct[i].ep_fb != 0) {
1307 disable = false;
1308 break;
1309 }
1310 }
1311 if (disable) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, false);
1312 }
1313
1314 if (cfg.is_ep_in() && cfg.enable_ep_in_flow_control)
1315 audiod_calc_tx_packet_sz(audio);
1316
1317 tud_control_status(rhport, p_request);
1318
1319 return true;
1320 }
1321
1322 // Invoked when class request DATA stage is finished.
1323 // return false to stall control EP (e.g Host send non-sense DATA)
1324 bool audiod_control_complete(uint8_t rhport,
1325 tusb_control_request_t const *p_request) {
1326 // Handle audio class specific set requests
1327 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
1328 p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) {
1329 uint8_t func_id;
1330
1331 switch (p_request->bmRequestType_bit.recipient) {
1332 case TUSB_REQ_RCPT_INTERFACE: {
1333 uint8_t itf = TU_U16_LOW(p_request->wIndex);
1334 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
1335
1336 if (entityID != 0) {
1337 if (p_cb) {
1338 // Check if entity is present and get corresponding driver index
1339 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
1340
1341 // Invoke callback
1342 return p_cb->set_req_entity_cb(rhport, p_request,
1343 _audiod_fct[func_id].ctrl_buf);
1344 } else {
1345 TU_LOG2(" No entity set request callback available!\r\n");
1346 return false; // In case no callback function is present or
1347 // request can not be conducted we stall it
1348 }
1349 } else {
1350 if (p_cb) {
1351 // Find index of audio driver structure and verify interface
1352 // really exists
1353 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
1354
1355 // Invoke callback
1356 return p_cb->set_req_itf_cb(rhport, p_request,
1357 _audiod_fct[func_id].ctrl_buf);
1358 } else {
1359 TU_LOG2(" No interface set request callback available!\r\n");
1360 return false; // In case no callback function is present or
1361 // request can not be conducted we stall it
1362 }
1363 }
1364 } break;
1365
1366 case TUSB_REQ_RCPT_ENDPOINT: {
1367 uint8_t ep = TU_U16_LOW(p_request->wIndex);
1368
1369 if (p_cb) {
1370 // Check if entity is present and get corresponding driver index
1371 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
1372
1373 // Invoke callback
1374 return p_cb->set_req_ep_cb(rhport, p_request,
1375 _audiod_fct[func_id].ctrl_buf);
1376 } else {
1377 TU_LOG2(" No EP set request callback available!\r\n");
1378 return false; // In case no callback function is present or
1379 // request can not be conducted we stall it
1380 }
1381 } break;
1382 // Unknown/Unsupported recipient
1383 default:
1384 TU_BREAKPOINT();
1385 return false;
1386 }
1387 }
1388 return true;
1389 }
1390
1391 // return false to stall control endpoint (e.g unsupported request)
1392 bool audiod_control_request(uint8_t rhport,
1393 tusb_control_request_t const *p_request) {
1394 (void)rhport;
1395
1396 // Handle standard requests - standard set requests usually have no data
1397 // stage so we also handle set requests here
1398 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
1399 switch (p_request->bRequest) {
1400 case TUSB_REQ_GET_INTERFACE:
1401 return audiod_get_interface(rhport, p_request);
1402
1403 case TUSB_REQ_SET_INTERFACE:
1404 return audiod_set_interface(rhport, p_request);
1405
1406 case TUSB_REQ_CLEAR_FEATURE:
1407 return true;
1408
1409 // Unknown/Unsupported request
1410 default:
1411 TU_BREAKPOINT();
1412 return false;
1413 }
1414 }
1415
1416 // Handle class requests
1417 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
1418 uint8_t itf = TU_U16_LOW(p_request->wIndex);
1419 uint8_t func_id;
1420
1421 // Conduct checks which depend on the recipient
1422 switch (p_request->bmRequestType_bit.recipient) {
1423 case TUSB_REQ_RCPT_INTERFACE: {
1424 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
1425
1426 // Verify if entity is present
1427 if (entityID != 0) {
1428 // Find index of audio driver structure and verify entity really
1429 // exists
1430 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
1431
1432 // In case we got a get request invoke callback - callback needs
1433 // to answer as defined in UAC2 specification page 89 - 5.
1434 // Requests
1435 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
1436 if (p_cb) {
1437 return p_cb->get_req_entity_cb(rhport, p_request);
1438 } else {
1439 TU_LOG2(" No entity get request callback available!\r\n");
1440 return false; // Stall
1441 }
1442 }
1443 } else {
1444 // Find index of audio driver structure and verify interface
1445 // really exists
1446 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
1447
1448 // In case we got a get request invoke callback - callback needs
1449 // to answer as defined in UAC2 specification page 89 - 5.
1450 // Requests
1451 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
1452 if (p_cb) {
1453 return p_cb->set_itf_cb(rhport, p_request);
1454 } else {
1455 TU_LOG2(" No interface get request callback available!\r\n");
1456 return false; // Stall
1457 }
1458 }
1459 }
1460 } break;
1461
1462 case TUSB_REQ_RCPT_ENDPOINT: {
1463 uint8_t ep = TU_U16_LOW(p_request->wIndex);
1464
1465 // Find index of audio driver structure and verify EP really exists
1466 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
1467
1468 // In case we got a get request invoke callback - callback needs to
1469 // answer as defined in UAC2 specification page 89 - 5. Requests
1470 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
1471 if (p_cb) {
1472 return p_cb->get_req_ep_cb(rhport, p_request);
1473 } else {
1474 TU_LOG2(" No EP get request callback available!\r\n");
1475 return false; // Stall
1476 }
1477 }
1478 } break;
1479
1480 // Unknown/Unsupported recipient
1481 default:
1482 TU_LOG2(" Unsupported recipient: %d\r\n",
1483 p_request->bmRequestType_bit.recipient);
1484 TU_BREAKPOINT();
1485 return false;
1486 }
1487
1488 // If we end here, the received request is a set request - we schedule a
1489 // receive for the data stage and return true here. We handle the rest
1490 // later in audiod_control_complete() once the data stage was finished
1491 TU_VERIFY(tud_control_xfer(rhport, p_request,
1492 _audiod_fct[func_id].ctrl_buf,
1493 _audiod_fct[func_id].ctrl_buf_sz));
1494 return true;
1495 }
1496
1497 // There went something wrong - unsupported control request type
1498 TU_BREAKPOINT();
1499 return false;
1500 }
1501
1502 bool audiod_get_interface(uint8_t rhport,
1503 tusb_control_request_t const *p_request) {
1504 uint8_t const itf = tu_u16_low(p_request->wIndex);
1505
1506 // Find index of audio streaming interface
1507 uint8_t func_id, idxItf;
1508 uint8_t const *dummy;
1509
1510 TU_VERIFY(
1511 audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
1512 TU_VERIFY(tud_control_xfer(rhport, p_request,
1513 &_audiod_fct[func_id].alt_setting[idxItf], 1));
1514
1515 TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf,
1516 _audiod_fct[func_id].alt_setting[idxItf]);
1517
1518 return true;
1519 }
1520
1521 // Invoked when class request DATA stage is finished.
1522 // return false to stall control EP (e.g Host send non-sense DATA)
1523 bool audiod_control_completeX(uint8_t rhport,
1524 tusb_control_request_t const *p_request) {
1525 // Handle audio class specific set requests
1526 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
1527 p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) {
1528 uint8_t func_id;
1529
1530 switch (p_request->bmRequestType_bit.recipient) {
1531 case TUSB_REQ_RCPT_INTERFACE: {
1532 uint8_t itf = TU_U16_LOW(p_request->wIndex);
1533 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
1534
1535 if (entityID != 0) {
1536 if (p_cb) {
1537 // Check if entity is present and get corresponding driver index
1538 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
1539
1540 // Invoke callback
1541 return p_cb->set_req_entity_cb(rhport, p_request,
1542 _audiod_fct[func_id].ctrl_buf);
1543 } else {
1544 TU_LOG2(" No entity set request callback available!\r\n");
1545 return false; // In case no callback function is present or
1546 // request can not be conducted we stall it
1547 }
1548 } else {
1549 if (p_cb) {
1550 // Find index of audio driver structure and verify interface
1551 // really exists
1552 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
1553
1554 // Invoke callback
1555 return p_cb->set_req_itf_cb(rhport, p_request,
1556 _audiod_fct[func_id].ctrl_buf);
1557 } else {
1558 TU_LOG2(" No interface set request callback available!\r\n");
1559 return false; // In case no callback function is present or
1560 // request can not be conducted we stall it
1561 }
1562 }
1563 } break;
1564
1565 case TUSB_REQ_RCPT_ENDPOINT: {
1566 uint8_t ep = TU_U16_LOW(p_request->wIndex);
1567
1568 if (p_cb) {
1569 // Check if entity is present and get corresponding driver index
1570 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
1571
1572 // Invoke callback
1573 return p_cb->set_req_ep_cb(rhport, p_request,
1574 _audiod_fct[func_id].ctrl_buf);
1575 } else {
1576 TU_LOG2(" No EP set request callback available!\r\n");
1577 return false; // In case no callback function is present or
1578 // request can not be conducted we stall it
1579 }
1580 } break;
1581 // Unknown/Unsupported recipient
1582 default:
1583 TU_BREAKPOINT();
1584 return false;
1585 }
1586 }
1587 return true;
1588 }
1589
1590 bool set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq,
1591 uint32_t mclk_freq) {
1592 // Check if frame interval is within sane limits
1593 // The interval value n_frames was taken from the descriptors within
1594 // audiod_set_interface()
1595
1596 // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 *
1597 // f_s / f_m) for high speed this lower limit ensures the measures
1598 // feedback value has sufficient precision
1599 uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13;
1600 uint32_t const n_frame = (1UL << audio->feedback.frame_shift);
1601
1602 if ((((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame) {
1603 TU_LOG1(" UAC2 feedback interval too small\r\n");
1604 TU_BREAKPOINT();
1605 return false;
1606 }
1607
1608 // Check if parameters really allow for a power of two division
1609 if ((mclk_freq % sample_freq) == 0 &&
1610 tu_is_power_of_two(mclk_freq / sample_freq)) {
1611 audio->feedback.compute_method =
1612 AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
1613 audio->feedback.compute.power_of_2 =
1614 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq);
1615 } else if (audio->feedback.compute_method ==
1616 AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) {
1617 audio->feedback.compute.float_const =
1618 (float)sample_freq / mclk_freq *
1619 (1UL << (16 - audio->feedback.frame_shift));
1620 } else {
1621 audio->feedback.compute.fixed.sample_freq = sample_freq;
1622 audio->feedback.compute.fixed.mclk_freq = mclk_freq;
1623 }
1624
1625 return true;
1626 }
1627
1628 uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) {
1629 audiod_function_t *audio = &_audiod_fct[func_id];
1630 uint32_t feedback;
1631
1632 switch (audio->feedback.compute_method) {
1633 case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
1634 feedback = (cycles << audio->feedback.compute.power_of_2);
1635 break;
1636
1637 case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
1638 feedback =
1639 (uint32_t)((float)cycles * audio->feedback.compute.float_const);
1640 break;
1641
1642 case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: {
1643 uint64_t fb64 =
1644 (((uint64_t)cycles) * audio->feedback.compute.fixed.sample_freq)
1645 << (16 - audio->feedback.frame_shift);
1646 feedback = (uint32_t)(fb64 / audio->feedback.compute.fixed.mclk_freq);
1647 } break;
1648
1649 default:
1650 return 0;
1651 }
1652
1653 // For Windows:
1654 // https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers
1655 // The size of isochronous packets created by the device must be within
1656 // the limits specified in FMT-2.0 section 2.3.1.1. This means that the
1657 // deviation of actual packet size from nominal size must not exceed ±
1658 // one audio slot (audio slot = channel count samples).
1659 if (feedback > audio->feedback.max_value)
1660 feedback = audio->feedback.max_value;
1661 if (feedback < audio->feedback.min_value)
1662 feedback = audio->feedback.min_value;
1663
1664 tud_audio_n_fb_set(func_id, feedback);
1665
1666 return feedback;
1667 }
1668
1669 // This helper function finds for a given audio function and AS interface
1670 // number the index of the attached driver structure, the index of the
1671 // interface in the audio function (e.g. the std. AS interface with
1672 // interface number 15 is the first AS interface for the given audio
1673 // function and thus gets index zero), and finally a pointer to the std. AS
1674 // interface, where the pointer always points to the first alternate setting
1675 // i.e. alternate interface zero.
1676 bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio,
1677 uint8_t *idxItf,
1678 uint8_t const **pp_desc_int) {
1679 if (audio->p_desc) {
1680 // Get pointer at end
1681 uint8_t const *p_desc_end =
1682 audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
1683
1684 // Advance past AC descriptors
1685 uint8_t const *p_desc = tu_desc_next(audio->p_desc);
1686 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
1687
1688 uint8_t tmp = 0;
1689 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1690 // strict-overflow warning
1691 while (p_desc_end - p_desc > 0) {
1692 // We assume the number of alternate settings is increasing thus we
1693 // return the index of alternate setting zero!
1694 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE &&
1695 ((tusb_desc_interface_t const *)p_desc)->bAlternateSetting == 0) {
1696 if (((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber ==
1697 itf) {
1698 *idxItf = tmp;
1699 *pp_desc_int = p_desc;
1700 return true;
1701 }
1702 // Increase index, bytes read, and pointer
1703 tmp++;
1704 }
1705 p_desc = tu_desc_next(p_desc);
1706 }
1707 }
1708 return false;
1709 }
1710
1711 // This helper function finds for a given AS interface number the index of
1712 // the attached driver structure, the index of the interface in the audio
1713 // function (e.g. the std. AS interface with interface number 15 is the
1714 // first AS interface for the given audio function and thus gets index
1715 // zero), and finally a pointer to the std. AS interface, where the pointer
1716 // always points to the first alternate setting i.e. alternate interface
1717 // zero.
1718 bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id,
1719 uint8_t *idxItf,
1720 uint8_t const **pp_desc_int) {
1721 // Loop over audio driver interfaces
1722 uint8_t i;
1723 for (i = 0; i < cfg.func_n_as_int; i++) {
1724 if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf,
1725 pp_desc_int)) {
1726 *func_id = i;
1727 return true;
1728 }
1729 }
1730
1731 return false;
1732 }
1733
1734 // Verify an entity with the given ID exists and returns also the
1735 // corresponding driver index
1736 bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID,
1737 uint8_t *func_id) {
1738 uint8_t i;
1739 for (i = 0; i < cfg.func_n_as_int; i++) {
1740 // Look for the correct driver by checking if the unique standard AC
1741 // interface number fits
1742 if (_audiod_fct[i].p_desc &&
1743 ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)
1744 ->bInterfaceNumber == itf) {
1745 // Get pointers after class specific AC descriptors and end of AC
1746 // descriptors - entities are defined in between
1747 uint8_t const *p_desc =
1748 tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor
1749 uint8_t const *p_desc_end =
1750 ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength +
1751 p_desc;
1752 p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor
1753
1754 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1755 // strict-overflow warning
1756 while (p_desc_end - p_desc > 0) {
1757 if (p_desc[3] == entityID) // Entity IDs are always at offset 3
1758 {
1759 *func_id = i;
1760 return true;
1761 }
1762 p_desc = tu_desc_next(p_desc);
1763 }
1764 }
1765 }
1766 return false;
1767 }
1768
1769 bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) {
1770 uint8_t i;
1771 for (i = 0; i < cfg.func_n_as_int; i++) {
1772 if (_audiod_fct[i].p_desc) {
1773 // Get pointer at beginning and end
1774 uint8_t const *p_desc = _audiod_fct[i].p_desc;
1775 uint8_t const *p_desc_end = _audiod_fct[i].p_desc +
1776 _audiod_fct[i].desc_length -
1777 TUD_AUDIO_DESC_IAD_LEN;
1778 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1779 // strict-overflow warning
1780 while (p_desc_end - p_desc > 0) {
1781 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE &&
1782 ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)
1783 ->bInterfaceNumber == itf) {
1784 *func_id = i;
1785 return true;
1786 }
1787 p_desc = tu_desc_next(p_desc);
1788 }
1789 }
1790 }
1791 return false;
1792 }
1793
1794 bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) {
1795 uint8_t i;
1796 for (i = 0; i < cfg.func_n_as_int; i++) {
1797 if (_audiod_fct[i].p_desc) {
1798 // Get pointer at end
1799 uint8_t const *p_desc_end =
1800 _audiod_fct[i].p_desc + _audiod_fct[i].desc_length;
1801
1802 // Advance past AC descriptors - EP we look for are streaming EPs
1803 uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);
1804 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
1805
1806 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1807 // strict-overflow warning
1808 while (p_desc_end - p_desc > 0) {
1809 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT &&
1810 ((tusb_desc_endpoint_t const *)p_desc)->bEndpointAddress == ep) {
1811 *func_id = i;
1812 return true;
1813 }
1814 p_desc = tu_desc_next(p_desc);
1815 }
1816 }
1817 }
1818 return false;
1819 }
1820
1821 // p_desc points to the AS interface of alternate setting zero
1822 // itf is the interface number of the corresponding interface - we check if
1823 // the interface belongs to EP in or EP out to see if it is a TX or RX
1824 // parameter Currently, only AS interfaces with an EP (in or out) are
1825 // supposed to be parsed for!
1826 void audiod_parse_for_AS_params(audiod_function_t *audio,
1827 uint8_t const *p_desc,
1828 uint8_t const *p_desc_end,
1829 uint8_t const as_itf) {
1830 if (cfg.is_ep_in() && cfg.is_ep_out()) {
1831 if (as_itf != audio->ep_in_as_intf_num &&
1832 as_itf != audio->ep_out_as_intf_num)
1833 return; // Abort, this interface has no EP, this driver does not
1834 // support this currently
1835 }
1836 if (cfg.is_ep_in() && !cfg.is_ep_out()) {
1837 if (as_itf != audio->ep_in_as_intf_num) return;
1838 }
1839 if (!cfg.is_ep_in() && cfg.is_ep_out()) {
1840 if (as_itf != audio->ep_out_as_intf_num) return;
1841 }
1842
1843 p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor
1844 // of current alternate interface descriptor
1845 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1846 // strict-overflow warning
1847 while (p_desc_end - p_desc > 0) {
1848 // Abort if follow up descriptor is a new standard interface descriptor
1849 // - indicates the last AS descriptor was already finished
1850 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
1851
1852 // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify
1853 // format type and format and also to get number of physical channels
1854 if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE &&
1855 tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) {
1856 if (cfg.is_ep_in()) {
1857 if (as_itf == audio->ep_in_as_intf_num) {
1858 audio->n_channels_tx =
1859 ((audio_desc_cs_as_interface_t const *)p_desc)->bNrChannels;
1860 audio->format_type_tx =
1861 (audio_format_type_t)(((audio_desc_cs_as_interface_t const *)
1862 p_desc)
1863 ->bFormatType);
1864 }
1865 }
1866
1867 // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
1868 if (cfg.enable_ep_in_flow_control) {
1869 if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE &&
1870 tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE &&
1871 ((audio_desc_type_I_format_t const *)p_desc)->bFormatType ==
1872 AUDIO_FORMAT_TYPE_I) {
1873 if (cfg.is_ep_in() && cfg.is_ep_out()) {
1874 if (as_itf != audio->ep_in_as_intf_num &&
1875 as_itf != audio->ep_out_as_intf_num)
1876 break; // Abort loop, this interface has no EP, this driver
1877 // does not support this currently
1878 }
1879 if (cfg.is_ep_in() && !cfg.is_ep_out()) {
1880 if (as_itf != audio->ep_in_as_intf_num) break;
1881 }
1882 if (!cfg.is_ep_in() && cfg.is_ep_out()) {
1883 if (as_itf != audio->ep_out_as_intf_num) break;
1884 }
1885
1886 if (cfg.is_ep_in()) {
1887 if (as_itf == audio->ep_in_as_intf_num) {
1888 audio->n_bytes_per_sample_tx =
1889 ((audio_desc_type_I_format_t const *)p_desc)->bSubslotSize;
1890 }
1891 }
1892 }
1893 }
1894 }
1895 // Other format types are not supported yet
1896
1897 p_desc = tu_desc_next(p_desc);
1898 }
1899 }
1900
1901 bool audiod_calc_tx_packet_sz(audiod_function_t *audio) {
1902 TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I);
1903 TU_VERIFY(audio->n_channels_tx);
1904 TU_VERIFY(audio->n_bytes_per_sample_tx);
1905 TU_VERIFY(audio->interval_tx);
1906 TU_VERIFY(audio->sample_rate_tx);
1907
1908 const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL)
1909 ? audio->interval_tx
1910 : 1 << (audio->interval_tx - 1);
1911
1912 const uint16_t sample_normimal =
1913 (uint16_t)(audio->sample_rate_tx * interval /
1914 ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
1915 const uint16_t sample_reminder =
1916 (uint16_t)(audio->sample_rate_tx * interval %
1917 ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
1918
1919 const uint16_t packet_sz_tx_min =
1920 (uint16_t)((sample_normimal - 1) * audio->n_channels_tx *
1921 audio->n_bytes_per_sample_tx);
1922 const uint16_t packet_sz_tx_norm =
1923 (uint16_t)(sample_normimal * audio->n_channels_tx *
1924 audio->n_bytes_per_sample_tx);
1925 const uint16_t packet_sz_tx_max =
1926 (uint16_t)((sample_normimal + 1) * audio->n_channels_tx *
1927 audio->n_bytes_per_sample_tx);
1928
1929 // Endpoint size must larger than packet size
1930 TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz);
1931
1932 // Frmt20.pdf 2.3.1.1 USB Packets
1933 if (sample_reminder) {
1934 // All virtual frame packets must either contain INT(nav) audio slots
1935 // (small VFP) or INT(nav)+1 (large VFP) audio slots
1936 audio->packet_sz_tx[0] = packet_sz_tx_norm;
1937 audio->packet_sz_tx[1] = packet_sz_tx_norm;
1938 audio->packet_sz_tx[2] = packet_sz_tx_max;
1939 } else {
1940 // In the case where nav = INT(nav), ni may vary between INT(nav)-1
1941 // (small VFP), INT(nav) (medium VFP) and INT(nav)+1 (large VFP).
1942 audio->packet_sz_tx[0] = packet_sz_tx_min;
1943 audio->packet_sz_tx[1] = packet_sz_tx_norm;
1944 audio->packet_sz_tx[2] = packet_sz_tx_max;
1945 }
1946
1947 return true;
1948 }
1949
1950 uint16_t audiod_tx_packet_size(const uint16_t *norminal_size,
1951 uint16_t data_count, uint16_t fifo_depth,
1952 uint16_t max_depth) {
1953 // Flow control need a FIFO size of at least 4*Navg
1954 if (norminal_size[1] && norminal_size[1] <= fifo_depth * 4) {
1955 // Use blackout to prioritize normal size packet
1956 int ctrl_blackout = 0;
1957 uint16_t packet_size;
1958 uint16_t slot_size = norminal_size[2] - norminal_size[1];
1959 if (data_count < norminal_size[0]) {
1960 // If you get here frequently, then your I2S clock deviation is too
1961 // big !
1962 packet_size = 0;
1963 } else if (data_count < fifo_depth / 2 - slot_size && !ctrl_blackout) {
1964 packet_size = norminal_size[0];
1965 ctrl_blackout = 10;
1966 } else if (data_count > fifo_depth / 2 + slot_size && !ctrl_blackout) {
1967 packet_size = norminal_size[2];
1968 if (norminal_size[0] == norminal_size[1]) {
1969 // nav > INT(nav), eg. 44.1k, 88.2k
1970 ctrl_blackout = 0;
1971 } else {
1972 // nav = INT(nav), eg. 48k, 96k
1973 ctrl_blackout = 10;
1974 }
1975 } else {
1976 packet_size = norminal_size[1];
1977 if (ctrl_blackout) {
1978 ctrl_blackout--;
1979 }
1980 }
1981 // Normally this cap is not necessary
1982 return tu_min16(packet_size, max_depth);
1983 } else {
1984 return tu_min16(data_count, max_depth);
1985 }
1986 }
1987};
1988
1989// TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id,
1990// uint32_t frame_number, uint8_t interval_shift){
1991// // call audiod_sof_isr
1992// }
Definition USBDeviceAudioAPI.h:103
Configuration for TinyUSB Audio.
Definition USBDeviceAudioAPI.h:43
Definition USBDeviceAudioAPI.h:177
uint16_t tud_audio_n_write(uint8_t func_id, const void *data, uint16_t len)
Write data to EP in buffer.
Definition USBDeviceAudioAPI.h:231
Definition USBDeviceAudio.h:104
Definition USBDeviceAudioAPI.h:859
Definition USBDeviceAudioAPI.h:817
Definition USBDeviceAudioAPI.h:28