arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Modules Pages
USBAudioDevice.h
1#pragma once
2#include <cstddef>
3#include <cstdint>
4#include <cstring>
5#include <functional>
6#include <mutex>
7#include <vector>
8
9#ifndef ARDUINO_USB_MODE
10#error This ESP32 SoC has no Native USB interface
11#else
12#if ARDUINO_USB_MODE == 1
13#error This sketch should be used when USB is in OTG mode
14#endif
15#endif
16
17
18#include "USBAudio2DescriptorBuilder.h"
19#include "USBAudioConfig.h"
20
21extern "C" {
22#include "device/usbd.h"
23#include "device/usbd_pvt.h"
24#include "tusb.h"
25}
26
27namespace audio_tools {
28
30 enum audio_format_type_t {
31 AUDIO_FORMAT_TYPE_I,
32 AUDIO_FORMAT_TYPE_II,
33 AUDIO_FORMAT_TYPE_III,
34 };
35
36 enum audio_feedback_method_t {
37 AUDIO_FEEDBACK_METHOD_DISABLED,
38 AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED,
39 AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT,
40 AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, // For driver internal use only
41 AUDIO_FEEDBACK_METHOD_FIFO_COUNT
42 };
43
44 struct audiod_function_t {
45 uint8_t rhport;
46 uint8_t const *p_desc; // Pointer to Standard AC Interface Descriptor
47 uint8_t ep_in; // TX audio data EP.
48 uint16_t ep_in_sz; // Current size of TX EP
49 uint8_t
50 ep_in_as_intf_num; // Standard AS Interface Descriptor number for IN
51 uint8_t ep_out; // RX audio data EP.
52 uint16_t ep_out_sz; // Current size of RX EP
53 uint8_t
54 ep_out_as_intf_num; // Standard AS Interface Descriptor number for OUT
55 uint8_t ep_fb; // Feedback EP.
56 uint8_t ep_int; // Audio control interrupt EP.
57 bool mounted; // Device opened
58 uint16_t desc_length; // Length of audio function descriptor
59 struct {
60 uint32_t value;
61 uint32_t min_value;
62 uint32_t max_value;
63 uint8_t frame_shift;
64 uint8_t compute_method;
65 bool format_correction;
66 union {
67 uint8_t power_of_2;
68 float float_const;
69 struct {
70 uint32_t sample_freq;
71 uint32_t mclk_freq;
72 } fixed;
73 struct {
74 uint32_t nom_value;
75 uint32_t fifo_lvl_avg;
76 uint16_t fifo_lvl_thr;
77 uint16_t rate_const[2];
78 } fifo_count;
79 } compute;
80 } feedback;
81 uint32_t sample_rate_tx;
82 uint16_t packet_sz_tx[3];
83 uint8_t bclock_id_tx;
84 uint8_t interval_tx;
85 audio_format_type_t format_type_tx;
86 uint8_t n_channels_tx;
87 uint8_t n_bytes_per_sample_tx;
88 // From this point, data is not cleared by bus reset
89 uint8_t ctrl_buf_sz;
90 tu_fifo_t ep_out_ff;
91 tu_fifo_t ep_in_ff;
92 std::vector<uint8_t> ctrl_buf;
93 std::vector<uint8_t> alt_setting;
94 std::vector<uint8_t> lin_buf_out;
95 std::vector<uint8_t> lin_buf_in;
96 std::vector<uint32_t> fb_buf;
97 std::vector<uint8_t> ep_in_sw_buf; // For feedback EP
98 std::vector<uint8_t> ep_out_sw_buf; // For feedback EP
99 };
100
101 struct audio_feedback_params_t {
102 uint8_t method;
103 uint32_t sample_freq; // sample frequency in Hz
104
105 union {
106 struct {
107 uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to
108 // which sample clock is based on
109 } frequency;
110 };
111 };
112
113 public:
114 void setConfig(USBAudioConfig &cfg) { config_ = cfg; }
115
116 // Feature flag setters/getters
117 bool getEnableEpIn() const { return config_.enable_ep_in;}
118 bool getEnableEpOut() const { return config_.enable_ep_out; }
119 bool getEnableFeedbackEp() const { return config_.enable_feedback_ep; }
120 bool getEnableEpInFlowControl() const { return config_.enable_ep_in_flow_control;}
121 bool getEnableInterruptEp() const { return config_.enable_interrupt_ep; }
122 bool getEnableFifoMutex() const { return config_.enable_fifo_mutex; }
123
124 // Audio count setter/getter: getAudioCount()
125 uint8_t getAudioCount() const { return config_.audio_count; }
126
127 // Descriptor setup (call this during USB init)
128 const uint8_t *getAudioDescriptors(uint8_t itf, uint8_t alt,
129 uint16_t *out_length) {
130 // // Example: simple UAC1 streaming interface with one IN and one OUT
131 // endpoint static const uint8_t desc[] = {
132 // // Interface Association Descriptor (IAD)
133 // 0x08, 0x0B, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00,
134 // // Standard AC Interface Descriptor
135 // 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
136 // // Class-specific AC Interface Descriptor
137 // 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01,
138 // // Standard AS Interface Descriptor (alt 0 - zero bandwidth)
139 // 0x09, 0x04, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
140 // // Standard AS Interface Descriptor (alt 1 - operational, IN)
141 // 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,
142 // // Class-specific AS Interface Descriptor (IN)
143 // 0x07, 0x24, 0x01, 0x01, 0x01, 0x01, 0x00,
144 // // Type I Format Type Descriptor (IN)
145 // 0x0B, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01, 0x44, 0xAC, 0x00,
146 // // Standard AS Isochronous Audio Data Endpoint Descriptor (IN)
147 // 0x07, 0x05, 0x81, 0x01, 0x40, 0x00, 0x01,
148 // // Class-specific AS Isochronous Audio Data Endpoint Descriptor (IN)
149 // 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00,
150 // // Standard AS Interface Descriptor (alt 2 - operational, OUT)
151 // 0x09, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,
152 // // Class-specific AS Interface Descriptor (OUT)
153 // 0x07, 0x24, 0x01, 0x01, 0x01, 0x01, 0x00,
154 // // Type I Format Type Descriptor (OUT)
155 // 0x0B, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01, 0x44, 0xAC, 0x00,
156 // // Standard AS Isochronous Audio Data Endpoint Descriptor (OUT)
157 // 0x07, 0x05, 0x01, 0x01, 0x40, 0x00, 0x01,
158 // // Class-specific AS Isochronous Audio Data Endpoint Descriptor (OUT)
159 // 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00};
160 // if (out_length) *out_length = sizeof(desc);
161 // return desc;
162 return descr_builder.buildDescriptor(itf, alt, out_length);
163 }
164
165 // Mount status
166 bool mounted() const { return tud_mounted(); }
167
168 // Control request handler (call from tud_control_request_cb)
169 bool handleControlRequest(const tusb_control_request_t *request, void *buffer,
170 uint16_t length) {
171 // Example: handle standard GET_DESCRIPTOR request for audio interface
172 if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
173 request->bRequest == TUSB_REQ_GET_DESCRIPTOR) {
174 uint16_t desc_len;
175
176 uint8_t const itf = tu_u16_low(request->wIndex);
177 uint8_t const alt = tu_u16_low(request->wValue);
178
179 const uint8_t *desc = getAudioDescriptors(itf, alt, &desc_len);
180 if (desc && buffer && length >= desc_len) {
181 std::memcpy(buffer, desc, desc_len);
182 return true;
183 }
184 }
185 // TODO: handle class-specific requests (mute, volume, etc.)
186 return false;
187 }
188
189 // Streaming logic: call this in your main loop or USB task
190 void process() {
191 // Example: check if host is ready for IN, send audio packet
192 if (tud_ready()) {
193 uint8_t audio_data[48] = {0};
194 uint16_t bytes_written = 48;
195 if (tx_callback_)
196 bytes_written = tx_callback_(audio_data, sizeof(audio_data));
197 write(audio_data, bytes_written);
198 }
199 // Example: check for OUT data
200 if (tud_ready()) {
201 uint8_t buf[48];
202 uint16_t n = read(buf, sizeof(buf));
203 if (n > 0 && rx_callback_) rx_callback_(buf, n);
204 }
205 }
206
207 // Register RX callback
208 void setRxCallback(std::function<void(const uint8_t *, uint16_t)> cb) {
209 rx_callback_ = cb;
210 }
211 // Register TX callback
212 void setTxCallback(std::function<uint16_t(const void *, uint16_t)> cb) {
213 tx_callback_ = cb;
214 }
215 // Setter for interface GET request callback
216 void setGetReqItfCallback(std::function<bool(USBAudioDevice *, uint8_t,
217 tusb_control_request_t const *)>
218 cb) {
219 get_req_itf_cb_ = cb;
220 }
221 // Setter for entity GET request callback
222 void setGetReqEntityCallback(
223 std::function<bool(USBAudioDevice *, uint8_t,
224 tusb_control_request_t const *)>
225 cb) {
226 get_req_entity_cb_ = cb;
227 }
228 // Setter for endpoint GET request callback
229 void setGetReqEpCallback(std::function<bool(USBAudioDevice *, uint8_t,
230 tusb_control_request_t const *)>
231 cb) {
232 get_req_ep_cb_ = cb;
233 }
234 // Setter for feedback done callback
235 void setFbDoneCallback(std::function<void(USBAudioDevice *, uint8_t)> cb) {
236 fb_done_cb_ = cb;
237 }
238 // Setter for interrupt done callback
239 void setIntDoneCallback(std::function<void(USBAudioDevice *, uint8_t)> cb) {
240 int_done_cb_ = cb;
241 }
242 // Setter for TX done callback
243 void setTxDoneCallback(
244 std::function<bool(USBAudioDevice *, uint8_t, audiod_function_t *)> cb) {
245 tx_done_cb_ = cb;
246 }
247 // Setter for RX done callback
248 void setRxDoneCallback(std::function<bool(USBAudioDevice *, uint8_t,
249 audiod_function_t *, uint16_t)> cb) {
250 rx_done_cb_ = cb;
251 }
252 // Setter for req_entity_cb_
253 void setReqEntityCallback(std::function<bool(USBAudioDevice *, uint8_t)> cb) {
254 req_entity_cb_ = cb;
255 }
256 // Setter for tud_audio_set_itf_cb_
257 void setTudAudioSetItfCallback(
258 std::function<bool(USBAudioDevice *, uint8_t,
259 tusb_control_request_t const *)>cb) {
260 tud_audio_set_itf_cb_ = cb;
261 }
262 // Setter for tud_audio_set_req_entity_cb_
263 void setReqEntityCallback(
264 std::function<bool(USBAudioDevice *, uint8_t,
265 tusb_control_request_t const *, uint8_t *)>
266 cb) {
267 tud_audio_set_req_entity_cb_ = cb;
268 }
269 // Setter for tud_audio_set_req_itf_cb_
270 void setReqItfCallback(
271 std::function<bool(USBAudioDevice *, uint8_t,
272 tusb_control_request_t const *, uint8_t *)>
273 cb) {
274 tud_audio_set_req_itf_cb_ = cb;
275 }
276 // Setter for tud_audio_set_req_ep_cb_
277 void setReqEpCallback(
278 std::function<bool(USBAudioDevice *, uint8_t,
279 tusb_control_request_t const *, uint8_t *)>
280 cb) {
281 tud_audio_set_req_ep_cb_ = cb;
282 }
283 // Setter for tud_audio_set_itf_close_EP_cb_
284 void setItfCloseEpCallback(std::function<bool(USBAudioDevice *, uint8_t,
285 tusb_control_request_t const *)>
286 cb) {
287 tud_audio_set_itf_close_EP_cb_ = cb;
288 }
289 // Setter for audiod_tx_done_cb_
290 void setAudiodTxDoneCallback(
291 std::function<bool(USBAudioDevice *, uint8_t, audiod_function_t *)> cb) {
292 audiod_tx_done_cb_ = cb;
293 }
294 // Setter for tud_audio_feedback_params_cb_
295 void setAudioFeedbackParamsCallback(
296 std::function<void(USBAudioDevice *, uint8_t, uint8_t,
297 audio_feedback_params_t *)>
298 cb) {
299 tud_audio_feedback_params_cb_ = cb;
300 }
301 // Setter for tud_audio_feedback_format_correction_cb_
302 void setAudioFeedbackFormatCorrectionCallback(
303 std::function<bool(USBAudioDevice *, uint8_t)> cb) {
304 tud_audio_feedback_format_correction_cb_ = cb;
305 }
306
307
308 static USBAudioDevice &instance() {
309 static USBAudioDevice instance_;
310 return instance_;
311 }
312
313 usbd_class_driver_t const *usbd_app_driver_get(uint8_t *count) {
314 static usbd_class_driver_t driver;
315 driver.name = "Audio";
316 driver.init = [](void) { USBAudioDevice::instance().audiod_init(); };
317 driver.deinit = [](void) {
318 return USBAudioDevice::instance().audiod_deinit();
319 };
320 driver.reset = [](uint8_t rhport) {
321 USBAudioDevice::instance().audiod_reset(rhport);
322 };
323 driver.open = [](uint8_t rhport, tusb_desc_interface_t const *itf_desc,
324 uint16_t max_len) {
325 return USBAudioDevice::instance().audiod_open(rhport, itf_desc, max_len);
326 };
327 driver.control_xfer_cb = [](uint8_t rhport, uint8_t stage,
328 tusb_control_request_t const *request) {
329 return USBAudioDevice::instance().audiod_control_xfer_cb(rhport, stage,
330 request);
331 };
332 driver.xfer_cb = [](uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
333 uint32_t xferred_bytes) {
334 return USBAudioDevice::instance().audiod_xfer_cb(rhport, ep_addr, result,
335 xferred_bytes);
336 };
337 driver.sof = [](uint8_t rhport, uint32_t frame_count) {
338 USBAudioDevice::instance().audiod_sof_isr(rhport, frame_count);
339 };
340 *count = 1;
341 return &driver;
342 }
343
344 private:
345 // Only one set of member variables and methods retained
346 USBAudioConfig config_;
347 USBAudio2DescriptorBuilder descr_builder{config_};
348 std::function<void(const uint8_t *, uint16_t)> rx_callback_;
349 std::function<uint16_t(const void *, uint16_t)> tx_callback_;
350 std::function<void(USBAudioDevice *, uint8_t rhport)> int_done_cb_;
351 std::function<bool(USBAudioDevice *, uint8_t rhport, audiod_function_t *)>
352 tx_done_cb_;
353 std::function<bool(USBAudioDevice *, uint8_t rhport, audiod_function_t *,
354 uint16_t xferred_bytes)>
355 rx_done_cb_;
356 // Callback for interface GET requests
357 std::function<bool(USBAudioDevice *, uint8_t rhport,
358 tusb_control_request_t const *)>
359 get_req_itf_cb_;
360 // Callback for entity GET requests
361 std::function<bool(USBAudioDevice *, uint8_t rhport,
362 tusb_control_request_t const *)>
363 get_req_entity_cb_;
364 // Callback for endpoint GET requests
365 std::function<bool(USBAudioDevice *, uint8_t rhport,
366 tusb_control_request_t const *)>
367 get_req_ep_cb_;
368
369 // Callback for feedback done event
370 std::function<void(USBAudioDevice *, uint8_t func_id)> fb_done_cb_;
371 std::function<bool(USBAudioDevice *, uint8_t func_id)> req_entity_cb_;
372 std::function<bool(USBAudioDevice *, uint8_t rhport,
373 tusb_control_request_t const *p_request)>
374 tud_audio_set_itf_cb_;
375 std::function<bool(USBAudioDevice *, uint8_t rhport,
376 tusb_control_request_t const *p_request, uint8_t *pBuff)>
377 tud_audio_set_req_entity_cb_;
378
379 std::function<bool(USBAudioDevice *, uint8_t rhport,
380 tusb_control_request_t const *p_request, uint8_t *pBuff)>
381 tud_audio_set_req_itf_cb_;
382
383 std::function<bool(USBAudioDevice *, uint8_t rhport,
384 tusb_control_request_t const *p_request, uint8_t *pBuff)>
385 tud_audio_set_req_ep_cb_;
386
387 std::function<bool(USBAudioDevice *, uint8_t rhport,
388 tusb_control_request_t const *p_request)>
389 tud_audio_set_itf_close_EP_cb_;
390
391 std::function<bool(USBAudioDevice *, uint8_t rhport,
392 audiod_function_t *audio)>
393 audiod_tx_done_cb_;
394
395 std::function<void(USBAudioDevice *, uint8_t func_id, uint8_t alt_itf,
396 audio_feedback_params_t *feedback_param)>
397 tud_audio_feedback_params_cb_;
398
399 std::function<bool(USBAudioDevice *, uint8_t func_id)>
400 tud_audio_feedback_format_correction_cb_;
401
402 // TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT,
403 // CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT)
404 std::vector<uint16_t> ep_out_sw_buf_sz_;
405 // (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write
406 // FIFO every 1ms, so it should be 8 times larger for HS device
407 std::vector<uint16_t> ep_in_sw_buf_sz_;
408 // calculate!
409 std::vector<uint16_t> desc_len_;
410 // 64
411 std::vector<uint16_t> ctrl_buf_sz_;
412
413 std::vector<audiod_function_t> audiod_fct_;
414 std::vector<osal_mutex_def_t> ep_in_ff_mutex_wr_;
415 std::vector<osal_mutex_def_t> ep_out_ff_mutex_rd_;
416
417 USBAudioDevice() = default;
418
419 // Returns the control buffer size for a given function number
420 uint16_t getCtrlBufSz(uint8_t fn) const {
421 return (fn < ctrl_buf_sz_.size()) ? ctrl_buf_sz_[fn] : 64;
422 }
423
424 // Returns the OUT software buffer size for a given function number
425 uint16_t getEpOutSwBufSz(uint8_t fn) const {
426 return (fn < ep_out_sw_buf_sz_.size()) ? ep_out_sw_buf_sz_[fn] : 0;
427 }
428
429 // Returns the IN software buffer size for a given function number
430 uint16_t getEpInSwBufSz(uint8_t fn) const {
431 return (fn < ep_in_sw_buf_sz_.size()) ? ep_in_sw_buf_sz_[fn] : 0;
432 }
433
434 // Returns the descriptor length for a given function number
435 uint16_t getDescLen(uint8_t fn) const {
436 return (fn < desc_len_.size()) ? desc_len_[fn] : 0;
437 }
438
439 // Returns whether linear buffer RX is enabled
440 bool getUseLinearBufferRx() const { return config_.use_linear_buffer_rx; }
441
442 bool getUseLinearBufferTx() const { return config_.use_linear_buffer_tx; }
443
444 // Returns the reset size for audiod_function_t up to and including
445 // ctrl_buf_sz
446 static constexpr size_t getResetSize() {
447 return offsetof(audiod_function_t, ctrl_buf_sz) +
448 sizeof(((audiod_function_t *)0)->ctrl_buf_sz);
449 }
450
451 // Dummy for tud_audio_feedback_interval_isr (should be implemented elsewhere
452 // if not available)
453 void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_count,
454 uint8_t frame_shift) {
455 // Implement or forward to actual USB stack as needed
456 }
457
458 // Write audio data to IN endpoint
459 uint16_t write(const void *data, uint16_t len) {
460 uint16_t written = tud_audio_n_write(config_.ep_in, data, len);
461 return written;
462 return 0;
463 }
464
465 // Read audio data from OUT endpoint
466 uint16_t read(void *buffer, uint16_t bufsize) {
467 return tud_audio_n_read(config_.ep_out, buffer, bufsize);
468 }
469
470 // USBD Driver API
471 void audiod_init(void) {
472 audiod_fct_.resize(getAudioCount());
473 alloc_mutex();
474
475 // Initialize control buffers
476 for (uint8_t i = 0; i < getAudioCount(); i++) {
477 audiod_function_t *audio = &audiod_fct_[i];
478 // Initialize control buffers
479 int size = getCtrlBufSz(i);
480 audio->ctrl_buf.resize(size);
481 audio->ctrl_buf_sz = size;
482 // Initialize active alternate interface buffers
483 audio->alt_setting.resize(config_.as_descr_count);
484 // Initialize IN EP FIFO if required
485 if (getEnableEpIn()) {
486 audio->ep_in_sw_buf.resize(getEpInSwBufSz(i));
487
488 tu_fifo_config(&audio->ep_in_ff,
489 audio->ep_in_sw_buf.data(), // Use data pointer for FIFO
490 getEpInSwBufSz(i), 1, true);
491 if (getEnableFifoMutex()) {
492 tu_fifo_config_mutex(&audio->ep_in_ff,
493 osal_mutex_create(&ep_in_ff_mutex_wr_[i]), NULL);
494 }
495 }
496 // Initialize linear buffers
497 if (getUseLinearBufferTx()) {
498 audio->lin_buf_in.resize(config_.lin_buf_in_size_per_func);
499 }
500 // Initialize OUT EP FIFO if required
501 if (getEnableEpOut()) {
502 audio->ep_out_sw_buf.resize(getEpOutSwBufSz(i));
503 tu_fifo_config(&audio->ep_out_ff, audio->ep_out_sw_buf.data(),
504 getEpOutSwBufSz(i), 1, true);
505 if (getEnableFifoMutex()) {
506 tu_fifo_config_mutex(&audio->ep_out_ff, NULL,
507 osal_mutex_create(&ep_out_ff_mutex_rd_[i]));
508 }
509 }
510 // Initialize linear buffers
511 if (getUseLinearBufferRx()) {
512 audio->lin_buf_out.resize(config_.lin_buf_in_size_per_func);
513 }
514 if (getEnableFeedbackEp()) {
515 audio->fb_buf.resize(getEpOutSwBufSz(i));
516 }
517 }
518 }
519
520 void alloc_mutex() {
521 if (getEnableFifoMutex()) {
522 if (getEnableEpIn()) {
523 ep_in_ff_mutex_wr_.resize(getAudioCount());
524 }
525 if (getEnableEpOut()) {
526 ep_out_ff_mutex_rd_.resize(getAudioCount());
527 }
528 }
529 }
530
531 bool audiod_deinit(void) {
532 return false; // TODO not implemented yet
533 }
534
535 void audiod_reset(uint8_t rhport) {
536 (void)rhport;
537 for (uint8_t i = 0; i < getAudioCount(); i++) {
538 audiod_function_t *audio = &audiod_fct_[i];
539 memset(audio, 0, getResetSize());
540 if (getEnableEpIn()) {
541 tu_fifo_clear(&audio->ep_in_ff);
542 }
543 if (getEnableEpOut()) {
544 tu_fifo_clear(&audio->ep_out_ff);
545 }
546 }
547 }
548
549 uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
550 uint16_t max_len) {
551 (void)max_len;
552 TU_VERIFY(TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass &&
553 AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass);
554 TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
555 TU_ASSERT(itf_desc->bNumEndpoints <= 1);
556 if (itf_desc->bNumEndpoints == 1) {
557 TU_ASSERT(getEnableInterruptEp());
558 }
559 TU_VERIFY(itf_desc->bAlternateSetting == 0);
560 uint8_t i;
561 for (i = 0; i < getAudioCount(); i++) {
562 if (!audiod_fct_[i].p_desc) {
563 audiod_fct_[i].p_desc = (uint8_t const *)itf_desc;
564 audiod_fct_[i].rhport = rhport;
565 audiod_fct_[i].desc_length = getDescLen(i);
566 if (getEnableEpIn() || getEnableEpOut() || getEnableFeedbackEp()) {
567 uint8_t ep_in = 0, ep_out = 0, ep_fb = 0;
568 uint16_t ep_in_size = 0, ep_out_size = 0;
569 uint8_t const *p_desc = audiod_fct_[i].p_desc;
570 uint8_t const *p_desc_end =
571 p_desc + audiod_fct_[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
572 while (p_desc_end - p_desc > 0) {
573 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
574 tusb_desc_endpoint_t const *desc_ep =
575 (tusb_desc_endpoint_t const *)p_desc;
576 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
577 if (getEnableFeedbackEp() && desc_ep->bmAttributes.usage == 1) {
578 ep_fb = desc_ep->bEndpointAddress;
579 }
580 if (desc_ep->bmAttributes.usage == 0) {
581 if (getEnableEpIn() &&
582 tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
583 ep_in = desc_ep->bEndpointAddress;
584 ep_in_size =
585 TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
586 } else if (getEnableEpOut() &&
587 tu_edpt_dir(desc_ep->bEndpointAddress) ==
588 TUSB_DIR_OUT) {
589 ep_out = desc_ep->bEndpointAddress;
590 ep_out_size =
591 TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
592 }
593 }
594 }
595 }
596 p_desc = tu_desc_next(p_desc);
597 }
598 if (getEnableEpIn() && ep_in) {
599 usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size);
600 }
601 if (getEnableEpOut() && ep_out) {
602 usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size);
603 }
604 if (getEnableFeedbackEp() && ep_fb) {
605 usbd_edpt_iso_alloc(rhport, ep_fb, 4);
606 }
607 }
608 if (getEnableEpIn() && getEnableEpInFlowControl()) {
609 uint8_t const *p_desc = audiod_fct_[i].p_desc;
610 uint8_t const *p_desc_end =
611 p_desc + audiod_fct_[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
612 while (p_desc_end - p_desc > 0) {
613 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
614 tusb_desc_endpoint_t const *desc_ep =
615 (tusb_desc_endpoint_t const *)p_desc;
616 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS &&
617 desc_ep->bmAttributes.usage == 0 &&
618 tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
619 audiod_fct_[i].interval_tx = desc_ep->bInterval;
620 }
621 } else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE &&
622 tu_desc_subtype(p_desc) ==
623 AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) {
624 if (tu_unaligned_read16(p_desc + 4) ==
625 AUDIO_TERM_TYPE_USB_STREAMING) {
626 audiod_fct_[i].bclock_id_tx = p_desc[8];
627 }
628 }
629 p_desc = tu_desc_next(p_desc);
630 }
631 }
632 if (getEnableInterruptEp()) {
633 uint8_t const *p_desc = audiod_fct_[i].p_desc;
634 uint8_t const *p_desc_end =
635 p_desc + audiod_fct_[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
636 while (p_desc_end - p_desc > 0) {
637 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
638 tusb_desc_endpoint_t const *desc_ep =
639 (tusb_desc_endpoint_t const *)p_desc;
640 uint8_t const ep_addr = desc_ep->bEndpointAddress;
641 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN &&
642 desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) {
643 audiod_fct_[i].ep_int = ep_addr;
644 TU_ASSERT(usbd_edpt_open(audiod_fct_[i].rhport, desc_ep));
645 }
646 }
647 p_desc = tu_desc_next(p_desc);
648 }
649 }
650 audiod_fct_[i].mounted = true;
651 break;
652 }
653 }
654 TU_ASSERT(i < getAudioCount());
655 uint16_t drv_len = audiod_fct_[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
656 return drv_len;
657 }
658
659 bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage,
660 tusb_control_request_t const *request) {
661 if (stage == CONTROL_STAGE_SETUP) {
662 return audiod_control_request(rhport, request);
663 } else if (stage == CONTROL_STAGE_DATA) {
664 return audiod_control_complete(rhport, request);
665 }
666 return true;
667 }
668 // Invoked when class request DATA stage is finished.
669 // return false to stall control EP (e.g Host send non-sense DATA)
670 bool audiod_control_complete(uint8_t rhport,
671 tusb_control_request_t const *p_request) {
672 // Handle audio class specific set requests
673 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
674 p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) {
675 uint8_t func_id;
676
677 switch (p_request->bmRequestType_bit.recipient) {
678 case TUSB_REQ_RCPT_INTERFACE: {
679 uint8_t itf = TU_U16_LOW(p_request->wIndex);
680 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
681
682 if (entityID != 0) {
683 // Check if entity is present and get corresponding driver index
684 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
685
686 if (getEnableEpIn() && getEnableEpInFlowControl()) {
687 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
688 if (audiod_fct_[func_id].bclock_id_tx == entityID &&
689 ctrlSel == AUDIO_CS_CTRL_SAM_FREQ &&
690 p_request->bRequest == AUDIO_CS_REQ_CUR) {
691 audiod_fct_[func_id].sample_rate_tx =
692 tu_unaligned_read32(audiod_fct_[func_id].ctrl_buf.data());
693 }
694 }
695
696 // Invoke callback
697 if (tud_audio_set_req_entity_cb_) {
698 return tud_audio_set_req_entity_cb_(
699 this, rhport, p_request,
700 audiod_fct_[func_id].ctrl_buf.data());
701 }
702 } else {
703 // Find index of audio driver structure and verify interface really
704 // exists
705 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
706
707 // Invoke callback
708 if (tud_audio_set_req_itf_cb_) {
709 return tud_audio_set_req_itf_cb_(
710 this, rhport, p_request,
711 audiod_fct_[func_id].ctrl_buf.data());
712 }
713 }
714 } break;
715
716 case TUSB_REQ_RCPT_ENDPOINT: {
717 uint8_t ep = TU_U16_LOW(p_request->wIndex);
718
719 // Check if entity is present and get corresponding driver index
720 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
721
722 // Invoke callback
723 if (tud_audio_set_req_ep_cb_) {
724 return tud_audio_set_req_ep_cb_(
725 this, rhport, p_request, audiod_fct_[func_id].ctrl_buf.data());
726 }
727 } break;
728 // Unknown/Unsupported recipient
729 default:
730 TU_BREAKPOINT();
731 return false;
732 }
733 }
734 return true;
735 }
736
737 bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
738 uint32_t xferred_bytes) {
739 (void)result;
740 (void)xferred_bytes;
741 for (uint8_t func_id = 0; func_id < getAudioCount(); func_id++) {
742 audiod_function_t *audio = &audiod_fct_[func_id];
743 if (getEnableInterruptEp() && audio->ep_int == ep_addr) {
744 if (int_done_cb_) int_done_cb_(this, rhport);
745 return true;
746 }
747 if (getEnableEpIn() && audio->ep_in == ep_addr &&
748 audio->alt_setting.size() != 0) {
749 if (tx_done_cb_ && tx_done_cb_(this, rhport, audio)) return true;
750 return true;
751 }
752 if (getEnableEpOut() && audio->ep_out == ep_addr) {
753 if (rx_done_cb_ &&
754 rx_done_cb_(this, rhport, audio, (uint16_t)xferred_bytes))
755 return true;
756 return true;
757 }
758 if (getEnableFeedbackEp() && audio->ep_fb == ep_addr) {
759 if (fb_done_cb_) {
760 fb_done_cb_(this, func_id);
761 }
762 if (usbd_edpt_claim(rhport, audio->ep_fb)) {
763 return audiod_fb_send(audio);
764 }
765 }
766 }
767 return false;
768 }
769
770 TU_ATTR_FAST_FUNC void audiod_sof_isr(uint8_t rhport, uint32_t frame_count) {
771 (void)rhport;
772 (void)frame_count;
773 if (getEnableEpOut() && getEnableFeedbackEp()) {
774 for (uint8_t i = 0; i < getAudioCount(); i++) {
775 audiod_function_t *audio = &audiod_fct_[i];
776 if (audio->ep_fb != 0) {
777 uint8_t const hs_adjust =
778 (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0;
779 uint32_t const interval =
780 1UL << (audio->feedback.frame_shift - hs_adjust);
781 if (0 == (frame_count & (interval - 1))) {
782 tud_audio_feedback_interval_isr(i, frame_count,
783 audio->feedback.frame_shift);
784 }
785 }
786 }
787 }
788 }
789
790 bool audiod_control_request(uint8_t rhport,
791 tusb_control_request_t const *p_request) {
792 (void)rhport;
793
794 // Handle standard requests - standard set requests usually have no data
795 // stage so we also handle set requests here
796 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
797 switch (p_request->bRequest) {
798 case TUSB_REQ_GET_INTERFACE:
799 return audiod_get_interface(rhport, p_request);
800
801 case TUSB_REQ_SET_INTERFACE:
802 return audiod_set_interface(rhport, p_request);
803
804 case TUSB_REQ_CLEAR_FEATURE:
805 return true;
806
807 // Unknown/Unsupported request
808 default:
809 TU_BREAKPOINT();
810 return false;
811 }
812 }
813
814 // Handle class requests
815 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
816 uint8_t itf = TU_U16_LOW(p_request->wIndex);
817 uint8_t func_id;
818
819 // Conduct checks which depend on the recipient
820 switch (p_request->bmRequestType_bit.recipient) {
821 case TUSB_REQ_RCPT_INTERFACE: {
822 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
823
824 // Verify if entity is present
825 if (entityID != 0) {
826 // Find index of audio driver structure and verify entity really
827 // exists
828 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
829
830 // In case we got a get request invoke callback - callback needs to
831 // answer as defined in UAC2 specification page 89 - 5. Requests
832 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN &&
833 req_entity_cb_) {
834 return req_entity_cb_(this, func_id);
835 }
836 } else {
837 // Find index of audio driver structure and verify interface really
838 // exists
839 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
840
841 // In case we got a get request invoke callback - callback needs to
842 // answer as defined in UAC2 specification page 89 - 5. Requests
843 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
844 // Use callback if set, otherwise return false
845 if (get_req_itf_cb_) {
846 return get_req_itf_cb_(this, rhport, p_request);
847 }
848 return false;
849 }
850 }
851 } break;
852
853 case TUSB_REQ_RCPT_ENDPOINT: {
854 uint8_t ep = TU_U16_LOW(p_request->wIndex);
855
856 // Find index of audio driver structure and verify EP really exists
857 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
858
859 // In case we got a get request invoke callback - callback needs to
860 // answer as defined in UAC2 specification page 89 - 5. Requests
861 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
862 // Use callback if set, otherwise return false
863 if (get_req_ep_cb_) {
864 return get_req_ep_cb_(this, rhport, p_request);
865 }
866 return false;
867 }
868 } break;
869
870 // Unknown/Unsupported recipient
871 default:
872 TU_LOG2(" Unsupported recipient: %d\r\n",
873 p_request->bmRequestType_bit.recipient);
874 TU_BREAKPOINT();
875 return false;
876 }
877
878 // If we end here, the received request is a set request - we schedule a
879 // receive for the data stage and return true here. We handle the rest
880 // later in audiod_control_complete() once the data stage was finished
881 TU_VERIFY(tud_control_xfer(rhport, p_request,
882 audiod_fct_[func_id].ctrl_buf.data(),
883 audiod_fct_[func_id].ctrl_buf_sz));
884 return true;
885 }
886
887 // There went something wrong - unsupported control request type
888 TU_BREAKPOINT();
889 return false;
890 }
891 // Verify an entity with the given ID exists and returns also the
892 // corresponding driver index
893 bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID,
894 uint8_t *func_id) {
895 uint8_t i;
896 for (i = 0; i < getAudioCount(); i++) {
897 // Look for the correct driver by checking if the unique standard AC
898 // interface number fits
899 if (audiod_fct_[i].p_desc &&
900 ((tusb_desc_interface_t const *)audiod_fct_[i].p_desc)
901 ->bInterfaceNumber == itf) {
902 // Get pointers after class specific AC descriptors and end of AC
903 // descriptors - entities are defined in between
904 uint8_t const *p_desc =
905 tu_desc_next(audiod_fct_[i].p_desc); // Points to CS AC descriptor
906 uint8_t const *p_desc_end =
907 ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength +
908 p_desc;
909 p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor
910
911 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
912 // strict-overflow warning
913 while (p_desc_end - p_desc > 0) {
914 if (p_desc[3] == entityID) // Entity IDs are always at offset 3
915 {
916 *func_id = i;
917 return true;
918 }
919 p_desc = tu_desc_next(p_desc);
920 }
921 }
922 }
923 return false;
924 }
925
926 bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) {
927 uint8_t i;
928 for (i = 0; i < getAudioCount(); i++) {
929 if (audiod_fct_[i].p_desc) {
930 // Get pointer at end
931 uint8_t const *p_desc_end =
932 audiod_fct_[i].p_desc + audiod_fct_[i].desc_length;
933
934 // Advance past AC descriptors - EP we look for are streaming EPs
935 uint8_t const *p_desc = tu_desc_next(audiod_fct_[i].p_desc);
936 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
937
938 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
939 // strict-overflow warning
940 while (p_desc_end - p_desc > 0) {
941 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT &&
942 ((tusb_desc_endpoint_t const *)p_desc)->bEndpointAddress == ep) {
943 *func_id = i;
944 return true;
945 }
946 p_desc = tu_desc_next(p_desc);
947 }
948 }
949 }
950 return false;
951 }
952
953 bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) {
954 uint8_t i;
955 for (i = 0; i < getAudioCount(); i++) {
956 if (audiod_fct_[i].p_desc) {
957 // Get pointer at beginning and end
958 uint8_t const *p_desc = audiod_fct_[i].p_desc;
959 uint8_t const *p_desc_end = audiod_fct_[i].p_desc +
960 audiod_fct_[i].desc_length -
961 TUD_AUDIO_DESC_IAD_LEN;
962 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
963 // strict-overflow warning
964 while (p_desc_end - p_desc > 0) {
965 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE &&
966 ((tusb_desc_interface_t const *)audiod_fct_[i].p_desc)
967 ->bInterfaceNumber == itf) {
968 *func_id = i;
969 return true;
970 }
971 p_desc = tu_desc_next(p_desc);
972 }
973 }
974 }
975 return false;
976 }
977
978 void audiod_parse_flow_control_params(audiod_function_t *audio,
979 uint8_t const *p_desc) {
980 p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor
981 // of current alternate interface descriptor
982
983 // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format
984 // type and format and also to get number of physical channels
985 if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE &&
986 tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) {
987 audio->n_channels_tx =
988 ((audio_desc_cs_as_interface_t const *)p_desc)->bNrChannels;
989 audio->format_type_tx =
990 (audio_format_type_t)(((audio_desc_cs_as_interface_t const *)p_desc)
991 ->bFormatType);
992 // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
993 p_desc = tu_desc_next(p_desc);
994 if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE &&
995 tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE &&
996 ((audio_desc_type_I_format_t const *)p_desc)->bFormatType ==
997 AUDIO_FORMAT_TYPE_I) {
998 audio->n_bytes_per_sample_tx =
999 ((audio_desc_type_I_format_t const *)p_desc)->bSubslotSize;
1000 }
1001 }
1002 }
1003
1004 // This helper function finds for a given audio function and AS interface
1005 // number the index of the attached driver structure, the index of the
1006 // interface in the audio function
1007 // (e.g. the std. AS interface with interface number 15 is the first AS
1008 // interface for the given audio function and thus gets index zero), and
1009 // finally a pointer to the std. AS interface, where the pointer always points
1010 // to the first alternate setting i.e. alternate interface zero.
1011 bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio,
1012 uint8_t *idxItf,
1013 uint8_t const **pp_desc_int) {
1014 if (audio->p_desc) {
1015 // Get pointer at end
1016 uint8_t const *p_desc_end =
1017 audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
1018
1019 // Advance past AC descriptors
1020 uint8_t const *p_desc = tu_desc_next(audio->p_desc);
1021 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
1022
1023 uint8_t tmp = 0;
1024 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1025 // strict-overflow warning
1026 while (p_desc_end - p_desc > 0) {
1027 // We assume the number of alternate settings is increasing thus we
1028 // return the index of alternate setting zero!
1029 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE &&
1030 ((tusb_desc_interface_t const *)p_desc)->bAlternateSetting == 0) {
1031 if (((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber ==
1032 itf) {
1033 *idxItf = tmp;
1034 *pp_desc_int = p_desc;
1035 return true;
1036 }
1037 // Increase index, bytes read, and pointer
1038 tmp++;
1039 }
1040 p_desc = tu_desc_next(p_desc);
1041 }
1042 }
1043 return false;
1044 }
1045
1046 // This helper function finds for a given AS interface number the index of the
1047 // attached driver structure, the index of the interface in the audio function
1048 // (e.g. the std. AS interface with interface number 15 is the first AS
1049 // interface for the given audio function and thus gets index zero), and
1050 // finally a pointer to the std. AS interface, where the pointer always points
1051 // to the first alternate setting i.e. alternate interface zero.
1052 bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id,
1053 uint8_t *idxItf,
1054 uint8_t const **pp_desc_int) {
1055 // Loop over audio driver interfaces
1056 uint8_t i;
1057 for (i = 0; i < getAudioCount(); i++) {
1058 if (audiod_get_AS_interface_index(itf, &audiod_fct_[i], idxItf,
1059 pp_desc_int)) {
1060 *func_id = i;
1061 return true;
1062 }
1063 }
1064
1065 return false;
1066 }
1067
1068 bool audiod_get_interface(uint8_t rhport,
1069 tusb_control_request_t const *p_request) {
1070 uint8_t const itf = tu_u16_low(p_request->wIndex);
1071
1072 // Find index of audio streaming interface
1073 uint8_t func_id, idxItf;
1074 uint8_t const *dummy;
1075
1076 TU_VERIFY(
1077 audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
1078 TU_VERIFY(tud_control_xfer(rhport, p_request,
1079 &audiod_fct_[func_id].alt_setting[idxItf], 1));
1080
1081 TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf,
1082 audiod_fct_[func_id].alt_setting[idxItf]);
1083
1084 return true;
1085 }
1086
1087 bool audiod_fb_send(audiod_function_t *audio) {
1088 bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) &&
1089 audio->feedback.format_correction;
1090 // Format the feedback value
1091 if (apply_correction) {
1092 uint8_t *fb = (uint8_t *)audio->fb_buf.data();
1093
1094 // For FS format is 10.14
1095 *(fb++) = (audio->feedback.value >> 2) & 0xFF;
1096 *(fb++) = (audio->feedback.value >> 10) & 0xFF;
1097 *(fb++) = (audio->feedback.value >> 18) & 0xFF;
1098 *fb = 0;
1099 } else {
1100 audio->fb_buf[0] = audio->feedback.value;
1101 }
1102
1103 // About feedback format on FS
1104 //
1105 // 3 variables: Format | packetSize | sendSize | Working OS:
1106 // 16.16 4 4 Linux, Windows
1107 // 16.16 4 3 Linux
1108 // 16.16 3 4 Linux
1109 // 16.16 3 3 Linux
1110 // 10.14 4 4 Linux
1111 // 10.14 4 3 Linux
1112 // 10.14 3 4 Linux, OSX
1113 // 10.14 3 3 Linux, OSX
1114 //
1115 // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty
1116 // ugly
1117 return usbd_edpt_xfer(audio->rhport, audio->ep_fb,
1118 (uint8_t *)audio->fb_buf.data(),
1119 apply_correction ? 3 : 4);
1120 }
1121
1122 bool audiod_set_interface(uint8_t rhport,
1123 tusb_control_request_t const *p_request) {
1124 (void)rhport;
1125
1126 // Here we need to do the following:
1127
1128 // 1. Find the audio driver assigned to the given interface to be set
1129 // Since one audio driver interface has to be able to cover an unknown
1130 // number of interfaces (AC, AS + its alternate settings), the best memory
1131 // efficient way to solve this is to always search through the descriptors.
1132 // The audio driver is mapped to an audio function by a reference pointer to
1133 // the corresponding AC interface of this audio function which serves as a
1134 // starting point for searching
1135
1136 // 2. Close EPs which are currently open
1137 // To do so it is not necessary to know the current active alternate
1138 // interface since we already save the current EP addresses - we simply
1139 // close them
1140
1141 // 3. Open new EP
1142
1143 uint8_t const itf = tu_u16_low(p_request->wIndex);
1144 uint8_t const alt = tu_u16_low(p_request->wValue);
1145
1146 TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt);
1147
1148 // Find index of audio streaming interface and index of interface
1149 uint8_t func_id, idxItf;
1150 uint8_t const *p_desc;
1151 TU_VERIFY(
1152 audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
1153
1154 audiod_function_t *audio = &audiod_fct_[func_id];
1155
1156 // Look if there is an EP to be closed - for this driver, there are only 3
1157 // possible EPs which may be closed (only AS related EPs can be closed, AC
1158 // EP (if present) is always open)
1159 if (getEnableEpIn()) {
1160 if (audio->ep_in_as_intf_num == itf) {
1161 audio->ep_in_as_intf_num = 0;
1162#ifndef TUP_DCD_EDPT_ISO_ALLOC
1163 usbd_edpt_close(rhport, audio->ep_in);
1164#endif
1165
1166 // Clear FIFOs, since data is no longer valid
1167 tu_fifo_clear(&audio->ep_in_ff);
1168
1169 // Invoke callback - can be used to stop data sampling
1170 if (tud_audio_set_itf_close_EP_cb_) {
1171 TU_VERIFY(tud_audio_set_itf_close_EP_cb_(this, rhport, p_request));
1172 }
1173
1174 audio->ep_in = 0; // Necessary?
1175
1176 if (getEnableEpInFlowControl()) {
1177 audio->packet_sz_tx[0] = 0;
1178 audio->packet_sz_tx[1] = 0;
1179 audio->packet_sz_tx[2] = 0;
1180 }
1181 }
1182 } // getEnableEpIn()
1183
1184 if (getEnableEpOut()) {
1185 if (audio->ep_out_as_intf_num == itf) {
1186 audio->ep_out_as_intf_num = 0;
1187#ifndef TUP_DCD_EDPT_ISO_ALLOC
1188 usbd_edpt_close(rhport, audio->ep_out);
1189#endif
1190
1191 // Clear FIFOs, since data is no longer valid
1192 tu_fifo_clear(&audio->ep_out_ff);
1193
1194 // Invoke callback - can be used to stop data sampling
1195 if (tud_audio_set_itf_close_EP_cb_) {
1196 TU_VERIFY(tud_audio_set_itf_close_EP_cb_(this, rhport, p_request));
1197 }
1198
1199 audio->ep_out = 0; // Necessary?
1200
1201 // Close corresponding feedback EP
1202 if (getEnableFeedbackEp()) {
1203 // #ifndef TUP_DCD_EDPT_ISO_ALLOC
1204 // usbd_edpt_close(rhport, audio->ep_fb);
1205 // #endif
1206 audio->ep_fb = 0;
1207 tu_memclr(&audio->feedback, sizeof(audio->feedback));
1208 }
1209 }
1210 } // getEnableEpOut()
1211
1212 // Save current alternative interface setting
1213 audio->alt_setting[idxItf] = alt;
1214
1215 // Open new EP if necessary - EPs are only to be closed or opened for AS
1216 // interfaces - Look for AS interface with correct alternate interface Get
1217 // pointer at end
1218 uint8_t const *p_desc_end =
1219 audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
1220
1221 // p_desc starts at required interface with alternate setting zero
1222 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1223 // strict-overflow warning
1224 while (p_desc_end - p_desc > 0) {
1225 // Find correct interface
1226 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE &&
1227 ((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber == itf &&
1228 ((tusb_desc_interface_t const *)p_desc)->bAlternateSetting == alt) {
1229 uint8_t const *p_desc_parse_for_params = nullptr;
1230 if (getEnableEpIn() && getEnableEpInFlowControl()) {
1231 p_desc_parse_for_params = p_desc;
1232 }
1233 // From this point forward follow the EP descriptors associated to the
1234 // current alternate setting interface - Open EPs if necessary
1235 uint8_t foundEPs = 0,
1236 nEps = ((tusb_desc_interface_t const *)p_desc)->bNumEndpoints;
1237 // Condition modified from p_desc < p_desc_end to prevent gcc>=12
1238 // strict-overflow warning
1239 while (foundEPs < nEps && (p_desc_end - p_desc > 0)) {
1240 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
1241 tusb_desc_endpoint_t const *desc_ep =
1242 (tusb_desc_endpoint_t const *)p_desc;
1243#ifdef TUP_DCD_EDPT_ISO_ALLOC
1244 TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep));
1245#else
1246 TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
1247#endif
1248 uint8_t const ep_addr = desc_ep->bEndpointAddress;
1249
1250 // TODO: We need to set EP non busy since this is not taken care of
1251 // right now in ep_close() - THIS IS A WORKAROUND!
1252 usbd_edpt_clear_stall(rhport, ep_addr);
1253
1254 if (getEnableEpIn()) {
1255 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN &&
1256 desc_ep->bmAttributes.usage ==
1257 0x00) // Check if usage is data EP
1258 {
1259 // Save address
1260 audio->ep_in = ep_addr;
1261 audio->ep_in_as_intf_num = itf;
1262 audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
1263
1264 // If flow control is enabled, parse for the corresponding
1265 // parameters - doing this here means only AS interfaces with
1266 // EPs get scanned for parameters
1267 if (getEnableEpInFlowControl()) {
1268 audiod_parse_flow_control_params(audio,
1269 p_desc_parse_for_params);
1270 }
1271 // Schedule first transmit if alternate interface is not zero
1272 // i.e. streaming is disabled - in case no sample data is
1273 // available a ZLP is loaded It is necessary to trigger this
1274 // here since the refill is done with an RX FIFO empty interrupt
1275 // which can only trigger if something was in there
1276 if (audiod_tx_done_cb_) {
1277 TU_VERIFY(
1278 audiod_tx_done_cb_(this, rhport, &audiod_fct_[func_id]));
1279 }
1280 }
1281 } // getEnableEpIn()
1282
1283 if (getEnableEpOut()) {
1284 if (tu_edpt_dir(ep_addr) ==
1285 TUSB_DIR_OUT) // Checking usage not necessary
1286 {
1287 // Save address
1288 audio->ep_out = ep_addr;
1289 audio->ep_out_as_intf_num = itf;
1290 audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
1291
1292 // Prepare for incoming data
1293 if (getUseLinearBufferRx()) {
1294 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out,
1295 audio->lin_buf_out.data(),
1296 audio->ep_out_sz),
1297 false);
1298 } else {
1299 TU_VERIFY(
1300 usbd_edpt_xfer_fifo(rhport, audio->ep_out,
1301 &audio->ep_out_ff, audio->ep_out_sz),
1302 false);
1303 }
1304 }
1305
1306 if (getEnableFeedbackEp()) {
1307 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN &&
1308 desc_ep->bmAttributes.usage ==
1309 1) // Check if usage is explicit data feedback
1310 {
1311 audio->ep_fb = ep_addr;
1312 audio->feedback.frame_shift = desc_ep->bInterval - 1;
1313 }
1314 }
1315 } // getEnableEpOut()
1316
1317 foundEPs += 1;
1318 }
1319 p_desc = tu_desc_next(p_desc);
1320 }
1321
1322 TU_VERIFY(foundEPs == nEps);
1323
1324 // Invoke one callback for a final set interface
1325 if (tud_audio_set_itf_cb_) {
1326 TU_VERIFY(tud_audio_set_itf_cb_(this, rhport, p_request));
1327 }
1328
1329 if (getEnableFeedbackEp()) {
1330 // Prepare feedback computation if endpoint is available
1331 if (audio->ep_fb != 0) {
1332 audio_feedback_params_t fb_param;
1333
1334 if (tud_audio_feedback_params_cb_) {
1335 tud_audio_feedback_params_cb_(this, func_id, alt, &fb_param);
1336 }
1337 audio->feedback.compute_method = fb_param.method;
1338
1339 if (TUSB_SPEED_FULL == tud_speed_get())
1340 if (tud_audio_feedback_format_correction_cb_) {
1341 audio->feedback.format_correction =
1342 tud_audio_feedback_format_correction_cb_(this, func_id);
1343 }
1344
1345 // Minimal/Maximum value in 16.16 format for full speed (1ms per
1346 // frame) or high speed (125 us per frame)
1347 uint32_t const frame_div =
1348 (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
1349 audio->feedback.min_value = ((fb_param.sample_freq - 1) / frame_div)
1350 << 16;
1351 audio->feedback.max_value = (fb_param.sample_freq / frame_div + 1)
1352 << 16;
1353
1354 switch (fb_param.method) {
1355 case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
1356 case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
1357 case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
1358 audiod_set_fb_params_freq(audio, fb_param.sample_freq,
1359 fb_param.frequency.mclk_freq);
1360 break;
1361
1362 case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: {
1363 // Initialize the threshold level to half filled
1364 uint16_t fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2;
1365 audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr;
1366 audio->feedback.compute.fifo_count.fifo_lvl_avg =
1367 ((uint32_t)fifo_lvl_thr) << 16;
1368 // Avoid 64bit division
1369 uint32_t nominal =
1370 ((fb_param.sample_freq / 100) << 16) / (frame_div / 100);
1371 audio->feedback.compute.fifo_count.nom_value = nominal;
1372 audio->feedback.compute.fifo_count.rate_const[0] =
1373 (uint16_t)((audio->feedback.max_value - nominal) /
1374 fifo_lvl_thr);
1375 audio->feedback.compute.fifo_count.rate_const[1] =
1376 (uint16_t)((nominal - audio->feedback.min_value) /
1377 fifo_lvl_thr);
1378 // On HS feedback is more sensitive since packet size can vary
1379 // every MSOF, could cause instability
1380 if (tud_speed_get() == TUSB_SPEED_HIGH) {
1381 audio->feedback.compute.fifo_count.rate_const[0] /= 8;
1382 audio->feedback.compute.fifo_count.rate_const[1] /= 8;
1383 }
1384 } break;
1385
1386 // nothing to do
1387 default:
1388 break;
1389 }
1390 }
1391 } // getEnableFeedbackEp()
1392
1393 // We are done - abort loop
1394 break;
1395 }
1396
1397 // Moving forward
1398 p_desc = tu_desc_next(p_desc);
1399 }
1400
1401 if (getEnableFeedbackEp()) {
1402 // Disable SOF interrupt if no driver has any enabled feedback EP
1403 bool enable_sof = false;
1404 for (uint8_t i = 0; i < getAudioCount(); i++) {
1405 if (audiod_fct_[i].ep_fb != 0 &&
1406 (audiod_fct_[i].feedback.compute_method ==
1407 AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED ||
1408 audiod_fct_[i].feedback.compute_method ==
1409 AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT ||
1410 audiod_fct_[i].feedback.compute_method ==
1411 AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2)) {
1412 enable_sof = true;
1413 break;
1414 }
1415 }
1416 usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, enable_sof);
1417 }
1418
1419 if (getEnableEpIn() && getEnableEpInFlowControl()) {
1420 audiod_calc_tx_packet_sz(audio);
1421 }
1422
1423 tud_control_status(rhport, p_request);
1424
1425 return true;
1426 }
1427
1428 bool audiod_set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq,
1429 uint32_t mclk_freq) {
1430 // Check if frame interval is within sane limits
1431 // The interval value n_frames was taken from the descriptors within
1432
1433 // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s
1434 // / f_m) for high speed this lower limit ensures the measures feedback
1435 // value has sufficient precision
1436 uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13;
1437 uint32_t const n_frame = (1UL << audio->feedback.frame_shift);
1438
1439 if ((((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame) {
1440 TU_LOG1(" UAC2 feedback interval too small\r\n");
1441 TU_BREAKPOINT();
1442 return false;
1443 }
1444
1445 // Check if parameters really allow for a power of two division
1446 if ((mclk_freq % sample_freq) == 0 &&
1447 tu_is_power_of_two(mclk_freq / sample_freq)) {
1448 audio->feedback.compute_method =
1449 AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
1450 audio->feedback.compute.power_of_2 =
1451 (uint8_t)(16 - (audio->feedback.frame_shift - 1) -
1452 tu_log2(mclk_freq / sample_freq));
1453 } else if (audio->feedback.compute_method ==
1454 AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) {
1455 audio->feedback.compute.float_const =
1456 (float)sample_freq / (float)mclk_freq *
1457 (1UL << (16 - (audio->feedback.frame_shift - 1)));
1458 } else {
1459 audio->feedback.compute.fixed.sample_freq = sample_freq;
1460 audio->feedback.compute.fixed.mclk_freq = mclk_freq;
1461 }
1462
1463 return true;
1464 }
1465
1466 bool audiod_calc_tx_packet_sz(audiod_function_t *audio) {
1467 TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I);
1468 TU_VERIFY(audio->n_channels_tx);
1469 TU_VERIFY(audio->n_bytes_per_sample_tx);
1470 TU_VERIFY(audio->interval_tx);
1471 TU_VERIFY(audio->sample_rate_tx);
1472
1473 const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL)
1474 ? audio->interval_tx
1475 : 1 << (audio->interval_tx - 1);
1476
1477 const uint16_t sample_normimal =
1478 (uint16_t)(audio->sample_rate_tx * interval /
1479 ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
1480 const uint16_t sample_reminder =
1481 (uint16_t)(audio->sample_rate_tx * interval %
1482 ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
1483
1484 const uint16_t packet_sz_tx_min =
1485 (uint16_t)((sample_normimal - 1) * audio->n_channels_tx *
1486 audio->n_bytes_per_sample_tx);
1487 const uint16_t packet_sz_tx_norm =
1488 (uint16_t)(sample_normimal * audio->n_channels_tx *
1489 audio->n_bytes_per_sample_tx);
1490 const uint16_t packet_sz_tx_max =
1491 (uint16_t)((sample_normimal + 1) * audio->n_channels_tx *
1492 audio->n_bytes_per_sample_tx);
1493
1494 // Endpoint size must larger than packet size
1495 TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz);
1496
1497 // Frmt20.pdf 2.3.1.1 USB Packets
1498 if (sample_reminder) {
1499 // All virtual frame packets must either contain INT(nav) audio slots
1500 // (small VFP) or INT(nav)+1 (large VFP) audio slots
1501 audio->packet_sz_tx[0] = packet_sz_tx_norm;
1502 audio->packet_sz_tx[1] = packet_sz_tx_norm;
1503 audio->packet_sz_tx[2] = packet_sz_tx_max;
1504 } else {
1505 // In the case where nav = INT(nav), ni may vary between INT(nav)-1 (small
1506 // VFP), INT(nav) (medium VFP) and INT(nav)+1 (large VFP).
1507 audio->packet_sz_tx[0] = packet_sz_tx_min;
1508 audio->packet_sz_tx[1] = packet_sz_tx_norm;
1509 audio->packet_sz_tx[2] = packet_sz_tx_max;
1510 }
1511
1512 return true;
1513 }
1514
1515 uint16_t tud_audio_n_write(uint8_t func_id, const void *data, uint16_t len) {
1516 TU_VERIFY(func_id < getAudioCount() && audiod_fct_[func_id].p_desc != NULL);
1517 return tu_fifo_write_n(&audiod_fct_[func_id].ep_in_ff, data, len);
1518 }
1519
1520 uint16_t tud_audio_n_available(uint8_t func_id) {
1521 TU_VERIFY(func_id < getAudioCount() && audiod_fct_[func_id].p_desc != NULL);
1522 return tu_fifo_count(&audiod_fct_[func_id].ep_out_ff);
1523 }
1524
1525 uint16_t tud_audio_n_read(uint8_t func_id, void *buffer, uint16_t bufsize) {
1526 TU_VERIFY(func_id < getAudioCount() && audiod_fct_[func_id].p_desc != NULL);
1527 return tu_fifo_read_n(&audiod_fct_[func_id].ep_out_ff, buffer, bufsize);
1528 }
1529};
1530
1531} // namespace audio_tools
1532
1533// Custom driver registration
1534extern usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *count) {
1535 return audio_tools::USBAudioDevice::instance().usbd_app_driver_get(count);
1536}
Definition USBAudio2DescriptorBuilder.h:12
Definition USBAudioDevice.h:29
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Definition USBAudioConfig.h:6